diff --git a/.buildkite/disabled_jest_configs.json b/.buildkite/disabled_jest_configs.json index 0d7741e60b385e..fe51488c7066f6 100644 --- a/.buildkite/disabled_jest_configs.json +++ b/.buildkite/disabled_jest_configs.json @@ -1,3 +1 @@ -[ - "x-pack/plugins/index_management/jest.config.js" -] \ No newline at end of file +[] diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dda328bfa1bef5..fac258fd64248d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,6 +87,7 @@ x-pack/plugins/cloud_integrations/cloud_links @elastic/kibana-core x-pack/plugins/cloud @elastic/kibana-core x-pack/plugins/cloud_security_posture @elastic/kibana-cloud-security-posture packages/shared-ux/code_editor @elastic/appex-sharedux +packages/kbn-code-owners @elastic/appex-qa packages/kbn-coloring @elastic/kibana-visualizations packages/kbn-config @elastic/kibana-core packages/kbn-config-mocks @elastic/kibana-core @@ -425,6 +426,7 @@ packages/kbn-flot-charts @elastic/kibana-operations x-pack/test/ui_capabilities/common/plugins/foo_plugin @elastic/kibana-security src/plugins/ftr_apis @elastic/kibana-core packages/kbn-ftr-common-functional-services @elastic/kibana-operations @elastic/appex-qa +packages/kbn-ftr-common-functional-ui-services @elastic/appex-qa packages/kbn-ftr-screenshot-filename @elastic/kibana-operations @elastic/appex-qa x-pack/test/functional_with_es_ssl/plugins/cases @elastic/response-ops x-pack/examples/gen_ai_streaming_response_example @elastic/response-ops @@ -626,6 +628,7 @@ x-pack/test/plugin_functional/plugins/resolver_test @elastic/security-solution examples/response_stream @elastic/ml-ui packages/kbn-rison @elastic/kibana-operations x-pack/plugins/rollup @elastic/platform-deployment-management +packages/kbn-router-utils @elastic/obs-ux-logs-team examples/routing_example @elastic/kibana-core packages/kbn-rrule @elastic/response-ops packages/kbn-rule-data-utils @elastic/security-detections-response @elastic/response-ops @elastic/obs-ux-management-team @@ -1251,8 +1254,37 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib # AI assistant in Security Solution tests /x-pack/test/security_solution_cypress/cypress/e2e/ai_assistant @elastic/security-threat-hunting-investigations @elastic/security-detection-rule-management +# Security Solution cross teams ownership +/x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting +/x-pack/test/security_solution_cypress/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine + +/x-pack/plugins/security_solution/common/ecs @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/common/test @elastic/security-detections-response @elastic/security-threat-hunting + +/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/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 +x-pack/test/security_solution_api_integration/test_suites/detections_response/utils @elastic/security-detections-response +x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-detections-response + # Security Solution sub teams +## Security Solution sub teams - security-engineering-productivity +## NOTE: It's important to keep this above other teams' sections because test automation doesn't process +## the CODEOWNERS file correctly. See https://github.com/elastic/kibana/issues/173307#issuecomment-1855858929 +/x-pack/test/security_solution_cypress/* @elastic/security-engineering-productivity +/x-pack/test/security_solution_cypress/cypress/* @elastic/security-engineering-productivity +/x-pack/test/security_solution_cypress/cypress/tasks/login.ts @elastic/security-engineering-productivity +/x-pack/test/security_solution_cypress/es_archives @elastic/security-engineering-productivity +/x-pack/plugins/security_solution/scripts/run_cypress @MadameSheema @patrykkopycinski @oatkiller @maximpn @banderror + ## Security Solution sub teams - Threat Hunting Investigations /x-pack/plugins/security_solution/common/api/timeline @elastic/security-threat-hunting-investigations @@ -1427,30 +1459,9 @@ x-pack/test/security_solution_api_integration/test_suites/detections_response/de /x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_delete/delete_rules.ts @elastic/security-detection-engine /x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_delete/delete_rules_ess.ts @elastic/security-detection-engine - ## Security Threat Intelligence - Under Security Platform /x-pack/plugins/security_solution/public/common/components/threat_match @elastic/security-detection-engine -## Security Solution cross teams ownership -/x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/helpers @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/objects @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/plugins @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/screens/common @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/support @elastic/security-detections-response @elastic/security-threat-hunting -/x-pack/test/security_solution_cypress/cypress/urls @elastic/security-threat-hunting-investigations @elastic/security-detection-engine - -/x-pack/plugins/security_solution/common/ecs @elastic/security-threat-hunting-investigations -/x-pack/plugins/security_solution/common/test @elastic/security-detections-response @elastic/security-threat-hunting - -/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/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 -x-pack/test/security_solution_api_integration/test_suites/detections_response/utils @elastic/security-detections-response -x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-detections-response - ## Security Solution sub teams - security-defend-workflows /x-pack/plugins/security_solution/public/management/ @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/common/lib/endpoint*/ @elastic/security-defend-workflows @@ -1474,13 +1485,6 @@ x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/telemetry @elastic/security-data-analytics -## Security Solution sub teams - security-engineering-productivity -/x-pack/test/security_solution_cypress/* @elastic/security-engineering-productivity -/x-pack/test/security_solution_cypress/cypress/* @elastic/security-engineering-productivity -/x-pack/test/security_solution_cypress/cypress/tasks/login.ts @elastic/security-engineering-productivity -/x-pack/test/security_solution_cypress/es_archives @elastic/security-engineering-productivity -/x-pack/plugins/security_solution/scripts/run_cypress @MadameSheema @patrykkopycinski @oatkiller @maximpn @banderror - ## 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 diff --git a/examples/discover_customization_examples/public/plugin.tsx b/examples/discover_customization_examples/public/plugin.tsx index 5eefb4932cc43e..9368c943532a4a 100644 --- a/examples/discover_customization_examples/public/plugin.tsx +++ b/examples/discover_customization_examples/public/plugin.tsx @@ -213,7 +213,6 @@ export class DiscoverCustomizationExamplesPlugin implements Plugin { {currentSavedSearch.title ?? 'None selected'} } - anchorClassName="eui-fullWidth" isOpen={isPopoverOpen} panelPaddingSize="none" closePopover={closePopover} @@ -280,7 +279,6 @@ export class DiscoverCustomizationExamplesPlugin implements Plugin { {currentSavedSearch.title ?? 'None selected'} } - anchorClassName="eui-fullWidth" isOpen={isPopoverOpen} panelPaddingSize="none" closePopover={closePopover} diff --git a/package.json b/package.json index d85136a35d99b0..e0f4284393e2fe 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@elastic/datemath": "5.0.3", "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.9.1-canary.1", "@elastic/ems-client": "8.5.1", - "@elastic/eui": "90.0.1-backport.0", + "@elastic/eui": "91.0.0-backport.0", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "1.2.1", "@elastic/numeral": "^2.5.1", @@ -629,6 +629,7 @@ "@kbn/response-stream-plugin": "link:examples/response_stream", "@kbn/rison": "link:packages/kbn-rison", "@kbn/rollup-plugin": "link:x-pack/plugins/rollup", + "@kbn/router-utils": "link:packages/kbn-router-utils", "@kbn/routing-example-plugin": "link:examples/routing_example", "@kbn/rrule": "link:packages/kbn-rrule", "@kbn/rule-data-utils": "link:packages/kbn-rule-data-utils", @@ -1176,6 +1177,7 @@ "@kbn/ci-stats-reporter": "link:packages/kbn-ci-stats-reporter", "@kbn/ci-stats-shipper-cli": "link:packages/kbn-ci-stats-shipper-cli", "@kbn/cli-dev-mode": "link:packages/kbn-cli-dev-mode", + "@kbn/code-owners": "link:packages/kbn-code-owners", "@kbn/core-analytics-browser-mocks": "link:packages/core/analytics/core-analytics-browser-mocks", "@kbn/core-analytics-server-mocks": "link:packages/core/analytics/core-analytics-server-mocks", "@kbn/core-application-browser-mocks": "link:packages/core/application/core-application-browser-mocks", @@ -1249,6 +1251,7 @@ "@kbn/failed-test-reporter-cli": "link:packages/kbn-failed-test-reporter-cli", "@kbn/find-used-node-modules": "link:packages/kbn-find-used-node-modules", "@kbn/ftr-common-functional-services": "link:packages/kbn-ftr-common-functional-services", + "@kbn/ftr-common-functional-ui-services": "link:packages/kbn-ftr-common-functional-ui-services", "@kbn/ftr-screenshot-filename": "link:packages/kbn-ftr-screenshot-filename", "@kbn/generate": "link:packages/kbn-generate", "@kbn/get-repo-files": "link:packages/kbn-get-repo-files", @@ -1558,6 +1561,7 @@ "html": "1.0.0", "html-loader": "^1.3.2", "http-proxy": "^1.18.1", + "ignore": "^5.3.0", "is-path-inside": "^3.0.2", "jest": "^29.6.1", "jest-axe": "^5.0.0", diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap index 416ce39bbf9baf..f505901f37abb4 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/collapsible_nav.test.tsx.snap @@ -157,7 +157,7 @@ Array [ aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="generated-id" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -281,7 +281,7 @@ Array [ aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="generated-id" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -412,7 +412,7 @@ Array [ aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="generated-id" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -526,7 +526,7 @@ Array [ aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="generated-id" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -623,7 +623,7 @@ Array [ aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="generated-id" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/header.test.tsx.snap b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/header.test.tsx.snap index 689888d4d82a5f..209e2f1d0c1130 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/header.test.tsx.snap +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/header/__snapshots__/header.test.tsx.snap @@ -108,37 +108,33 @@ Array [ class="euiHeaderSectionItem emotion-euiHeaderSectionItem" >
- + +
{ ), 'euiAbsoluteTab.dateFormatError': ({ dateFormat }: EuiValues) => i18n.translate('core.euiAbsoluteTab.dateFormatError', { - defaultMessage: 'Expected format: {dateFormat}', + defaultMessage: 'Allowed formats: {dateFormat}, ISO 8601, RFC 2822, or Unix timestamp.', values: { dateFormat }, }), 'euiRelativeTab.fullDescription': ({ unit }: EuiValues) => @@ -1454,6 +1454,9 @@ export const getEuiContextMapping = (): EuiTokensObject => { 'euiRelativeTab.dateInputError': i18n.translate('core.euiRelativeTab.dateInputError', { defaultMessage: 'Must be a valid range', }), + 'euiAbsoluteTab.dateFormatHint': i18n.translate('core.euiAbsoluteTab.dateFormatHint', { + defaultMessage: 'Press the Enter key to parse as a date.', + }), 'euiResizableButton.horizontalResizerAriaLabel': i18n.translate( 'core.euiResizableButton.horizontalResizerAriaLabel', { diff --git a/packages/home/sample_data_card/src/__snapshots__/sample_data_card.test.tsx.snap b/packages/home/sample_data_card/src/__snapshots__/sample_data_card.test.tsx.snap index 9f397dc7ccbd79..269499f65547af 100644 --- a/packages/home/sample_data_card/src/__snapshots__/sample_data_card.test.tsx.snap +++ b/packages/home/sample_data_card/src/__snapshots__/sample_data_card.test.tsx.snap @@ -83,33 +83,29 @@ exports[`SampleDataCard installed renders with app links 1`] = ` class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ + +
diff --git a/packages/home/sample_data_card/src/footer/__snapshots__/view_button.test.tsx.snap b/packages/home/sample_data_card/src/footer/__snapshots__/view_button.test.tsx.snap index ca5d1ccce07391..472852006ca26f 100644 --- a/packages/home/sample_data_card/src/footer/__snapshots__/view_button.test.tsx.snap +++ b/packages/home/sample_data_card/src/footer/__snapshots__/view_button.test.tsx.snap @@ -2,65 +2,57 @@ exports[`should render popover when appLinks is not empty 1`] = `
-
- -
+ + +
`; exports[`should render popover with ordered appLinks 1`] = `
-
- -
+ + +
`; diff --git a/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_fields.ts b/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_fields.ts index 7c3ab2c2b1e3a6..3ee43dc63f04f0 100644 --- a/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_fields.ts +++ b/packages/kbn-apm-synthtrace-client/src/lib/apm/apm_fields.ts @@ -50,6 +50,35 @@ export interface GeoLocation { type: string; } +export interface APMStacktrace { + abs_path?: string; + classname?: string; + context?: { + post?: string[]; + pre?: string[]; + }; + exclude_from_grouping?: boolean; + filename?: string; + function?: string; + module?: string; + library_frame?: boolean; + line?: + | { + column?: number; + number: number; + } + | { + context?: string; + }; + sourcemap?: { + error?: string; + updated?: boolean; + }; + vars?: { + [key: string]: unknown; + }; +} + type ExperimentalFields = Partial<{ 'metricset.interval': string; 'transaction.duration.summary': string; @@ -80,6 +109,8 @@ export type ApmFields = Fields<{ 'cloud.provider': string; 'cloud.region': string; 'cloud.service.name': string; + // otel + 'code.stacktrace': string; 'container.id': string; 'destination.address': string; 'destination.port': number; @@ -169,6 +200,7 @@ export type ApmFields = Fields<{ 'span.duration.us': number; 'span.id': string; 'span.name': string; + 'span.stacktrace': APMStacktrace[]; 'span.self_time.count': number; 'span.self_time.sum.us': number; 'span.subtype': string; diff --git a/packages/kbn-check-mappings-update-cli/current_fields.json b/packages/kbn-check-mappings-update-cli/current_fields.json index 7f7c317f7f63a1..c745e4886cde99 100644 --- a/packages/kbn-check-mappings-update-cli/current_fields.json +++ b/packages/kbn-check-mappings-update-cli/current_fields.json @@ -968,5 +968,8 @@ "kuery", "serviceEnvironmentFilterEnabled", "serviceNameFilterEnabled" + ], + "cloud-security-posture-settings": [ + "rules" ] } diff --git a/packages/kbn-check-mappings-update-cli/current_mappings.json b/packages/kbn-check-mappings-update-cli/current_mappings.json index fe4b3dba0940d1..7f5c94647b941d 100644 --- a/packages/kbn-check-mappings-update-cli/current_mappings.json +++ b/packages/kbn-check-mappings-update-cli/current_mappings.json @@ -2349,6 +2349,10 @@ } } }, + "cloud-security-posture-settings": { + "dynamic": false, + "properties": {} + }, "slo": { "dynamic": false, "properties": { diff --git a/packages/kbn-code-owners/README.md b/packages/kbn-code-owners/README.md new file mode 100644 index 00000000000000..b25944e2efbe61 --- /dev/null +++ b/packages/kbn-code-owners/README.md @@ -0,0 +1,3 @@ +# @kbn/code-owners + +This package contains utility methods to determine GitHub code ownership for files in the repository. diff --git a/packages/kbn-code-owners/index.ts b/packages/kbn-code-owners/index.ts new file mode 100644 index 00000000000000..0b2cd53a0b3a96 --- /dev/null +++ b/packages/kbn-code-owners/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export type { PathWithOwners } from './src/file_code_owner'; +export { getPathsWithOwnersReversed, getCodeOwnersForFile } from './src/file_code_owner'; diff --git a/packages/kbn-code-owners/jest.config.js b/packages/kbn-code-owners/jest.config.js new file mode 100644 index 00000000000000..471e87b73b1611 --- /dev/null +++ b/packages/kbn-code-owners/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-code-owners'], +}; diff --git a/packages/kbn-code-owners/kibana.jsonc b/packages/kbn-code-owners/kibana.jsonc new file mode 100644 index 00000000000000..66d2e57ca15c13 --- /dev/null +++ b/packages/kbn-code-owners/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-common", + "id": "@kbn/code-owners", + "owner": "@elastic/appex-qa", + "devOnly": true +} diff --git a/packages/kbn-code-owners/package.json b/packages/kbn-code-owners/package.json new file mode 100644 index 00000000000000..38a7c77800d0e5 --- /dev/null +++ b/packages/kbn-code-owners/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/code-owners", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-code-owners/src/file_code_owner.ts b/packages/kbn-code-owners/src/file_code_owner.ts new file mode 100644 index 00000000000000..56f3c54ef16032 --- /dev/null +++ b/packages/kbn-code-owners/src/file_code_owner.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { REPO_ROOT } from '@kbn/repo-info'; +import { createFailError } from '@kbn/dev-cli-errors'; +import { join as joinPath } from 'path'; +import { existsSync, readFileSync } from 'fs'; + +import type { Ignore } from 'ignore'; +import ignore from 'ignore'; + +export interface PathWithOwners { + path: string; + teams: string; + ignorePattern: Ignore; +} + +/** + * Get the .github/CODEOWNERS entries, prepared for path matching. + * The last matching CODEOWNERS entry has highest precedence: + * https://help.github.com/articles/about-codeowners/ + * so entries are returned in reversed order to later search for the first match. + */ +export function getPathsWithOwnersReversed(): PathWithOwners[] { + const codeownersPath = joinPath(REPO_ROOT, '.github', 'CODEOWNERS'); + if (existsSync(codeownersPath) === false) { + throw createFailError(`Unable to determine code owners: file ${codeownersPath} not found`); + } + const codeownersContent = readFileSync(codeownersPath, { encoding: 'utf8', flag: 'r' }); + const codeownersLines = codeownersContent.split(/\r?\n/); + const codeowners = codeownersLines + .map((line) => line.trim()) + .filter((line) => line && line[0] !== '#'); + + const pathsWithOwners: PathWithOwners[] = codeowners.map((c) => { + const [path, ...ghTeams] = c.split(/\s+/); + return { + path, + teams: ghTeams.map((t) => t.replace('@', '')).join(), + // register CODEOWNERS entries with the `ignores` lib for later path matching + ignorePattern: ignore().add([path]), + }; + }); + + return pathsWithOwners.reverse(); +} + +/** + * Get the GitHub CODEOWNERS for a file in the repository + * @param filePath the file to get code owners for + * @param reversedCodeowners a cached reversed code owners list, use to speed up multiple requests + */ +export function getCodeOwnersForFile( + filePath: string, + reversedCodeowners?: PathWithOwners[] +): string | undefined { + const pathsWithOwners = reversedCodeowners ?? getPathsWithOwnersReversed(); + + const match = pathsWithOwners.find((p) => p.ignorePattern.test(filePath).ignored); + + return match?.teams; +} diff --git a/packages/kbn-code-owners/tsconfig.json b/packages/kbn-code-owners/tsconfig.json new file mode 100644 index 00000000000000..e97f927147d73f --- /dev/null +++ b/packages/kbn-code-owners/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/repo-info", + "@kbn/dev-cli-errors" + ] +} diff --git a/packages/kbn-ftr-common-functional-ui-services/README.md b/packages/kbn-ftr-common-functional-ui-services/README.md new file mode 100644 index 00000000000000..b6fbe963d099b8 --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/README.md @@ -0,0 +1,3 @@ +# @kbn/ftr-common-functional-ui-services + +Common test services for ui actions. diff --git a/packages/kbn-ftr-common-functional-ui-services/index.ts b/packages/kbn-ftr-common-functional-ui-services/index.ts new file mode 100644 index 00000000000000..5fe8ae6fd01643 --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { services as commonFunctionalUIServices } from './services/all'; +export type { FtrProviderContext } from './services/ftr_provider_context'; diff --git a/packages/kbn-ftr-common-functional-ui-services/jest.config.js b/packages/kbn-ftr-common-functional-ui-services/jest.config.js new file mode 100644 index 00000000000000..afd295ad81883c --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../..', + roots: ['/packages/kbn-ftr-common-functional-ui-services'], +}; diff --git a/packages/kbn-ftr-common-functional-ui-services/kibana.jsonc b/packages/kbn-ftr-common-functional-ui-services/kibana.jsonc new file mode 100644 index 00000000000000..5437a12260a9cf --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "type": "shared-common", + "id": "@kbn/ftr-common-functional-ui-services", + "owner": "@elastic/appex-qa", + "devOnly": true +} diff --git a/packages/kbn-ftr-common-functional-ui-services/package.json b/packages/kbn-ftr-common-functional-ui-services/package.json new file mode 100644 index 00000000000000..4fad67bc28fa0b --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/ftr-common-functional-ui-services", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/packages/kbn-ftr-common-functional-ui-services/services/all.ts b/packages/kbn-ftr-common-functional-ui-services/services/all.ts new file mode 100644 index 00000000000000..8c8a7236601172 --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/services/all.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { RetryOnStaleProvider } from './retry_on_stale'; + +export const services = { + retryOnStale: RetryOnStaleProvider, +}; diff --git a/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts b/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts new file mode 100644 index 00000000000000..979658fbd8eddf --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/services/ftr_provider_context.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; + +import type { services } from './all'; + +type Services = typeof services; + +export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} diff --git a/test/functional/services/common/retry_on_stale.ts b/packages/kbn-ftr-common-functional-ui-services/services/retry_on_stale.ts similarity index 95% rename from test/functional/services/common/retry_on_stale.ts rename to packages/kbn-ftr-common-functional-ui-services/services/retry_on_stale.ts index 4a190266458ec6..8f4b374a8b3cd6 100644 --- a/test/functional/services/common/retry_on_stale.ts +++ b/packages/kbn-ftr-common-functional-ui-services/services/retry_on_stale.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrProviderContext } from './ftr_provider_context'; const MAX_ATTEMPTS = 10; diff --git a/packages/kbn-ftr-common-functional-ui-services/tsconfig.json b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json new file mode 100644 index 00000000000000..0c77cc5d6b9175 --- /dev/null +++ b/packages/kbn-ftr-common-functional-ui-services/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node" + ] + }, + "include": [ + "**/*.ts", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/test", + ] +} diff --git a/packages/kbn-router-utils/README.md b/packages/kbn-router-utils/README.md new file mode 100644 index 00000000000000..e5dcb4cdb4fe4d --- /dev/null +++ b/packages/kbn-router-utils/README.md @@ -0,0 +1,34 @@ +# @kbn/router-utils + +This package provides util functions when working with the router. + +## getRouterLinkProps + +Useful to generate link component properties for HTML elements, this link properties will allow them to behave as native links and handle events such as open in a new tab, or client-side navigation without refreshing the whole page. + +### Example + +We want a button to both navigate to Discover client-side or open on a new window. + +```ts +const DiscoverLink = (discoverLinkParams) => { + const discoverUrl = discover.locator?.getRedirectUrl(discoverLinkParams); + + const navigateToDiscover = () => { + discover.locator?.navigate(discoverLinkParams); + }; + + const linkProps = getRouterLinkProps({ + href: discoverUrl, + onClick: navigateToDiscover, + }); + + return ( + <> + + {discoverLinkTitle} + + + ); +}; +``` diff --git a/packages/kbn-router-utils/index.ts b/packages/kbn-router-utils/index.ts new file mode 100644 index 00000000000000..f5ed5ed7e76044 --- /dev/null +++ b/packages/kbn-router-utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { getRouterLinkProps } from './src/get_router_link_props'; diff --git a/packages/kbn-router-utils/jest.config.js b/packages/kbn-router-utils/jest.config.js new file mode 100644 index 00000000000000..32497360f94191 --- /dev/null +++ b/packages/kbn-router-utils/jest.config.js @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-router-utils'], +}; diff --git a/packages/kbn-router-utils/kibana.jsonc b/packages/kbn-router-utils/kibana.jsonc new file mode 100644 index 00000000000000..c255dacb11c700 --- /dev/null +++ b/packages/kbn-router-utils/kibana.jsonc @@ -0,0 +1,5 @@ +{ + "type": "shared-common", + "id": "@kbn/router-utils", + "owner": "@elastic/obs-ux-logs-team" +} diff --git a/packages/kbn-router-utils/package.json b/packages/kbn-router-utils/package.json new file mode 100644 index 00000000000000..d84ddd2c06bc27 --- /dev/null +++ b/packages/kbn-router-utils/package.json @@ -0,0 +1,6 @@ +{ + "name": "@kbn/router-utils", + "private": true, + "version": "1.0.0", + "license": "SSPL-1.0 OR Elastic License 2.0" +} \ No newline at end of file diff --git a/x-pack/plugins/log_explorer/public/utils/get_router_link_props.ts b/packages/kbn-router-utils/src/get_router_link_props/index.ts similarity index 57% rename from x-pack/plugins/log_explorer/public/utils/get_router_link_props.ts rename to packages/kbn-router-utils/src/get_router_link_props/index.ts index a325df1a7e86ff..f3def2e88650b8 100644 --- a/x-pack/plugins/log_explorer/public/utils/get_router_link_props.ts +++ b/packages/kbn-router-utils/src/get_router_link_props/index.ts @@ -1,8 +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. + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. */ interface GetRouterLinkPropsDeps { @@ -15,6 +16,18 @@ const isModifiedEvent = (event: React.MouseEvent) => const isLeftClickEvent = (event: React.MouseEvent) => event.button === 0; +/** + * + * getRouterLinkProps is an util that enable HTML elements, such buttons, to + * behave as links. + * @example + * const linkProps = getRouterLinkProps({ href: 'https://my-link', onClick: () => {console.log('click event')} }); + * My custom link + * @param href target url + * @param onClick onClick callback + * @returns An object that contains an href and a guardedClick handler that will + * manage behaviours such as leftClickEvent and event with modifiers (Ctrl, Shift, etc) + */ export const getRouterLinkProps = ({ href, onClick }: GetRouterLinkPropsDeps) => { const guardedClickHandler = (event: React.MouseEvent) => { if (event.defaultPrevented) { diff --git a/packages/kbn-router-utils/tsconfig.json b/packages/kbn-router-utils/tsconfig.json new file mode 100644 index 00000000000000..87f865132f4b46 --- /dev/null +++ b/packages/kbn-router-utils/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types", + "types": [ + "jest", + "node", + "react" + ] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [] +} diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap index 8cc75ec2beab86..1a4c9076a20d6f 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap +++ b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/__snapshots__/index.test.tsx.snap @@ -10,90 +10,7 @@ Object { data-test-subj="fieldAutocompleteComboBox" >
-
-
-
-
- - - machine.os.raw - - - -
-
- - -
-
-
-
-
- - - , - "container":
-
-
-
- - - machine.os.raw - -
+ , + "container":
+
+
+
+
+
+ +
+
+ + +
+
+
+
+
, "debug": [Function], "findAllByAltText": [Function], @@ -227,46 +199,32 @@ Object { data-test-subj="fieldAutocompleteComboBox" >
-
- - - machine.os.raw - - - -
+
@@ -280,46 +238,32 @@ Object { data-test-subj="fieldAutocompleteComboBox" >
-
- - - machine.os.raw - - - -
+
@@ -390,79 +334,7 @@ Object { data-test-subj="fieldAutocompleteComboBox" >
-
-
-
-
- - - machine.os.raw - - - -
-
- -
-
-
-
-
-
-
- , - "container":
-
-
-
- - - machine.os.raw - -
+ , + "container":
+
+
+
+
+
+ +
+
+ +
+
+
+
+
, "debug": [Function], "findAllByAltText": [Function], @@ -585,72 +501,7 @@ Object { data-test-subj="fieldAutocompleteComboBox" >
-
-
-
-
- - - machine.os.raw - - - -
-
- -
-
-
-
-
-
-
- , - "container":
-
-
-
- - - machine.os.raw - -
+ , + "container":
+
+
+
+
+
+ +
+
+ +
+
+
+
+
, "debug": [Function], "findAllByAltText": [Function], diff --git a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx index 48f7a109646f06..9ac7d9e58ee8bd 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field/__tests__/index.test.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { fireEvent, render, waitFor } from '@testing-library/react'; +import { fireEvent, render, waitFor, within } from '@testing-library/react'; import '@testing-library/jest-dom'; import { FieldComponent } from '..'; @@ -31,7 +31,9 @@ describe('FieldComponent', () => { /> ); expect(wrapper).toMatchSnapshot(); - expect(wrapper.getByTestId('fieldAutocompleteComboBox')).toHaveTextContent('machine.os.raw'); + const comboBox = wrapper.getByTestId('fieldAutocompleteComboBox'); + const input = within(comboBox).getByRole('combobox'); + expect(input).toHaveAttribute('value', 'machine.os.raw'); }); it('should render the component disabled if isDisabled is true', () => { const wrapper = render( diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx index acd1a315d2c482..733e111fb4dd5d 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_lists/index.test.tsx @@ -182,9 +182,9 @@ describe('AutocompleteFieldListsComponent', () => { expect( wrapper - .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] EuiComboBoxPill`) + .find(`[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input`) .at(0) - .text() + .props().value ).toEqual('some name'); }); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx index 24bb72c3058ac9..5d4f8cd89f1ccc 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_match/index.test.tsx @@ -166,7 +166,7 @@ describe('AutocompleteFieldMatchComponent', () => { ); expect( - wrapper.find('[data-test-subj="valuesAutocompleteMatch"] EuiComboBoxPill').at(0).text() + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().value ).toEqual('127.0.0.1'); }); diff --git a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx index 9eab42f5cec731..ec442385a1fd38 100644 --- a/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/field_value_wildcard/index.test.tsx @@ -168,7 +168,7 @@ describe('AutocompleteFieldWildcardComponent', () => { ); expect( - wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] EuiComboBoxPill').at(0).text() + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').at(0).props().value ).toEqual('/opt/*/app.dmg'); }); diff --git a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx index 954b14a8ea244d..21ed99dce4b721 100644 --- a/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx +++ b/packages/kbn-securitysolution-autocomplete/src/operator/index.test.tsx @@ -152,7 +152,7 @@ describe('operator', () => { ); expect( - wrapper.find(`[data-test-subj="operatorAutocompleteComboBox"] EuiComboBoxPill`).at(0).text() + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value ).toEqual('is'); }); diff --git a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap index ff7dddd2da9505..eecc554cd4e005 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap +++ b/packages/kbn-securitysolution-exception-list-components/src/exception_item_card/comments/__snapshots__/comments.test.tsx.snap @@ -101,7 +101,7 @@ Object { class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isClosed" id="exceptionItemCardComments" inert="" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -239,7 +239,7 @@ Object { class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isClosed" id="exceptionItemCardComments" inert="" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -433,7 +433,7 @@ Object { aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="exceptionItemCardComments" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -570,7 +570,7 @@ Object { aria-labelledby="generated-id" class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isOpen" id="exceptionItemCardComments" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > diff --git a/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap index dae6c052360015..5f87fe13836342 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap +++ b/packages/kbn-securitysolution-exception-list-components/src/header_menu/__snapshots__/header_menu.test.tsx.snap @@ -9,40 +9,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], @@ -124,26 +116,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -157,7 +145,7 @@ Object { aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: 16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -226,26 +214,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
, @@ -312,40 +296,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], @@ -427,45 +403,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], @@ -552,45 +520,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], @@ -677,46 +637,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], @@ -804,45 +756,8 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
-
-
-
- , - "container":
-
-
-
+ , + "container":
+
+
+ +
+
, "debug": [Function], "findAllByAltText": [Function], diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap index a458aa90dbedcb..c83f098c6d0906 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/__snapshots__/list_header.test.tsx.snap @@ -197,26 +197,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -584,26 +580,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -867,26 +859,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1093,26 +1081,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1348,27 +1332,23 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1547,27 +1527,23 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1784,26 +1760,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1826,7 +1798,7 @@ Object { aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: 16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -2053,26 +2025,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
diff --git a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap index 90c90a4f3eea54..a58f4a042bca32 100644 --- a/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap +++ b/packages/kbn-securitysolution-exception-list-components/src/list_header/menu_items/__snapshots__/menu_items.test.tsx.snap @@ -16,33 +16,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -53,26 +49,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -91,33 +83,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -128,26 +116,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -252,26 +236,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -319,26 +299,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -443,26 +419,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -478,7 +450,7 @@ Object { aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: 16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -598,26 +570,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -693,33 +661,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -730,26 +694,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -765,7 +725,7 @@ Object { aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPanel--paddingSmall euiPopover__panel emotion-euiPanel-grow-m-s-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: 16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -858,33 +818,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -895,26 +851,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -990,33 +942,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -1046,26 +994,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
@@ -1084,33 +1028,29 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+ + +
@@ -1140,26 +1080,22 @@ Object { class="euiFlexGroup emotion-euiFlexGroup-responsive-l-flexStart-stretch-row" >
-
- -
+
diff --git a/packages/kbn-test/index.ts b/packages/kbn-test/index.ts index 1b092f1fdd25ef..e5409ee6ee485d 100644 --- a/packages/kbn-test/index.ts +++ b/packages/kbn-test/index.ts @@ -52,6 +52,8 @@ export { getUrl } from './src/jest/get_url'; export { runCheckJestConfigsCli } from './src/jest/run_check_jest_configs_cli'; +export { runCheckFtrCodeOwnersCli } from './src/functional_test_runner/run_check_ftr_code_owners'; + export { runJest } from './src/jest/run'; export * from './src/kbn_archiver_cli'; diff --git a/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.ts b/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.ts new file mode 100644 index 00000000000000..91a6ded43dbacf --- /dev/null +++ b/packages/kbn-test/src/functional_test_runner/run_check_ftr_code_owners.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 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { run } from '@kbn/dev-cli-runner'; +import { createFailError } from '@kbn/dev-cli-errors'; +import { getRepoFiles } from '@kbn/get-repo-files'; +import { getCodeOwnersForFile, getPathsWithOwnersReversed } from '@kbn/code-owners'; + +const TEST_DIRECTORIES = ['test', 'x-pack/test', 'x-pack/test_serverless']; + +const fmtMs = (ms: number) => { + if (ms < 1000) { + return `${Math.round(ms)} ms`; + } + + return `${(Math.round(ms) / 1000).toFixed(2)} s`; +}; + +const fmtList = (list: Iterable) => [...list].map((i) => ` - ${i}`).join('\n'); + +export async function runCheckFtrCodeOwnersCli() { + run( + async ({ log }) => { + const start = performance.now(); + + const missingOwners = new Set(); + + // cache codeowners for quicker lookup + const reversedCodeowners = getPathsWithOwnersReversed(); + + const testFiles = await getRepoFiles(TEST_DIRECTORIES); + for (const { repoRel } of testFiles) { + const owners = getCodeOwnersForFile(repoRel, reversedCodeowners); + if (owners === undefined) { + missingOwners.add(repoRel); + } + } + + const timeSpent = fmtMs(performance.now() - start); + + if (missingOwners.size) { + log.error( + `The following test files do not have a GitHub code owner:\n${fmtList(missingOwners)}` + ); + throw createFailError( + `Found ${missingOwners.size} test files without code owner (checked ${testFiles.length} test files in ${timeSpent})` + ); + } + + log.success( + `All test files have a code owner (checked ${testFiles.length} test files in ${timeSpent})` + ); + }, + { + description: 'Check that all test files are covered by GitHub CODEOWNERS', + } + ); +} diff --git a/packages/kbn-test/tsconfig.json b/packages/kbn-test/tsconfig.json index abf0a35c4438ad..fa22159f0b387b 100644 --- a/packages/kbn-test/tsconfig.json +++ b/packages/kbn-test/tsconfig.json @@ -33,5 +33,6 @@ "@kbn/repo-packages", "@kbn/core-saved-objects-api-server", "@kbn/mock-idp-plugin", + "@kbn/code-owners", ] } diff --git a/packages/kbn-unified-data-table/src/components/data_table.test.tsx b/packages/kbn-unified-data-table/src/components/data_table.test.tsx index f898c4707717e5..e69d1a88200ba2 100644 --- a/packages/kbn-unified-data-table/src/components/data_table.test.tsx +++ b/packages/kbn-unified-data-table/src/components/data_table.test.tsx @@ -308,7 +308,7 @@ describe('UnifiedDataTable', () => { columns: ['message'], }); - expect(component.find(EuiDataGrid).prop('sorting')).toMatchInlineSnapshot(` + expect(component.find(EuiDataGrid).last().prop('sorting')).toMatchInlineSnapshot(` Object { "columns": Array [ Object { @@ -332,7 +332,7 @@ describe('UnifiedDataTable', () => { columns: ['bytes', 'message'], }); - expect(component.find(EuiDataGrid).prop('sorting')).toMatchInlineSnapshot(` + expect(component.find(EuiDataGrid).last().prop('sorting')).toMatchInlineSnapshot(` Object { "columns": Array [ Object { @@ -359,7 +359,7 @@ describe('UnifiedDataTable', () => { onUpdateRowHeight: jest.fn(), }); - expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(` + expect(component.find(EuiDataGrid).first().prop('toolbarVisibility')).toMatchInlineSnapshot(` Object { "additionalControls": null, "showColumnSelector": false, @@ -385,7 +385,7 @@ describe('UnifiedDataTable', () => { onUpdateRowHeight: jest.fn(), }); - expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(` + expect(component.find(EuiDataGrid).first().prop('toolbarVisibility')).toMatchInlineSnapshot(` Object { "additionalControls": null, "showColumnSelector": false, @@ -406,7 +406,7 @@ describe('UnifiedDataTable', () => { onUpdateSampleSize: undefined, }); - expect(component.find(EuiDataGrid).prop('toolbarVisibility')).toMatchInlineSnapshot(` + expect(component.find(EuiDataGrid).first().prop('toolbarVisibility')).toMatchInlineSnapshot(` Object { "additionalControls": null, "showColumnSelector": false, diff --git a/packages/kbn-unsaved-changes-badge/src/components/unsaved_changes_badge/__snapshots__/unsaved_changes_badge.test.tsx.snap b/packages/kbn-unsaved-changes-badge/src/components/unsaved_changes_badge/__snapshots__/unsaved_changes_badge.test.tsx.snap index 441d85d917ef3a..141a8c7b437b81 100644 --- a/packages/kbn-unsaved-changes-badge/src/components/unsaved_changes_badge/__snapshots__/unsaved_changes_badge.test.tsx.snap +++ b/packages/kbn-unsaved-changes-badge/src/components/unsaved_changes_badge/__snapshots__/unsaved_changes_badge.test.tsx.snap @@ -3,34 +3,30 @@ exports[` should show all menu items 1`] = `
-
- -
+ + +
`; diff --git a/packages/kbn-unsaved-changes-badge/src/utils/__snapshots__/get_top_nav_unsaved_changes_badge.test.tsx.snap b/packages/kbn-unsaved-changes-badge/src/utils/__snapshots__/get_top_nav_unsaved_changes_badge.test.tsx.snap index eafe487e0265c1..a2cca8a1cc1e35 100644 --- a/packages/kbn-unsaved-changes-badge/src/utils/__snapshots__/get_top_nav_unsaved_changes_badge.test.tsx.snap +++ b/packages/kbn-unsaved-changes-badge/src/utils/__snapshots__/get_top_nav_unsaved_changes_badge.test.tsx.snap @@ -3,34 +3,30 @@ exports[`getTopNavUnsavedChangesBadge() should work correctly 1`] = `
-
- -
+ + +
`; diff --git a/packages/kbn-visualization-ui-components/components/query_input/filter_query_input.tsx b/packages/kbn-visualization-ui-components/components/query_input/filter_query_input.tsx index e998e48eefe99c..ac24f7bb818605 100644 --- a/packages/kbn-visualization-ui-components/components/query_input/filter_query_input.tsx +++ b/packages/kbn-visualization-ui-components/components/query_input/filter_query_input.tsx @@ -101,7 +101,7 @@ export function FilterQueryInput({ is rendered 1`] = `
-
- -
+ + +
`; diff --git a/scripts/check_ftr_code_owners.js b/scripts/check_ftr_code_owners.js new file mode 100644 index 00000000000000..67161a997e0bcc --- /dev/null +++ b/scripts/check_ftr_code_owners.js @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../src/setup_node_env'); +require('@kbn/test').runCheckFtrCodeOwnersCli(); diff --git a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts index a2235b0f778120..f02dd54f791b4e 100644 --- a/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts +++ b/src/core/server/integration_tests/ci_checks/saved_objects/check_registered_types.test.ts @@ -76,6 +76,7 @@ describe('checking migration metadata changes on all registered SO types', () => "cases-connector-mappings": "f9d1ac57e484e69506c36a8051e4d61f4a8cfd25", "cases-telemetry": "f219eb7e26772884342487fc9602cfea07b3cedc", "cases-user-actions": "483f10db9b3bd1617948d7032a98b7791bf87414", + "cloud-security-posture-settings": "675e47dd958fbce6c70a20baac12af3145e7c0ef", "config": "179b3e2bc672626aafce3cf92093a113f456af38", "config-global": "8e8a134a2952df700d7d4ec51abb794bbd4cf6da", "connector_token": "5a9ac29fe9c740eb114e9c40517245c71706b005", diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts index 2cef3801868bd3..99e2692523f6d7 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/type_registrations.test.ts @@ -29,6 +29,7 @@ const previouslyRegisteredTypes = [ 'canvas-element', 'canvas-workpad', 'canvas-workpad-template', + 'cloud-security-posture-settings', 'cases', 'cases-comments', 'cases-configure', diff --git a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts index c39ceaf30da692..9f9c3a3c7bd582 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group5/dot_kibana_split.test.ts @@ -197,6 +197,7 @@ describe('split .kibana index into multiple system indices', () => { "cases-connector-mappings", "cases-telemetry", "cases-user-actions", + "cloud-security-posture-settings", "config", "config-global", "connector_token", diff --git a/src/dev/license_checker/config.ts b/src/dev/license_checker/config.ts index 08d4267e52b639..b0919d0ab61415 100644 --- a/src/dev/license_checker/config.ts +++ b/src/dev/license_checker/config.ts @@ -85,7 +85,7 @@ export const LICENSE_OVERRIDES = { 'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts '@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint '@elastic/ems-client@8.5.1': ['Elastic License 2.0'], - '@elastic/eui@90.0.1-backport.0': ['SSPL-1.0 OR Elastic License 2.0'], + '@elastic/eui@91.0.0-backport.0': ['SSPL-1.0 OR Elastic License 2.0'], 'language-subtag-registry@0.3.21': ['CC-BY-4.0'], // retired ODC‑By license https://github.com/mattcg/language-subtag-registry 'buffers@0.1.1': ['MIT'], // license in importing module https://www.npmjs.com/package/binary }; diff --git a/src/plugins/controls/public/control_group/component/control_error_component.tsx b/src/plugins/controls/public/control_group/component/control_error_component.tsx index 409455f0e304e9..6cdd1b5fc1fffe 100644 --- a/src/plugins/controls/public/control_group/component/control_error_component.tsx +++ b/src/plugins/controls/public/control_group/component/control_error_component.tsx @@ -43,7 +43,6 @@ export const ControlError = ({ error }: ControlErrorProps) => { button={popoverButton} isOpen={isPopoverOpen} className="errorEmbeddableCompact__popover" - anchorClassName="errorEmbeddableCompact__popoverAnchor" closePopover={() => setPopoverOpen(false)} > { const popover = await mountComponent(); const includeButton = findTestSubject(popover, 'optionsList__includeResults'); const excludeButton = findTestSubject(popover, 'optionsList__excludeResults'); - expect(includeButton.prop('checked')).toBe(true); - expect(excludeButton.prop('checked')).toBeFalsy(); + expect(includeButton.prop('aria-pressed')).toBe(true); + expect(excludeButton.prop('aria-pressed')).toBe(false); }); test('if exclude = true, select appropriate button in button group', async () => { @@ -163,8 +163,8 @@ describe('Options list popover', () => { }); const includeButton = findTestSubject(popover, 'optionsList__includeResults'); const excludeButton = findTestSubject(popover, 'optionsList__excludeResults'); - expect(includeButton.prop('checked')).toBeFalsy(); - expect(excludeButton.prop('checked')).toBe(true); + expect(includeButton.prop('aria-pressed')).toBe(false); + expect(excludeButton.prop('aria-pressed')).toBe(true); }); test('clicking another option unselects "Exists"', async () => { @@ -176,8 +176,8 @@ describe('Options list popover', () => { const availableOptionsDiv = findTestSubject(popover, 'optionsList-control-available-options'); availableOptionsDiv.children().forEach((child, i) => { - if (child.text() === 'woof') expect(child.prop('checked')).toBe('on'); - else expect(child.prop('checked')).toBeFalsy(); + if (child.text() === 'woof') expect(child.prop('aria-pressed')).toBe(true); + else expect(child.prop('aria-pressed')).toBeFalsy(); }); }); @@ -189,15 +189,15 @@ describe('Options list popover', () => { const existsOption = findTestSubject(popover, 'optionsList-control-selection-exists'); let availableOptionsDiv = findTestSubject(popover, 'optionsList-control-available-options'); availableOptionsDiv.children().forEach((child, i) => { - if (selections.includes(child.text())) expect(child.prop('checked')).toBe('on'); - else expect(child.prop('checked')).toBeFalsy(); + if (selections.includes(child.text())) expect(child.prop('aria-pressed')).toBe(true); + else expect(child.prop('aria-pressed')).toBeFalsy(); }); existsOption.simulate('click'); availableOptionsDiv = findTestSubject(popover, 'optionsList-control-available-options'); availableOptionsDiv.children().forEach((child, i) => { - if (child.text() === 'Exists (*)') expect(child.prop('checked')).toBe('on'); - else expect(child.prop('checked')).toBeFalsy(); + if (child.text() === 'Exists (*)') expect(child.prop('aria-pressed')).toBe(true); + else expect(child.prop('aria-pressed')).toBeFalsy(); }); }); diff --git a/src/plugins/controls/public/options_list/components/options_list_popover_sorting_button.tsx b/src/plugins/controls/public/options_list/components/options_list_popover_sorting_button.tsx index d1cad0bb97c815..d246e631fba84c 100644 --- a/src/plugins/controls/public/options_list/components/options_list_popover_sorting_button.tsx +++ b/src/plugins/controls/public/options_list/components/options_list_popover_sorting_button.tsx @@ -119,7 +119,6 @@ export const OptionsListPopoverSortingButton = ({ aria-labelledby="optionsList_sortingOptions" closePopover={() => setIsSortingPopoverOpen(false)} panelClassName={'optionsList--sortPopover'} - anchorClassName={'optionsList__sortButtonPopoverAnchor'} > diff --git a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap index 06a402fd475676..8bd049df006fcd 100644 --- a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap +++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap @@ -176,27 +176,23 @@ Array [ class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ color="inherit" + data-euiicon-type="arrowDown" + /> + +
, @@ -224,30 +220,26 @@ Array [ class="euiTableSortMobile" >
-
- -
+ + +
@@ -339,31 +331,27 @@ Array [ class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ + +
-
- -
+ + +
@@ -515,27 +499,23 @@ Array [ class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ color="inherit" + data-euiicon-type="arrowDown" + /> + +
, @@ -563,30 +543,26 @@ Array [ class="euiTableSortMobile" >
-
- -
+ + +
@@ -679,31 +655,27 @@ Array [ class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ + +
{ 'Matching sources' ); - findTestSubject(component, 'allIndices').simulate('change', { - target: { - value: true, - }, - }); + findTestSubject(component, 'allIndices').simulate('click'); await component.update(); @@ -109,11 +105,7 @@ describe('DataViewEditor PreviewPanel', () => { expect(component.find('.euiButtonGroupButton-isSelected').first().text()).toBe('All sources'); - findTestSubject(component, 'onlyMatchingIndices').simulate('change', { - target: { - value: true, - }, - }); + findTestSubject(component, 'onlyMatchingIndices').simulate('click'); await component.update(); diff --git a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.scss b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.scss index cc8d7f96982219..739d6930001e9c 100644 --- a/src/plugins/embeddable/public/lib/embeddables/error_embeddable.scss +++ b/src/plugins/embeddable/public/lib/embeddables/error_embeddable.scss @@ -1,9 +1,6 @@ .errorEmbeddableCompact__popover { height: 100%; -} - -.errorEmbeddableCompact__popoverAnchor { max-width: 100%; } diff --git a/src/plugins/home/public/application/components/tutorial/tutorial.test.js b/src/plugins/home/public/application/components/tutorial/tutorial.test.js index 3d0fde31aadbc7..be5dbfe3105509 100644 --- a/src/plugins/home/public/application/components/tutorial/tutorial.test.js +++ b/src/plugins/home/public/application/components/tutorial/tutorial.test.js @@ -130,7 +130,7 @@ describe('isCloudEnabled is false', () => { ); await loadTutorialPromise; component.update(); - component.find('#onPremElasticCloud').first().find('input').simulate('change'); + component.find('button[data-test-subj="onCloudTutorial"]').simulate('click'); component.update(); expect(component.state('visibleInstructions')).toBe('onPremElasticCloud'); }); diff --git a/src/plugins/inspector/public/ui/__snapshots__/inspector_panel.test.tsx.snap b/src/plugins/inspector/public/ui/__snapshots__/inspector_panel.test.tsx.snap index 3ebb9ee096fc52..11e7964056745f 100644 --- a/src/plugins/inspector/public/ui/__snapshots__/inspector_panel.test.tsx.snap +++ b/src/plugins/inspector/public/ui/__snapshots__/inspector_panel.test.tsx.snap @@ -21,32 +21,28 @@ Array [ class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+ + +
diff --git a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.scss b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.scss index 787376fac04900..1c16adbfc8c133 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.scss +++ b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.scss @@ -73,11 +73,6 @@ padding: $euiSizeM; } -.globalFilterItem__popover, -.globalFilterItem__popoverAnchor { - display: block; -} - .globalFilterItem__readonlyPanel { min-width: auto; padding: $euiSizeM; 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 d29529f59a3c96..596a32ea0a2f58 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 @@ -367,8 +367,7 @@ function FilterItemComponent(props: FilterItemProps) { const popoverProps: FilterPopoverProps = { id: `popoverFor_filter${id}`, - className: `globalFilterItem__popover`, - anchorClassName: `globalFilterItem__popoverAnchor`, + display: 'block', isOpen: isPopoverOpen, closePopover, button: , diff --git a/src/plugins/unified_search/public/query_string_input/no_data_popover.tsx b/src/plugins/unified_search/public/query_string_input/no_data_popover.tsx index 7e9760486bb930..8fde7a52e6bd5a 100644 --- a/src/plugins/unified_search/public/query_string_input/no_data_popover.tsx +++ b/src/plugins/unified_search/public/query_string_input/no_data_popover.tsx @@ -67,7 +67,6 @@ export function NoDataPopover({ } minWidth={300} anchorPosition="downCenter" - anchorClassName="eui-displayBlock" step={1} stepsTotal={1} isStepOpen={noDataPopoverVisible} diff --git a/src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap b/src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap index cc95e272d54f73..d23c14423efbb9 100644 --- a/src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap +++ b/src/plugins/vis_types/vislib/public/vislib/components/legend/__snapshots__/legend.test.tsx.snap @@ -2,4 +2,4 @@ exports[`VisLegend Component Legend closed should match the snapshot 1`] = `"
"`; -exports[`VisLegend Component Legend open should match the snapshot 1`] = `"
"`; +exports[`VisLegend Component Legend open should match the snapshot 1`] = `"
"`; diff --git a/test/examples/content_management/todo_app.ts b/test/examples/content_management/todo_app.ts index 5c5739c962e2d7..7812f1fcf66467 100644 --- a/test/examples/content_management/todo_app.ts +++ b/test/examples/content_management/todo_app.ts @@ -28,17 +28,17 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide expect(todos.length).to.be(2); // check that filters work - await (await find.byCssSelector('label[title="Completed"]')).click(); + await (await find.byButtonText('Completed')).click(); await testSubjects.missingOrFail(`todoPending`); todos = await testSubjects.findAll(`~todoItem`); expect(todos.length).to.be(1); - await (await find.byCssSelector('label[title="Todo"]')).click(); + await (await find.byButtonText('Todo')).click(); await testSubjects.missingOrFail(`todoPending`); todos = await testSubjects.findAll(`~todoItem`); expect(todos.length).to.be(1); - await (await find.byCssSelector('label[title="All"]')).click(); + await (await find.byButtonText('All')).click(); await testSubjects.missingOrFail(`todoPending`); todos = await testSubjects.findAll(`~todoItem`); expect(todos.length).to.be(2); @@ -56,9 +56,10 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide let newTodoCheckbox = await newTodo.findByTestSubject('~todoCheckbox'); expect(await newTodoCheckbox.isSelected()).to.be(false); await (await newTodo.findByTagName('label')).click(); + await newTodo.click(); await testSubjects.missingOrFail(`todoPending`); - await (await find.byCssSelector('label[title="Completed"]')).click(); + await (await find.byButtonText('Completed')).click(); await testSubjects.missingOrFail(`todoPending`); todos = await testSubjects.findAll(`~todoItem`); expect(todos.length).to.be(2); diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index 1566c15533810b..aa8832f28848ab 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -107,6 +107,8 @@ export class TimePickerPageObject extends FtrService { } else { await this.testSubjects.setValue(dataTestSubj, value); } + + await this.testSubjects.pressEnter(dataTestSubj); } private async showStartEndTimes() { diff --git a/test/functional/services/combo_box.ts b/test/functional/services/combo_box.ts index 78c36a87636f70..4b23dd3bd8b981 100644 --- a/test/functional/services/combo_box.ts +++ b/test/functional/services/combo_box.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import expect from '@kbn/expect'; import { FtrService } from '../ftr_provider_context'; import { WebElementWrapper } from './lib/web_element_wrapper'; @@ -84,6 +85,7 @@ export class ComboBoxService extends FtrService { const isOptionSelected = await this.isOptionSelected(comboBoxElement, trimmedValue); if (isOptionSelected) { + this.log.debug(`value is already selected. returning`); return; } @@ -116,7 +118,7 @@ export class ComboBoxService extends FtrService { const [alternate] = alternateTitle ? await this.find.allByCssSelector( - `.euiFilterSelectItem[title="${alternateTitle}"]`, + `.euiFilterSelectItem[title="${alternateTitle}" i]`, this.WAIT_FOR_EXISTS_TIME ) : []; @@ -177,15 +179,28 @@ export class ComboBoxService extends FtrService { * @param comboBoxElement element that wraps up EuiComboBox * @param filterValue text */ - private async setFilterValue( + public async setFilterValue( comboBoxElement: WebElementWrapper, filterValue: string ): Promise { const input = await comboBoxElement.findByTagName('input'); - await input.clearValue(); - await this.waitForOptionsListLoading(comboBoxElement); - await input.type(filterValue); - await this.waitForOptionsListLoading(comboBoxElement); + + await this.retry.try(async () => { + // Wait for the input to not be disabled before typing into it (otherwise + // typing will sometimes trigger the global search bar instead) + expect(await input.isEnabled()).to.equal(true); + + // Some Kibana comboboxes force state to not be clearable, so we can't use `input.clearValue()`. + // This is not-great production UX and shouldn't be happening, but for now we're going to + // work around it in FTR tests by selecting all existing text and typing to replace + if (!!(await input.getAttribute('value'))) { + await input.selectValueWithKeyboard(); + } + await input.type(filterValue); + await this.waitForOptionsListLoading(comboBoxElement); + + expect(await input.getAttribute('value')).to.equal(filterValue); + }); } /** @@ -241,9 +256,29 @@ export class ComboBoxService extends FtrService { this.log.debug(`comboBox.getComboBoxSelectedOptions, comboBoxSelector: ${comboBoxSelector}`); const comboBox = await this.testSubjects.find(comboBoxSelector); const $ = await comboBox.parseDomContent(); - return $('.euiComboBoxPill') + + if (await this.isSingleSelectionPlainText(comboBox)) { + const input = $('[data-test-subj="comboBoxSearchInput"]'); + this.log.debug('Single selection value: ', input.val()); + + const isValid = input.attr('aria-invalid') !== 'true'; + + if (isValid) { + const value = input.val(); + return value ? [value] : []; // Don't return empty strings + } else { + this.log.debug( + 'Single selection value is not valid and thus not selected - returning empty array' + ); + return []; + } + } + + const options = $('.euiComboBoxPill') .toArray() .map((option) => $(option).text()); + + return options; } /** @@ -315,8 +350,8 @@ export class ComboBoxService extends FtrService { if (!isOptionsListOpen) { await this.retry.try(async () => { - const toggleBtn = await comboBoxElement.findByTestSubject('comboBoxInput'); - await toggleBtn.click(); + const inputWrapper = await this.getComboBoxInputWrapper(comboBoxElement); + await inputWrapper.click(); }); } } @@ -333,9 +368,21 @@ export class ComboBoxService extends FtrService { ): Promise { this.log.debug(`comboBox.isOptionSelected, value: ${value}`); const $ = await comboBoxElement.parseDomContent(); + + if (await this.isSingleSelectionPlainText(comboBoxElement)) { + const input = $('input[role="combobox"]'); + + const hasValidValue = + input.attr('aria-invalid') !== 'true' && + value.toLowerCase().trim() === input.val().toLowerCase().trim(); // Normalizing text here for Firefox driver shenanigans + + return !!hasValidValue; + } + const selectedOptions = $('.euiComboBoxPill') .toArray() .map((option) => $(option).text()); + return ( selectedOptions.length === 1 && selectedOptions[0].toLowerCase().trim() === value.toLowerCase().trim() @@ -369,4 +416,26 @@ export class ComboBoxService extends FtrService { this.log.debug(`isDisabled:${isDisabled}`); return isDisabled?.toLowerCase() === 'true'; } + + /** + * Single selection plain text comboboxes do not render pill text, but instead render + * selected as well as search values in the child + */ + private async isSingleSelectionPlainText(comboBoxElement: WebElementWrapper): Promise { + const inputWrapper = await this.getComboBoxInputWrapper(comboBoxElement); + return await inputWrapper.elementHasClass('euiComboBox__inputWrap--plainText'); + } + + /** + * Kibana devs sometimes pass in the `comboBoxInput` element and not the parent wrapper 🤷 + * This util accounts for that and returns the `data-test-subj="comboBoxInput"` element no matter what + */ + private async getComboBoxInputWrapper( + comboBoxElement: WebElementWrapper + ): Promise { + const isInputWrapper = await comboBoxElement.elementHasClass('euiComboBox__inputWrap'); + return isInputWrapper + ? comboBoxElement + : await comboBoxElement.findByTestSubject('comboBoxInput'); + } } diff --git a/test/functional/services/common/index.ts b/test/functional/services/common/index.ts index 54c9e5a1ee54cc..b7b8c67a4280d9 100644 --- a/test/functional/services/common/index.ts +++ b/test/functional/services/common/index.ts @@ -14,4 +14,3 @@ export { PngService } from './png'; export { ScreenshotsService } from './screenshots'; export { SnapshotsService } from './snapshots'; export { TestSubjects } from './test_subjects'; -export { RetryOnStaleProvider } from './retry_on_stale'; diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 11975f560e2d70..dc151f1b243e37 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { commonFunctionalUIServices } from '@kbn/ftr-common-functional-ui-services'; import { services as commonServiceProviders } from '../../common/services'; import { AppsMenuService } from './apps_menu'; @@ -17,7 +18,6 @@ import { ScreenshotsService, SnapshotsService, TestSubjects, - RetryOnStaleProvider, } from './common'; import { ComboBoxService } from './combo_box'; import { @@ -60,7 +60,7 @@ import { DashboardSettingsProvider } from './dashboard/dashboard_settings'; export const services = { ...commonServiceProviders, - + ...commonFunctionalUIServices, __webdriver__: RemoteProvider, filterBar: FilterBarService, queryBar: QueryBarService, @@ -101,7 +101,6 @@ export const services = { managementMenu: ManagementMenuService, monacoEditor: MonacoEditorService, menuToggle: MenuToggleService, - retryOnStale: RetryOnStaleProvider, usageCollection: UsageCollectionService, savedObjectsFinder: SavedObjectsFinderService, }; diff --git a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts index 70df204b1de03c..6a914c7273ba34 100644 --- a/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts +++ b/test/functional/services/lib/web_element_wrapper/web_element_wrapper.ts @@ -261,28 +261,28 @@ export class WebElementWrapper { * @default { charByChar: false } */ async clearValueWithKeyboard(options: TypeOptions = { charByChar: false }) { + const value = await this.getAttribute('value'); + if (!value.length) { + return; + } + if (options.charByChar === true) { - const value = await this.getAttribute('value'); for (let i = 0; i <= value.length; i++) { await this.pressKeys(this.Keys.BACK_SPACE); await setTimeoutAsync(100); } } else { - if (this.isChromium) { - // https://bugs.chromium.org/p/chromedriver/issues/detail?id=30 - await this.retryCall(async function clearValueWithKeyboard(wrapper) { - await wrapper.driver.executeScript(`arguments[0].select();`, wrapper._webElement); - }); - await this.pressKeys(this.Keys.BACK_SPACE); - } else { - const selectionKey = this.Keys[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL']; - await this.pressKeys([selectionKey, 'a']); - await this.pressKeys(this.Keys.NULL); // Release modifier keys - await this.pressKeys(this.Keys.BACK_SPACE); // Delete all content - } + await this.selectValueWithKeyboard(); + await this.pressKeys(this.Keys.BACK_SPACE); } } + async selectValueWithKeyboard() { + const selectionKey = this.Keys[process.platform === 'darwin' ? 'COMMAND' : 'CONTROL']; + await this.pressKeys([selectionKey, 'a']); + await this.pressKeys(this.Keys.NULL); // Release modifier keys + } + /** * Types a key sequence on the DOM element represented by this instance. Modifier keys * (SHIFT, CONTROL, ALT, META) are stateful; once a modifier is processed in the key sequence, diff --git a/test/tsconfig.json b/test/tsconfig.json index a763d6f6a44d61..d451e64e6329bb 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -71,5 +71,6 @@ "@kbn/event-annotation-plugin", "@kbn/event-annotation-common", "@kbn/links-plugin", + "@kbn/ftr-common-functional-ui-services", ] } diff --git a/tsconfig.base.json b/tsconfig.base.json index e634fe61248a1c..178f70c927e281 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -168,6 +168,8 @@ "@kbn/cloud-security-posture-plugin/*": ["x-pack/plugins/cloud_security_posture/*"], "@kbn/code-editor": ["packages/shared-ux/code_editor"], "@kbn/code-editor/*": ["packages/shared-ux/code_editor/*"], + "@kbn/code-owners": ["packages/kbn-code-owners"], + "@kbn/code-owners/*": ["packages/kbn-code-owners/*"], "@kbn/coloring": ["packages/kbn-coloring"], "@kbn/coloring/*": ["packages/kbn-coloring/*"], "@kbn/config": ["packages/kbn-config"], @@ -844,6 +846,8 @@ "@kbn/ftr-apis-plugin/*": ["src/plugins/ftr_apis/*"], "@kbn/ftr-common-functional-services": ["packages/kbn-ftr-common-functional-services"], "@kbn/ftr-common-functional-services/*": ["packages/kbn-ftr-common-functional-services/*"], + "@kbn/ftr-common-functional-ui-services": ["packages/kbn-ftr-common-functional-ui-services"], + "@kbn/ftr-common-functional-ui-services/*": ["packages/kbn-ftr-common-functional-ui-services/*"], "@kbn/ftr-screenshot-filename": ["packages/kbn-ftr-screenshot-filename"], "@kbn/ftr-screenshot-filename/*": ["packages/kbn-ftr-screenshot-filename/*"], "@kbn/functional-with-es-ssl-cases-test-plugin": ["x-pack/test/functional_with_es_ssl/plugins/cases"], @@ -1246,6 +1250,8 @@ "@kbn/rison/*": ["packages/kbn-rison/*"], "@kbn/rollup-plugin": ["x-pack/plugins/rollup"], "@kbn/rollup-plugin/*": ["x-pack/plugins/rollup/*"], + "@kbn/router-utils": ["packages/kbn-router-utils"], + "@kbn/router-utils/*": ["packages/kbn-router-utils/*"], "@kbn/routing-example-plugin": ["examples/routing_example"], "@kbn/routing-example-plugin/*": ["examples/routing_example/*"], "@kbn/rrule": ["packages/kbn-rrule"], diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector/index.test.tsx index 8cd7c1dd0bd64f..4ab45c10b021a2 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector/index.test.tsx @@ -58,7 +58,7 @@ describe('Conversation selector', () => { ); expect(getByTestId('conversation-selector')).toBeInTheDocument(); - expect(getByTestId('euiComboBoxPill')).toHaveTextContent(welcomeConvo.id); + expect(getByTestId('comboBoxSearchInput')).toHaveValue(welcomeConvo.id); }); it('On change, selects new item', () => { const { getByTestId } = render( @@ -78,7 +78,7 @@ describe('Conversation selector', () => { expect(onConversationSelected).toHaveBeenCalledWith(alertConvo.id); }); it('On clear input, clears selected options', () => { - const { getByText, queryByText, getByTestId, queryByTestId } = render( + const { getByPlaceholderText, queryByPlaceholderText, getByTestId, queryByTestId } = render( ({ @@ -90,10 +90,10 @@ describe('Conversation selector', () => { ); - expect(getByTestId('euiComboBoxPill')).toBeInTheDocument(); - expect(queryByText(CONVERSATION_SELECTOR_PLACE_HOLDER)).not.toBeInTheDocument(); + expect(getByTestId('comboBoxSearchInput')).toBeInTheDocument(); + expect(queryByPlaceholderText(CONVERSATION_SELECTOR_PLACE_HOLDER)).not.toBeInTheDocument(); fireEvent.click(getByTestId('comboBoxClearButton')); - expect(getByText(CONVERSATION_SELECTOR_PLACE_HOLDER)).toBeInTheDocument(); + expect(getByPlaceholderText(CONVERSATION_SELECTOR_PLACE_HOLDER)).toBeInTheDocument(); expect(queryByTestId('euiComboBoxPill')).not.toBeInTheDocument(); }); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.test.tsx index afe6ede5929105..150784d9db4cf9 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/conversations/conversation_selector_settings/index.test.tsx @@ -30,7 +30,7 @@ describe('ConversationSelectorSettings', () => { }); it('Selects an existing conversation', () => { const { getByTestId } = render(); - expect(getByTestId('comboBoxInput')).toHaveTextContent(welcomeConvo.id); + expect(getByTestId('comboBoxSearchInput')).toHaveValue(welcomeConvo.id); fireEvent.click(getByTestId('comboBoxToggleListButton')); fireEvent.click(getByTestId(alertConvo.id)); expect(onConversationSelectionChange).toHaveBeenCalledWith(alertConvo); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.test.tsx index ea16553e71c6e7..d8d14a8ffebe03 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant/prompt_editor/system_prompt/system_prompt_modal/system_prompt_selector/system_prompt_selector.test.tsx @@ -25,7 +25,7 @@ describe('SystemPromptSelector', () => { }); it('Selects an existing quick prompt', () => { const { getByTestId } = render(); - expect(getByTestId('euiComboBoxPill')).toHaveTextContent(mockSystemPrompts[0].name); + expect(getByTestId('comboBoxSearchInput')).toHaveValue(mockSystemPrompts[0].name); fireEvent.click(getByTestId('comboBoxToggleListButton')); fireEvent.click(getByTestId(`systemPromptSelector-${mockSystemPrompts[1].id}`)); expect(onSystemPromptSelectionChange).toHaveBeenCalledWith(mockSystemPrompts[1]); diff --git a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/models/model_selector/model_selector.test.tsx b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/models/model_selector/model_selector.test.tsx index 459dfd3426584c..9138c02381eb44 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/connectorland/models/model_selector/model_selector.test.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/connectorland/models/model_selector/model_selector.test.tsx @@ -15,7 +15,7 @@ describe('ModelSelector', () => { const { getByTestId } = render( ); - expect(getByTestId('euiComboBoxPill')).toHaveTextContent(MODEL_GPT_3_5_TURBO); + expect(getByTestId('comboBoxSearchInput')).toHaveValue(MODEL_GPT_3_5_TURBO); }); it('should call onModelSelectionChange when custom option', () => { const onModelSelectionChange = jest.fn(); diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.test.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.test.tsx index 3fea6d6611f083..a354e47975bafe 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.test.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.test.tsx @@ -131,7 +131,9 @@ describe('CreateMaintenanceWindowForm', () => { 'Press the down key to open a popover containing a calendar.' ); const recurringInput = within(result.getByTestId('recurring-field')).getByTestId('input'); - const timezoneInput = within(result.getByTestId('timezone-field')).getByTestId('input'); + const timezoneInput = within(result.getByTestId('timezone-field')).getByTestId( + 'comboBoxSearchInput' + ); await waitFor(() => { expect( @@ -156,7 +158,7 @@ describe('CreateMaintenanceWindowForm', () => { expect(dateInputs[0]).toHaveValue('03/23/2023 09:00 PM'); expect(dateInputs[1]).toHaveValue('03/25/2023 09:00 PM'); expect(recurringInput).toBeChecked(); - expect(timezoneInput).toHaveTextContent('America/Los_Angeles'); + expect(timezoneInput).toHaveValue('America/Los_Angeles'); }); it('should initialize MWs without category ids properly', async () => { diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.test.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.test.tsx index 6422d285db7ef7..76390aea7ef186 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.test.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/recurring_schedule_form/recurring_schedule.test.tsx @@ -94,7 +94,7 @@ describe('RecurringSchedule', () => { const endsInput = within(result.getByTestId('ends-field')).getByTestId('never'); expect(frequencyInput).toHaveValue('3'); - expect(endsInput).toBeChecked(); + expect(endsInput).toHaveAttribute('aria-pressed', 'true'); }); it('should prefill the form when provided with initialValue', () => { @@ -119,7 +119,7 @@ describe('RecurringSchedule', () => { 'Press the down key to open a popover containing a calendar.' ); expect(frequencyInput).toHaveValue('1'); - expect(endsInput).toBeChecked(); + expect(endsInput).toHaveAttribute('aria-pressed', 'true'); expect(untilInput).toHaveValue('03/24/2023'); }); }); 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 31df2212bb5b53..d230f18f7ea60e 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 @@ -26,6 +26,7 @@ import { fromKueryExpression, nodeTypes } from '@kbn/es-query'; import { RecoveredActionGroup } from '../../../../../common'; import { DefaultRuleAggregationResult } from '../../../../routes/rule/apis/aggregate/types'; import { defaultRuleAggregationFactory } from '.'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -289,7 +290,7 @@ describe('aggregate()', () => { filter: undefined, page: 1, perPage: 0, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, aggs: { status: { terms: { field: 'alert.attributes.executionStatus.status' }, @@ -350,7 +351,7 @@ describe('aggregate()', () => { ]), page: 1, perPage: 0, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, aggs: { status: { terms: { field: 'alert.attributes.executionStatus.status' }, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts index d5f18db2f1065d..c3cbfd340984c0 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.test.ts @@ -30,6 +30,7 @@ import { siemRuleForBulkOps1, } from '../../../../rules_client/tests/test_helpers'; import { migrateLegacyActions } from '../../../../rules_client/lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; jest.mock('../../../../rules_client/lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -85,7 +86,7 @@ const rulesClientParams: jest.Mocked = { const getBulkOperationStatusErrorResponse = (statusCode: number) => ({ id: 'id2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, success: false, error: { error: '', @@ -164,9 +165,9 @@ describe('bulkDelete', () => { test('should try to delete rules, two successful and one with 500 error', async () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, getBulkOperationStatusErrorResponse(500), - { id: 'id3', type: 'alert', success: true }, + { id: 'id3', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); @@ -176,7 +177,7 @@ describe('bulkDelete', () => { expect(unsecuredSavedObjectsClient.bulkDelete).toHaveBeenCalledWith( [enabledRuleForBulkOps1, enabledRuleForBulkOps2, enabledRuleForBulkOps3].map(({ id }) => ({ id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, })), undefined ); @@ -201,7 +202,7 @@ describe('bulkDelete', () => { unsecuredSavedObjectsClient.bulkDelete .mockResolvedValueOnce({ statuses: [ - { id: 'id1', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, getBulkOperationStatusErrorResponse(409), ], }) @@ -265,7 +266,7 @@ describe('bulkDelete', () => { unsecuredSavedObjectsClient.bulkDelete .mockResolvedValueOnce({ statuses: [ - { id: 'id1', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, getBulkOperationStatusErrorResponse(409), ], }) @@ -273,7 +274,7 @@ describe('bulkDelete', () => { statuses: [ { id: 'id2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, success: true, }, ], @@ -356,9 +357,9 @@ describe('bulkDelete', () => { test('should not mark API keys for invalidation if the user is authenticated using an api key', async () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id3', type: 'alert', success: true }, - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: true }, + { id: 'id3', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); @@ -376,15 +377,15 @@ describe('bulkDelete', () => { test('should return task id if deleting task failed', async () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); taskManager.bulkRemove.mockImplementation(async () => ({ statuses: [ { id: 'id1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, success: true, }, getBulkOperationStatusErrorResponse(500), @@ -404,8 +405,8 @@ describe('bulkDelete', () => { test('should not throw an error if taskManager throw an error', async () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); taskManager.bulkRemove.mockImplementation(() => { @@ -424,20 +425,20 @@ describe('bulkDelete', () => { mockCreatePointInTimeFinderAsInternalUser(); unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); taskManager.bulkRemove.mockImplementation(async () => ({ statuses: [ { id: 'id1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, success: true, }, { id: 'id2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, success: true, }, ], @@ -468,9 +469,9 @@ describe('bulkDelete', () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: enabledRuleForBulkOps1.id, type: 'alert', success: true }, - { id: enabledRuleForBulkOps2.id, type: 'alert', success: true }, - { id: siemRuleForBulkOps1.id, type: 'alert', success: true }, + { id: enabledRuleForBulkOps1.id, type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: enabledRuleForBulkOps2.id, type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: siemRuleForBulkOps1.id, type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); @@ -501,8 +502,8 @@ describe('bulkDelete', () => { test('logs audit event when deleting rules', async () => { unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: true }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: true }, ], }); @@ -511,12 +512,12 @@ describe('bulkDelete', () => { expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_delete'); expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[0][0]?.kibana).toEqual({ - saved_object: { id: 'id1', type: 'alert' }, + saved_object: { id: 'id1', type: RULE_SAVED_OBJECT_TYPE }, }); expect(auditLogger.log.mock.calls[1][0]?.event?.action).toEqual('rule_delete'); expect(auditLogger.log.mock.calls[1][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[1][0]?.kibana).toEqual({ - saved_object: { id: 'id2', type: 'alert' }, + saved_object: { id: 'id2', type: RULE_SAVED_OBJECT_TYPE }, }); }); @@ -525,7 +526,7 @@ describe('bulkDelete', () => { throw new Error('Unauthorized'); }); unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ - statuses: [{ id: 'id1', type: 'alert', success: true }], + statuses: [{ id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }], }); await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrowError( @@ -541,7 +542,7 @@ describe('bulkDelete', () => { throw new Error('Error'); }); unsecuredSavedObjectsClient.bulkDelete.mockResolvedValue({ - statuses: [{ id: 'id1', type: 'alert', success: true }], + statuses: [{ id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }], }); await expect(rulesClient.bulkDeleteRules({ filter: 'fake_filter' })).rejects.toThrowError( diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts index 33da0fd6b2e072..429afed34926c6 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_delete/bulk_delete_rules.ts @@ -9,6 +9,7 @@ import Boom from '@hapi/boom'; import { KueryNode, nodeBuilder } from '@kbn/es-query'; import { SavedObjectsBulkUpdateObject } from '@kbn/core/server'; import { withSpan } from '@kbn/apm-utils'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { convertRuleIdsToKueryNode } from '../../../../lib'; import { bulkMarkApiKeysForInvalidation } from '../../../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; @@ -136,7 +137,7 @@ const bulkDeleteWithOCC = async ( context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, perPage: 100, ...(context.namespace ? { namespaces: [context.namespace] } : undefined), } @@ -168,7 +169,7 @@ const bulkDeleteWithOCC = async ( ruleAuditEvent({ action: RuleAuditAction.DELETE, outcome: 'unknown', - savedObject: { type: 'alert', id: rule.id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: rule.id }, }) ); } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts index f7e8eff33591f7..2b7c72fd4c51bc 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.test.ts @@ -35,6 +35,7 @@ import { siemRuleForBulkOps2, } from '../../../../rules_client/tests/test_helpers'; import { migrateLegacyActions } from '../../../../rules_client/lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; jest.mock('../../../../task_runner/alert_task_instance', () => ({ taskInstanceToAlertTaskInstance: jest.fn(), @@ -428,8 +429,8 @@ describe('bulkDisableRules', () => { taskManager.bulkRemove.mockResolvedValue({ statuses: [ - { id: 'id1', type: 'alert', success: true }, - { id: 'id2', type: 'alert', success: false }, + { id: 'id1', type: RULE_SAVED_OBJECT_TYPE, success: true }, + { id: 'id2', type: RULE_SAVED_OBJECT_TYPE, success: false }, ], }); @@ -543,12 +544,12 @@ describe('bulkDisableRules', () => { expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_disable'); expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[0][0]?.kibana).toEqual({ - saved_object: { id: 'id1', type: 'alert' }, + saved_object: { id: 'id1', type: RULE_SAVED_OBJECT_TYPE }, }); expect(auditLogger.log.mock.calls[1][0]?.event?.action).toEqual('rule_disable'); expect(auditLogger.log.mock.calls[1][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[1][0]?.kibana).toEqual({ - saved_object: { id: 'id2', type: 'alert' }, + saved_object: { id: 'id2', type: RULE_SAVED_OBJECT_TYPE }, }); }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts index e981a30181a494..0ac84ce2ef6d76 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_disable/bulk_disable_rules.ts @@ -11,6 +11,7 @@ import { withSpan } from '@kbn/apm-utils'; import pMap from 'p-map'; import { Logger } from '@kbn/core/server'; import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import type { RawRule, SanitizedRule, RawRuleAction } from '../../../../types'; import { convertRuleIdsToKueryNode } from '../../../../lib'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; @@ -132,7 +133,7 @@ const bulkDisableRulesWithOCC = async ( context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter: filter ? nodeBuilder.and([filter, additionalFilter]) : additionalFilter, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, perPage: 100, ...(context.namespace ? { namespaces: [context.namespace] } : undefined), } @@ -200,7 +201,7 @@ const bulkDisableRulesWithOCC = async ( ruleAuditEvent({ action: RuleAuditAction.DISABLE, outcome: 'unknown', - savedObject: { type: 'alert', id: rule.id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: rule.id }, }) ); } catch (error) { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts index 38a04fbd76c76a..dbd056bb1df30c 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.test.ts @@ -35,6 +35,7 @@ import { } from '../../../../rules_client/tests/test_helpers'; import { migrateLegacyActions } from '../../../../rules_client/lib'; import { migrateLegacyActionsMock } from '../../../../rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; jest.mock('../../../../rules_client/lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -121,7 +122,7 @@ describe('bulkEdit()', () => { let actionsClient: jest.Mocked; const existingRule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, tags: ['foo'], @@ -269,7 +270,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo', 'test-1'], @@ -314,7 +315,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: ['foo', 'test-1'], revision: 1, @@ -330,7 +331,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: [], @@ -371,7 +372,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: [], revision: 1, @@ -387,7 +388,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['test-1', 'test-2'], @@ -429,7 +430,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: ['test-1', 'test-2'], revision: 1, @@ -931,7 +932,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -982,7 +983,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ params: expect.objectContaining({ index: ['test-1', 'test-2', 'test-4', 'test-5'], @@ -1000,7 +1001,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -1046,7 +1047,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ params: expect.objectContaining({ index: ['test-1'], @@ -1104,7 +1105,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo', 'test-1'], @@ -1149,7 +1150,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ snoozeSchedule: [snoozePayload], revision: 0, @@ -1180,7 +1181,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ revision: 0, snoozeSchedule: [snoozePayload], @@ -1226,7 +1227,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ revision: 0, snoozeSchedule: [...existingSnooze, snoozePayload], @@ -1271,7 +1272,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ muteAll: true, revision: 0, @@ -1316,7 +1317,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ revision: 0, snoozeSchedule: [existingSnooze[1], existingSnooze[2]], @@ -1361,7 +1362,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ revision: 0, snoozeSchedule: [], @@ -1406,7 +1407,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ revision: 0, snoozeSchedule: [existingSnooze[0]], @@ -1525,7 +1526,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo', 'test-1'], @@ -1578,7 +1579,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: ['foo', 'test-1'], params: { @@ -1597,7 +1598,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo', 'test-1'], @@ -1651,7 +1652,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: ['foo', 'test-1'], params: { @@ -1670,7 +1671,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -1724,7 +1725,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ tags: ['foo'], params: { @@ -1814,7 +1815,7 @@ describe('bulkEdit()', () => { }, page: 1, perPage: 0, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); }); test('should call unsecuredSavedObjectsClient.find for aggregations when called with ids options', async () => { @@ -1884,7 +1885,7 @@ describe('bulkEdit()', () => { }, page: 1, perPage: 0, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); }); test('should throw if number of matched rules greater than 10_000', async () => { @@ -2032,7 +2033,7 @@ describe('bulkEdit()', () => { type: 'function', }, perPage: 100, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, namespaces: ['default'], }); }); @@ -2087,7 +2088,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -2228,7 +2229,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -2489,7 +2490,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo', 'test-1'], @@ -2551,7 +2552,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -2593,7 +2594,7 @@ describe('bulkEdit()', () => { [ expect.objectContaining({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: expect.objectContaining({ params: expect.objectContaining({ index: ['test-index-*'], @@ -2632,7 +2633,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -2675,7 +2676,7 @@ describe('bulkEdit()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], 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 996f67448c7f85..d9ff12bf9d3f3c 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 @@ -15,6 +15,7 @@ import { SavedObjectsFindResult, SavedObjectsUpdateResponse, } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { BulkActionSkipResult } from '../../../../../common/bulk_edit'; import { RuleTypeRegistry } from '../../../../types'; import { @@ -279,7 +280,7 @@ async function bulkEditRulesOcc( await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, perPage: 100, ...(context.namespace ? { namespaces: [context.namespace] } : undefined), } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts index 4fcb2b0d557167..ca2ccc98ea2923 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.test.ts @@ -27,6 +27,7 @@ import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/li import { RecoveredActionGroup } from '../../../../../common'; import { bulkMarkApiKeysForInvalidation } from '../../../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; import { getRuleExecutionStatusPending, getDefaultMonitoring } from '../../../../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; jest.mock('../../../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({ bulkMarkApiKeysForInvalidation: jest.fn(), @@ -174,7 +175,7 @@ describe('create()', () => { ): Promise { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -206,7 +207,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -270,7 +271,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { ...data, executionStatus: getRuleExecutionStatusPending('2019-02-12T21:01:22.479Z'), @@ -285,7 +286,7 @@ describe('create()', () => { action: 'rule_create', outcome: 'unknown', }), - kibana: { saved_object: { id: 'mock-saved-object-id', type: 'alert' } }, + kibana: { saved_object: { id: 'mock-saved-object-id', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -310,7 +311,7 @@ describe('create()', () => { kibana: { saved_object: { id: 'mock-saved-object-id', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -351,7 +352,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { ...createdAttributes, running: false, @@ -367,7 +368,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { ...createdAttributes, running: false, @@ -433,7 +434,7 @@ describe('create()', () => { `); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.create.mock.calls[0]).toHaveLength(3); - expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "actions": Array [ @@ -543,7 +544,7 @@ describe('create()', () => { `); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.update.mock.calls[0]).toHaveLength(4); - expect(unsecuredSavedObjectsClient.update.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.update.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.update.mock.calls[0][1]).toEqual('1'); expect(unsecuredSavedObjectsClient.update.mock.calls[0][2]).toMatchInlineSnapshot(` Object { @@ -582,7 +583,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { ...createdAttributes, running: false, @@ -646,7 +647,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { ...createdAttributes, running: false, @@ -798,7 +799,7 @@ describe('create()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { running: false, executionStatus: getRuleExecutionStatusPending('2019-02-12T21:01:22.479Z'), @@ -857,7 +858,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -1000,7 +1001,7 @@ describe('create()', () => { actionsClient.isPreconfigured.mockReturnValueOnce(false); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { executionStatus: getRuleExecutionStatusPending('2019-02-12T21:01:22.479Z'), alertTypeId: '123', @@ -1054,7 +1055,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -1110,7 +1111,7 @@ describe('create()', () => { } `); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -1261,7 +1262,7 @@ describe('create()', () => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { executionStatus: getRuleExecutionStatusPending('2019-02-12T21:01:22.479Z'), alertTypeId: '123', @@ -1314,7 +1315,7 @@ describe('create()', () => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -1371,7 +1372,7 @@ describe('create()', () => { `); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -1444,7 +1445,7 @@ describe('create()', () => { const data = getMockData({ enabled: false }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, alertTypeId: '123', @@ -1561,7 +1562,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -1600,7 +1601,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -1611,7 +1612,7 @@ describe('create()', () => { expect(extractReferencesFn).toHaveBeenCalledWith(ruleParams); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -1750,7 +1751,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -1789,7 +1790,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -1800,7 +1801,7 @@ describe('create()', () => { expect(extractReferencesFn).toHaveBeenCalledWith(ruleParams); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -1894,7 +1895,7 @@ describe('create()', () => { const data = getMockData({ name: ' my alert name ' }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, name: ' my alert name ', @@ -1963,7 +1964,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: createdAttributes, references: [ { @@ -1975,7 +1976,7 @@ describe('create()', () => { }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -2104,7 +2105,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: createdAttributes, references: [ { @@ -2116,7 +2117,7 @@ describe('create()', () => { }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -2245,7 +2246,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: createdAttributes, references: [ { @@ -2257,7 +2258,7 @@ describe('create()', () => { }); const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -2394,7 +2395,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: createdAttributes, references: [ { @@ -2408,7 +2409,7 @@ describe('create()', () => { const result = await rulesClient.create({ data }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { enabled: true, name: 'abc', @@ -2607,7 +2608,7 @@ describe('create()', () => { const data = getMockData(); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -2656,7 +2657,7 @@ describe('create()', () => { const data = getMockData(); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -2703,7 +2704,7 @@ describe('create()', () => { const data = getMockData(); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -2761,7 +2762,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -2791,7 +2792,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -2808,7 +2809,7 @@ describe('create()', () => { expect(rulesClientParams.createAPIKey).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -2866,7 +2867,7 @@ describe('create()', () => { const data = getMockData({ enabled: false }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -2896,7 +2897,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -2913,7 +2914,7 @@ describe('create()', () => { expect(rulesClientParams.createAPIKey).not.toHaveBeenCalled(); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -3070,7 +3071,7 @@ describe('create()', () => { }; unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: createdAttributes, references: [ { @@ -3534,7 +3535,7 @@ describe('create()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -3576,7 +3577,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -3744,7 +3745,7 @@ describe('create()', () => { rulesClientParams.isAuthenticationTypeAPIKey.mockReturnValueOnce(true); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '1m' }, @@ -3774,7 +3775,7 @@ describe('create()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'task-123', @@ -3792,7 +3793,7 @@ describe('create()', () => { expect(rulesClientParams.isAuthenticationTypeAPIKey).toHaveBeenCalledTimes(1); expect(rulesClientParams.getAuthenticationAPIKey).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { 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 74dd0775d0c222..bdd11da2483f74 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 @@ -8,6 +8,7 @@ import Semver from 'semver'; import Boom from '@hapi/boom'; import { SavedObject, SavedObjectsUtils } from '@kbn/core/server'; import { withSpan } from '@kbn/apm-utils'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { parseDuration, getRuleCircuitBreakerErrorMessage } from '../../../../../common'; import { WriteOperations, AlertingAuthorizationEntity } from '../../../../authorization'; import { @@ -101,7 +102,7 @@ export async function createRule( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.CREATE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.ts b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.ts index b670adeccae8a1..d30d172113248e 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/get_schedule_frequency/get_schedule_frequency.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { RulesClientContext } from '../../../../rules_client/types'; import { RuleDomain } from '../../types'; import { convertDurationToFrequency } from '../../../../../common/parse_duration'; @@ -41,7 +42,7 @@ export const getScheduleFrequency = async ( RuleDomain, SchedulesIntervalAggregationResult >({ - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, filter: 'alert.attributes.enabled: true', namespaces: ['*'], aggs: { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/mute_alert/mute_instance.ts b/x-pack/plugins/alerting/server/application/rule/methods/mute_alert/mute_instance.ts index 8adbdf7ae58c92..5758794b550fb8 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/mute_alert/mute_instance.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/mute_alert/mute_instance.ts @@ -6,6 +6,7 @@ */ import Boom from '@hapi/boom'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { updateRuleSo } from '../../../../data/rule/methods/update_rule_so'; import { muteAlertParamsSchema } from './schemas'; import type { MuteAlertParams } from './types'; @@ -38,7 +39,7 @@ async function muteInstanceWithOCC( { alertId, alertInstanceId }: MuteAlertParams ) { const { attributes, version } = await context.unsecuredSavedObjectsClient.get( - 'alert', + RULE_SAVED_OBJECT_TYPE, alertId ); @@ -57,7 +58,7 @@ async function muteInstanceWithOCC( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.MUTE_ALERT, - savedObject: { type: 'alert', id: alertId }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: alertId }, error, }) ); @@ -68,7 +69,7 @@ async function muteInstanceWithOCC( ruleAuditEvent({ action: RuleAuditAction.MUTE_ALERT, outcome: 'unknown', - savedObject: { type: 'alert', id: alertId }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: alertId }, }) ); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/resolve/resolve_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/resolve/resolve_rule.ts index cbde52a44b1fe8..de9f421a95924d 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/resolve/resolve_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/resolve/resolve_rule.ts @@ -7,6 +7,7 @@ import Boom from '@hapi/boom'; import { withSpan } from '@kbn/apm-utils'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { resolveRuleSavedObject } from '../../../../rules_client/lib'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { RuleTypeParams } from '../../../../types'; @@ -52,7 +53,7 @@ Promise> { context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.RESOLVE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -61,7 +62,7 @@ Promise> { context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.RESOLVE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/snooze/snooze_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/snooze/snooze_rule.ts index b10df195e5b771..162fe98d31f043 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/snooze/snooze_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/snooze/snooze_rule.ts @@ -7,6 +7,7 @@ import Boom from '@hapi/boom'; import { withSpan } from '@kbn/apm-utils'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { getRuleSavedObject } from '../../../../rules_client/lib'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { WriteOperations, AlertingAuthorizationEntity } from '../../../../authorization'; @@ -71,7 +72,7 @@ async function snoozeWithOCC( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.SNOOZE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -82,7 +83,7 @@ async function snoozeWithOCC( ruleAuditEvent({ action: RuleAuditAction.SNOOZE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); 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 dd1f3150d0a087..28e9fc08c3b8a4 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 @@ -22,6 +22,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup } from '../../../../rules_client/tests/lib'; import { RecoveredActionGroup } from '../../../../../common'; import { RegistryRuleType } from '../../../../rule_type_registry'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -147,7 +148,7 @@ describe('getTags()', () => { tags: { terms: { field: 'alert.attributes.tags', order: { _key: 'asc' }, size: 10000 } }, }, filter: undefined, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); expect(result.data).toEqual(['a', 'b', 'c']); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/unsnooze/unsnooze_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/unsnooze/unsnooze_rule.ts index c47b39f28aedb9..b5cb6f8f29e335 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/unsnooze/unsnooze_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/unsnooze/unsnooze_rule.ts @@ -7,6 +7,7 @@ import Boom from '@hapi/boom'; import { withSpan } from '@kbn/apm-utils'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../../saved_objects'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { getRuleSavedObject } from '../../../../rules_client/lib'; import { WriteOperations, AlertingAuthorizationEntity } from '../../../../authorization'; @@ -62,7 +63,7 @@ async function unsnoozeWithOCC(context: RulesClientContext, { id, scheduleIds }: context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.UNSNOOZE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -73,7 +74,7 @@ async function unsnoozeWithOCC(context: RulesClientContext, { id, scheduleIds }: ruleAuditEvent({ action: RuleAuditAction.UNSNOOZE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); diff --git a/x-pack/plugins/alerting/server/data/rule/methods/bulk_delete_rules_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/bulk_delete_rules_so.ts index 7f3568f76cf98e..15449dc003cd2b 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/bulk_delete_rules_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/bulk_delete_rules_so.ts @@ -10,6 +10,7 @@ import { SavedObjectsBulkDeleteOptions, SavedObjectsBulkDeleteResponse, } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; export interface BulkDeleteRulesSoParams { savedObjectsClient: SavedObjectsClientContract; @@ -23,7 +24,7 @@ export const bulkDeleteRulesSo = ( const { savedObjectsClient, ids, savedObjectsBulkDeleteOptions } = params; return savedObjectsClient.bulkDelete( - ids.map((id) => ({ id, type: 'alert' })), + ids.map((id) => ({ id, type: RULE_SAVED_OBJECT_TYPE })), savedObjectsBulkDeleteOptions ); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts index 7574e9aca16084..b276bb0e2e10db 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/create_rule_so.ts @@ -10,6 +10,7 @@ import { SavedObjectsCreateOptions, SavedObject, } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAttributes } from '../types'; export interface CreateRuleSoParams { @@ -21,5 +22,9 @@ export interface CreateRuleSoParams { export const createRuleSo = (params: CreateRuleSoParams): Promise> => { const { savedObjectsClient, ruleAttributes, savedObjectsCreateOptions } = params; - return savedObjectsClient.create('alert', ruleAttributes, savedObjectsCreateOptions); + return savedObjectsClient.create( + RULE_SAVED_OBJECT_TYPE, + ruleAttributes, + savedObjectsCreateOptions + ); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/delete_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/delete_rule_so.ts index e3428cfc78f637..7c15fd847303ff 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/delete_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/delete_rule_so.ts @@ -6,6 +6,7 @@ */ import { SavedObjectsClientContract, SavedObjectsDeleteOptions } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; export interface DeleteRuleSoParams { savedObjectsClient: SavedObjectsClientContract; @@ -16,5 +17,5 @@ export interface DeleteRuleSoParams { export const deleteRuleSo = (params: DeleteRuleSoParams): Promise<{}> => { const { savedObjectsClient, id, savedObjectsDeleteOptions } = params; - return savedObjectsClient.delete('alert', id, savedObjectsDeleteOptions); + return savedObjectsClient.delete(RULE_SAVED_OBJECT_TYPE, id, savedObjectsDeleteOptions); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts index 1362c2406dbae4..e929ccf019205f 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/find_rules_so.ts @@ -10,6 +10,7 @@ import { SavedObjectsFindOptions, SavedObjectsFindResponse, } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAttributes } from '../types'; export interface FindRulesSoParams { @@ -24,6 +25,6 @@ export const findRulesSo = >( return savedObjectsClient.find({ ...savedObjectsFindOptions, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts index c8777afef3f784..051644bab56f2b 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/get_rule_so.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract, SavedObject } from '@kbn/core/server'; import { SavedObjectsGetOptions } from '@kbn/core-saved-objects-api-server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAttributes } from '../types'; export interface GetRuleSoParams { @@ -18,5 +19,5 @@ export interface GetRuleSoParams { export const getRuleSo = (params: GetRuleSoParams): Promise> => { const { savedObjectsClient, id, savedObjectsGetOptions } = params; - return savedObjectsClient.get('alert', id, savedObjectsGetOptions); + return savedObjectsClient.get(RULE_SAVED_OBJECT_TYPE, id, savedObjectsGetOptions); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts index b8061cc6e3c3c0..d0429b4166d8ee 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/resolve_rule_so.ts @@ -7,6 +7,7 @@ import { SavedObjectsClientContract, SavedObjectsResolveResponse } from '@kbn/core/server'; import { SavedObjectsResolveOptions } from '@kbn/core-saved-objects-api-server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAttributes } from '../types'; export interface ResolveRuleSoParams { @@ -20,5 +21,5 @@ export const resolveRuleSo = ( ): Promise> => { const { savedObjectsClient, id, savedObjectsResolveOptions } = params; - return savedObjectsClient.resolve('alert', id, savedObjectsResolveOptions); + return savedObjectsClient.resolve(RULE_SAVED_OBJECT_TYPE, id, savedObjectsResolveOptions); }; diff --git a/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts b/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts index 8739202c237ea3..dfb8b6b5c1e7ec 100644 --- a/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts +++ b/x-pack/plugins/alerting/server/data/rule/methods/update_rule_so.ts @@ -10,6 +10,7 @@ import { SavedObjectsUpdateOptions, SavedObjectsUpdateResponse, } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAttributes } from '../types'; export interface UpdateRuleSoParams { @@ -25,7 +26,7 @@ export const updateRuleSo = ( const { savedObjectsClient, id, updateRuleAttributes, savedObjectsUpdateOptions } = params; return savedObjectsClient.update( - 'alert', + RULE_SAVED_OBJECT_TYPE, id, updateRuleAttributes, savedObjectsUpdateOptions diff --git a/x-pack/plugins/alerting/server/health/get_health.test.ts b/x-pack/plugins/alerting/server/health/get_health.test.ts index 3715113c842320..51e03dc890e986 100644 --- a/x-pack/plugins/alerting/server/health/get_health.test.ts +++ b/x-pack/plugins/alerting/server/health/get_health.test.ts @@ -6,6 +6,7 @@ */ import { savedObjectsRepositoryMock, savedObjectsServiceMock } from '@kbn/core/server/mocks'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; import { RuleExecutionStatusErrorReasons, HealthStatus } from '../types'; import { getAlertingHealthStatus, getHealth } from './get_health'; @@ -22,7 +23,7 @@ describe('getHealth()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -80,7 +81,7 @@ describe('getHealth()', () => { saved_objects: [ { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '1s' }, @@ -134,7 +135,7 @@ describe('getHealth()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -185,7 +186,7 @@ describe('getHealth()', () => { saved_objects: [ { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '1s' }, @@ -233,7 +234,7 @@ describe('getAlertingHealthStatus()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, diff --git a/x-pack/plugins/alerting/server/health/get_health.ts b/x-pack/plugins/alerting/server/health/get_health.ts index 5d2c43fe691820..f4b727170a4b9e 100644 --- a/x-pack/plugins/alerting/server/health/get_health.ts +++ b/x-pack/plugins/alerting/server/health/get_health.ts @@ -6,6 +6,7 @@ */ import { ISavedObjectsRepository, SavedObjectsServiceStart } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; import { AlertsHealth, HealthStatus, RawRule, RuleExecutionStatusErrorReasons } from '../types'; import type { LatestTaskStateSchema } from './task_state'; @@ -30,7 +31,7 @@ export const getHealth = async ( const { saved_objects: decryptErrorData } = await internalSavedObjectsRepository.find({ filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Decrypt}`, fields: ['executionStatus'], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, sortField: 'executionStatus.lastExecutionDate', sortOrder: 'desc', page: 1, @@ -48,7 +49,7 @@ export const getHealth = async ( const { saved_objects: executeErrorData } = await internalSavedObjectsRepository.find({ filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Execute}`, fields: ['executionStatus'], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, sortField: 'executionStatus.lastExecutionDate', sortOrder: 'desc', page: 1, @@ -66,7 +67,7 @@ export const getHealth = async ( const { saved_objects: readErrorData } = await internalSavedObjectsRepository.find({ filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Read}`, fields: ['executionStatus'], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, sortField: 'executionStatus.lastExecutionDate', sortOrder: 'desc', page: 1, @@ -84,7 +85,7 @@ export const getHealth = async ( const { saved_objects: noErrorData } = await internalSavedObjectsRepository.find({ filter: 'not alert.attributes.executionStatus.status:error', fields: ['executionStatus'], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, sortField: 'executionStatus.lastExecutionDate', sortOrder: 'desc', namespaces: ['*'], @@ -107,7 +108,9 @@ export const getAlertingHealthStatus = async ( savedObjects: SavedObjectsServiceStart, stateRuns: number ) => { - const alertingHealthStatus = await getHealth(savedObjects.createInternalRepository(['alert'])); + const alertingHealthStatus = await getHealth( + savedObjects.createInternalRepository([RULE_SAVED_OBJECT_TYPE]) + ); const state: LatestTaskStateSchema = { runs: stateRuns + 1, health_status: alertingHealthStatus.decryptionHealth.status, diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index 04c48ab77c8aa1..5be648354e61f4 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -34,6 +34,7 @@ export type { GetViewInAppRelativeUrlFnOpts, DataStreamAdapter, } from './types'; +export { RULE_SAVED_OBJECT_TYPE } from './saved_objects'; export { RuleNotifyWhen } from '../common'; export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config'; export type { PluginSetupContract, PluginStartContract } from './plugin'; diff --git a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts index f3fdcec752def9..680279f5dbac7f 100644 --- a/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts +++ b/x-pack/plugins/alerting/server/lib/alerting_event_logger/alerting_event_logger.ts @@ -13,6 +13,7 @@ import { } from '@kbn/event-log-plugin/server'; import { EVENT_LOG_ACTIONS } from '../../plugin'; import { UntypedNormalizedRuleType } from '../../rule_type_registry'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; import { TaskRunnerTimings } from '../../task_runner/task_runner_timer'; import { AlertInstanceState, RuleExecutionStatus } from '../../types'; import { createAlertEventLogRecordObject } from '../create_alert_event_log_record_object'; @@ -259,7 +260,7 @@ export function createAlertRecord(context: RuleContextOpts, alert: AlertOpts) { savedObjects: [ { id: context.ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: context.ruleType.id, relation: SAVED_OBJECT_REL_PRIMARY, }, @@ -286,7 +287,7 @@ export function createActionExecuteRecord(context: RuleContextOpts, action: Acti savedObjects: [ { id: context.ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: context.ruleType.id, relation: SAVED_OBJECT_REL_PRIMARY, }, @@ -319,7 +320,7 @@ export function createExecuteTimeoutRecord(context: RuleContextOpts) { savedObjects: [ { id: context.ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: context.ruleType.id, relation: SAVED_OBJECT_REL_PRIMARY, }, @@ -346,7 +347,7 @@ export function initializeExecuteRecord(context: RuleContext) { savedObjects: [ { id: context.ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: context.ruleType.id, relation: SAVED_OBJECT_REL_PRIMARY, }, diff --git a/x-pack/plugins/alerting/server/lib/is_alerting_error.test.ts b/x-pack/plugins/alerting/server/lib/is_alerting_error.test.ts index 2c4a40efb05f05..f197a8e7424de6 100644 --- a/x-pack/plugins/alerting/server/lib/is_alerting_error.test.ts +++ b/x-pack/plugins/alerting/server/lib/is_alerting_error.test.ts @@ -10,10 +10,11 @@ import { ErrorWithReason } from './error_with_reason'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { v4 as uuidv4 } from 'uuid'; import { RuleExecutionStatusErrorReasons } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; describe('isAlertSavedObjectNotFoundError', () => { const id = uuidv4(); - const errorSONF = SavedObjectsErrorHelpers.createGenericNotFoundError('alert', id); + const errorSONF = SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, id); test('identifies SavedObjects Not Found errors', () => { // ensure the error created by SO parses as a string with the format we expect @@ -34,7 +35,10 @@ describe('isAlertSavedObjectNotFoundError', () => { describe('isEsUnavailableError', () => { const id = uuidv4(); - const errorSONF = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('alert', id); + const errorSONF = SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError( + RULE_SAVED_OBJECT_TYPE, + id + ); test('identifies es unavailable errors', () => { // ensure the error created by SO parses as a string with the format we expect diff --git a/x-pack/plugins/alerting/server/lib/retry_if_conflicts.test.ts b/x-pack/plugins/alerting/server/lib/retry_if_conflicts.test.ts index 8cce79e22fe885..d1af51e179233d 100644 --- a/x-pack/plugins/alerting/server/lib/retry_if_conflicts.test.ts +++ b/x-pack/plugins/alerting/server/lib/retry_if_conflicts.test.ts @@ -8,6 +8,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { retryIfConflicts, RetryForConflictsAttempts } from './retry_if_conflicts'; import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; describe('retry_if_conflicts', () => { beforeEach(() => { @@ -47,7 +48,9 @@ describe('retry_if_conflicts', () => { MockOperationName, getOperationConflictsTimes(RetryForConflictsAttempts + 1) ) - ).rejects.toThrowError(SavedObjectsErrorHelpers.createConflictError('alert', MockAlertId)); + ).rejects.toThrowError( + SavedObjectsErrorHelpers.createConflictError(RULE_SAVED_OBJECT_TYPE, MockAlertId) + ); expect(MockLogger.debug).toBeCalledTimes(RetryForConflictsAttempts); expect(MockLogger.warn).toBeCalledTimes(1); expect(MockLogger.warn).toBeCalledWith(`${MockOperationName} conflict, exceeded retries`); @@ -71,7 +74,7 @@ function getOperationConflictsTimes(times: number) { return async function OperationConflictsTimes() { times--; if (times >= 0) { - throw SavedObjectsErrorHelpers.createConflictError('alert', MockAlertId); + throw SavedObjectsErrorHelpers.createConflictError(RULE_SAVED_OBJECT_TYPE, MockAlertId); } return MockResult; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 64bc8ca05281f3..87f6e4c3a3979e 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -77,7 +77,7 @@ import { } from './types'; import { registerAlertingUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; -import { setupSavedObjects, getLatestRuleVersion } from './saved_objects'; +import { setupSavedObjects, getLatestRuleVersion, RULE_SAVED_OBJECT_TYPE } from './saved_objects'; import { initializeApiKeyInvalidator, scheduleApiKeyInvalidatorTask, @@ -463,7 +463,7 @@ export class AlertingPlugin { licenseState?.setNotifyUsage(plugins.licensing.featureUsage.notifyUsage); const encryptedSavedObjectsClient = plugins.encryptedSavedObjects.getClient({ - includedHiddenTypes: ['alert'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE], }); const spaceIdToNamespace = (spaceId?: string) => { @@ -491,7 +491,9 @@ export class AlertingPlugin { taskManager: plugins.taskManager, securityPluginSetup: security, securityPluginStart: plugins.security, - internalSavedObjectsRepository: core.savedObjects.createInternalRepository(['alert']), + internalSavedObjectsRepository: core.savedObjects.createInternalRepository([ + RULE_SAVED_OBJECT_TYPE, + ]), encryptedSavedObjectsClient, spaceIdToNamespace, getSpaceId(request: KibanaRequest) { @@ -556,7 +558,9 @@ export class AlertingPlugin { encryptedSavedObjectsClient, basePathService: core.http.basePath, eventLogger: this.eventLogger!, - internalSavedObjectsRepository: core.savedObjects.createInternalRepository(['alert']), + internalSavedObjectsRepository: core.savedObjects.createInternalRepository([ + RULE_SAVED_OBJECT_TYPE, + ]), executionContext: core.executionContext, ruleTypeRegistry: this.ruleTypeRegistry!, alertsService: this.alertsService, @@ -571,7 +575,7 @@ export class AlertingPlugin { getMaintenanceWindowClientWithRequest, }); - this.eventLogService!.registerSavedObjectProvider('alert', (request) => { + this.eventLogService!.registerSavedObjectProvider(RULE_SAVED_OBJECT_TYPE, (request) => { const client = getRulesClientWithRequest(request); return (objects?: SavedObjectsBulkGetObject[]) => objects @@ -594,7 +598,7 @@ export class AlertingPlugin { getAlertingAuthorizationWithRequest, getRulesClientWithRequest, getFrameworkHealth: async () => - await getHealth(core.savedObjects.createInternalRepository(['alert'])), + await getHealth(core.savedObjects.createInternalRepository([RULE_SAVED_OBJECT_TYPE])), }; } @@ -621,7 +625,7 @@ export class AlertingPlugin { }, listTypes: ruleTypeRegistry!.list.bind(ruleTypeRegistry!), getFrameworkHealth: async () => - await getHealth(savedObjects.createInternalRepository(['alert'])), + await getHealth(savedObjects.createInternalRepository([RULE_SAVED_OBJECT_TYPE])), areApiKeysEnabled: async () => { const [, { security }] = await core.getStartServices(); return security?.authc.apiKeys.areAPIKeysEnabled() ?? false; diff --git a/x-pack/plugins/alerting/server/routes/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/routes/get_action_error_log.test.ts index 414d2e8b541223..408ed049044c6b 100644 --- a/x-pack/plugins/alerting/server/routes/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_action_error_log.test.ts @@ -11,6 +11,7 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../rules_client.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access', () => ({ @@ -99,7 +100,9 @@ describe('getActionErrorLogRoute', () => { rulesClient.getActionErrorLog = jest .fn() - .mockRejectedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockRejectedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts index f7fe1a3406e9cb..5eca11c27a4b25 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.test.ts @@ -12,6 +12,7 @@ import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../rules_client.mock'; import { AlertSummary } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access', () => ({ @@ -98,7 +99,9 @@ describe('getRuleAlertSummaryRoute', () => { rulesClient.getAlertSummary = jest .fn() - .mockRejectedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockRejectedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.test.ts index ff15a606231682..e92b54769d3293 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.test.ts @@ -11,6 +11,7 @@ import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../rules_client.mock'; import { getRuleExecutionKPIRoute } from './get_rule_execution_kpi'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access', () => ({ @@ -83,7 +84,9 @@ describe('getRuleExecutionKPIRoute', () => { rulesClient.getRuleExecutionKPI = jest .fn() - .mockRejectedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockRejectedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts index d84c6fe73b616c..b68d751147ebec 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.test.ts @@ -11,6 +11,7 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../rules_client.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access', () => ({ @@ -124,7 +125,9 @@ describe('getRuleStateRoute', () => { rulesClient.getAlertState = jest .fn() - .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockResolvedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, 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 a78fcd7f86f650..c04aa0b39c0225 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 @@ -13,6 +13,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; 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'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -98,7 +99,9 @@ describe('getAlertInstanceSummaryRoute', () => { rulesClient.getAlertSummary = jest .fn() - .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockResolvedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, 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 67fd50a965ea48..eab550ee4b3041 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 @@ -12,6 +12,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; 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'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -129,7 +130,9 @@ describe('getAlertStateRoute', () => { rulesClient.getAlertState = jest .fn() - .mockResolvedValueOnce(SavedObjectsErrorHelpers.createGenericNotFoundError('alert', '1')); + .mockResolvedValueOnce( + SavedObjectsErrorHelpers.createGenericNotFoundError(RULE_SAVED_OBJECT_TYPE, '1') + ); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/rules_client/common/audit_events.test.ts b/x-pack/plugins/alerting/server/rules_client/common/audit_events.test.ts index 781b8fe1f4715c..6d42be630ffd1c 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/audit_events.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/audit_events.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; import { RuleAuditAction, ruleAuditEvent } from './audit_events'; describe('#ruleAuditEvent', () => { @@ -13,7 +14,7 @@ describe('#ruleAuditEvent', () => { ruleAuditEvent({ action: RuleAuditAction.CREATE, outcome: 'unknown', - savedObject: { type: 'alert', id: 'ALERT_ID' }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: 'ALERT_ID' }, }) ).toMatchInlineSnapshot(` Object { @@ -43,7 +44,7 @@ describe('#ruleAuditEvent', () => { expect( ruleAuditEvent({ action: RuleAuditAction.CREATE, - savedObject: { type: 'alert', id: 'ALERT_ID' }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: 'ALERT_ID' }, }) ).toMatchInlineSnapshot(` Object { @@ -73,7 +74,7 @@ describe('#ruleAuditEvent', () => { expect( ruleAuditEvent({ action: RuleAuditAction.CREATE, - savedObject: { type: 'alert', id: 'ALERT_ID' }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: 'ALERT_ID' }, error: new Error('ERROR_MESSAGE'), }) ).toMatchInlineSnapshot(` diff --git a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.test.ts b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.test.ts index c5570a7422d026..d099ba8693c3fb 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.test.ts @@ -10,6 +10,7 @@ import { retryIfBulkEditConflicts } from './retry_if_bulk_edit_conflicts'; import { RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { BulkEditSkipReason } from '../../../common/bulk_edit'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const mockFilter: KueryNode = { type: 'function', @@ -21,12 +22,12 @@ const mockLogger = loggingSystemMock.create().get(); const mockSuccessfulResult = { apiKeysToInvalidate: [], rules: [ - { id: '1', type: 'alert', attributes: {} }, - { id: '2', type: 'alert', attributes: { name: 'Test rule 2' } }, + { id: '1', type: RULE_SAVED_OBJECT_TYPE, attributes: {} }, + { id: '2', type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'Test rule 2' } }, ], resultSavedObjects: [ - { id: '1', type: 'alert', attributes: {}, references: [] }, - { id: '2', type: 'alert', attributes: { name: 'Test rule 2' }, references: [] }, + { id: '1', type: RULE_SAVED_OBJECT_TYPE, attributes: {}, references: [] }, + { id: '2', type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'Test rule 2' }, references: [] }, ], errors: [], skipped: [ @@ -50,10 +51,10 @@ function getOperationConflictsTimes(times: number) { return { ...mockSuccessfulResult, resultSavedObjects: [ - { id: '1', type: 'alert', attributes: {}, references: [] }, + { id: '1', type: RULE_SAVED_OBJECT_TYPE, attributes: {}, references: [] }, { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: {}, references: [], error: { @@ -94,7 +95,7 @@ describe('retryIfBulkEditConflicts', () => { attributes: {}, id: '1', references: [], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { attributes: { @@ -102,7 +103,7 @@ describe('retryIfBulkEditConflicts', () => { }, id: '2', references: [], - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); diff --git a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts index 1a506b1b3fa867..86e38971838499 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/retry_if_bulk_edit_conflicts.ts @@ -14,6 +14,7 @@ import { convertRuleIdsToKueryNode } from '../../lib'; import { BulkOperationError } from '../types'; import { RuleAttributes } from '../../data/rule/types'; import { waitBeforeNextRetry, RETRY_IF_CONFLICTS_ATTEMPTS } from './wait_before_next_retry'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; // max number of failed SO ids in one retry filter const MaxIdsNumberInRetryFilter = 1000; @@ -70,7 +71,7 @@ export const retryIfBulkEditConflicts = async ( const conflictErrorMap = resultSavedObjects.reduce>( (acc, item) => { - if (item.type === 'alert' && item?.error?.statusCode === 409) { + if (item.type === RULE_SAVED_OBJECT_TYPE && item?.error?.statusCode === 409) { return acc.set(item.id, { message: item.error.message }); } return acc; diff --git a/x-pack/plugins/alerting/server/rules_client/common/validate_attributes.ts b/x-pack/plugins/alerting/server/rules_client/common/validate_attributes.ts index 80353ad0f6055f..b58cc453d5800f 100644 --- a/x-pack/plugins/alerting/server/rules_client/common/validate_attributes.ts +++ b/x-pack/plugins/alerting/server/rules_client/common/validate_attributes.ts @@ -8,6 +8,7 @@ import { KueryNode } from '@kbn/es-query'; import { get, isEmpty } from 'lodash'; import { alertMappings } from '../../../common/saved_objects/rules/mappings'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const astFunctionType = ['is', 'range', 'nested']; @@ -137,7 +138,10 @@ export const validateFilterKueryNode = ({ }: ValidateFilterKueryNodeParams) => { const action = ({ index, fieldName }: IterateActionProps) => { if (index === 0) { - const firstAttribute = getFieldNameAttribute(fieldName, ['alert', 'attributes']); + const firstAttribute = getFieldNameAttribute(fieldName, [ + RULE_SAVED_OBJECT_TYPE, + 'attributes', + ]); if (excludedFieldNames.includes(firstAttribute)) { throw new Error(`Filter is not supported on this field ${fieldName}`); } diff --git a/x-pack/plugins/alerting/server/rules_client/lib/check_authorization_and_get_total.ts b/x-pack/plugins/alerting/server/rules_client/lib/check_authorization_and_get_total.ts index 4327176841ad46..a4e75c58bde4bd 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/check_authorization_and_get_total.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/check_authorization_and_get_total.ts @@ -18,6 +18,7 @@ import { } from '../common/constants'; import { RulesClientContext } from '../types'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export const checkAuthorizationAndGetTotal = async ( context: RulesClientContext, @@ -54,7 +55,7 @@ export const checkAuthorizationAndGetTotal = async ( filter, page: 1, perPage: 0, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, aggs: { alertTypeId: { multi_terms: { diff --git a/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts b/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts index 14662953ba73b2..cc0d6a895dcc04 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/create_rule_saved_object.ts @@ -17,6 +17,7 @@ import { updateMeta } from './update_meta'; import { scheduleTask } from './schedule_task'; import { getAlertFromRaw } from './get_alert_from_raw'; import { createRuleSo, deleteRuleSo, updateRuleSo } from '../../data/rule'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; interface CreateRuleSavedObjectParams { intervalInMs: number; @@ -56,7 +57,7 @@ export async function createRuleSavedObject { const currentRule: SavedObject = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', diff --git a/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts b/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts index 101f846ae9ba96..f133aea9035a06 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/resolve_rule_saved_object.ts @@ -11,6 +11,7 @@ import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { resolveRuleSo } from '../../data/rule'; import { RuleAttributes } from '../../data/rule/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; interface ResolveRuleSavedObjectParams { ruleId: string; @@ -26,7 +27,7 @@ export async function resolveRuleSavedObject( ruleAuditEvent({ action: RuleAuditAction.RESOLVE, outcome: 'unknown', - savedObject: { type: 'alert', id: ruleId }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: ruleId }, }) ); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.test.ts index 072a1e98cc3de0..8830ce96a6c435 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { SavedObjectsFindResult, SavedObjectAttribute } from '@kbn/core/server'; import { loggingSystemMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; @@ -37,7 +38,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { test('calls "savedObjectsClient.find" with the expected "hasReferences"', async () => { await legacyGetBulkRuleActionsSavedObject({ alertIds: ['123'], savedObjectsClient, logger }); expect(savedObjectsClient.find).toHaveBeenCalledWith({ - hasReference: [{ id: '123', type: 'alert' }], + hasReference: [{ id: '123', type: RULE_SAVED_OBJECT_TYPE }], perPage: 10000, type: legacyRuleActionsSavedObjectType, }); @@ -70,7 +71,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -134,7 +135,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -163,7 +164,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-456', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -244,7 +245,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -330,7 +331,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -401,7 +402,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', @@ -468,7 +469,7 @@ describe('legacyGetBulkRuleActionsSavedObject', () => { id: '123', type: legacyRuleActionsSavedObjectType, references: [ - // Missing the "alert_0" of { name: 'alert_0', id: 'alert-123', type: 'alert', }, + // Missing the "alert_0" of { name: 'alert_0', id: 'alert-123', type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', id: 'action-123', @@ -539,7 +540,7 @@ describe('formatLegacyActions', () => { { name: 'alert_0', id: 'alert-123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, { name: 'action_0', diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.ts index a0aa3286f1f6de..74a56d1964ada6 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/format_legacy_actions.ts @@ -8,6 +8,7 @@ import { chunk } from 'lodash'; import type { SavedObjectsFindOptionsReference, Logger } from '@kbn/core/server'; import pMap from 'p-map'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import { RuleAction, Rule } from '../../../types'; import type { RuleExecutorServices } from '../../..'; import { injectReferencesIntoActions } from '../../common'; @@ -49,7 +50,7 @@ export const legacyGetBulkRuleActionsSavedObject = async ({ }: LegacyGetBulkRuleActionsSavedObject): Promise> => { const references = alertIds.map((alertId) => ({ id: alertId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, })); const errors: unknown[] = []; const results = await pMap( @@ -82,7 +83,7 @@ export const legacyGetBulkRuleActionsSavedObject = async ({ return actionSavedObjects.reduce((acc: { [key: string]: LegacyActionsObj }, savedObject) => { const ruleAlertId = savedObject.references.find((reference) => { // Find the first rule alert and assume that is the one we want since we should only ever have 1. - return reference.type === 'alert'; + return reference.type === RULE_SAVED_OBJECT_TYPE; }); // We check to ensure we have found a "ruleAlertId" and hopefully we have. const ruleAlertIdKey = ruleAlertId != null ? ruleAlertId.id : undefined; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts index d45c86c3f05a57..6a1a554655a3c8 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { SavedObjectsFindResponse, SavedObjectsFindResult, @@ -179,7 +180,7 @@ export const legacyGetSiemNotificationRuleNoActionsSOResult = ( ruleThrottle: 'no_actions', alertThrottle: null, }, - references: [{ id: ruleId, type: 'alert', name: 'alert_0' }], + references: [{ id: ruleId, type: RULE_SAVED_OBJECT_TYPE, name: 'alert_0' }], migrationVersion: { 'siem-detection-engine-rule-actions': '7.11.2', }, @@ -214,7 +215,7 @@ export const legacyGetSiemNotificationRuleEveryRunSOResult = ( ruleThrottle: 'rule', alertThrottle: null, }, - references: [{ id: ruleId, type: 'alert', name: 'alert_0' }], + references: [{ id: ruleId, type: RULE_SAVED_OBJECT_TYPE, name: 'alert_0' }], migrationVersion: { 'siem-detection-engine-rule-actions': '7.11.2', }, @@ -251,7 +252,7 @@ export const legacyGetSiemNotificationRuleHourlyActionsSOResult = ( alertThrottle: '1h', }, references: [ - { id: ruleId, type: 'alert', name: 'alert_0' }, + { id: ruleId, type: RULE_SAVED_OBJECT_TYPE, name: 'alert_0' }, { id: connectorId, type: 'action', name: 'action_0' }, ], migrationVersion: { @@ -290,7 +291,7 @@ export const legacyGetSiemNotificationRuleDailyActionsSOResult = ( alertThrottle: '1d', }, references: [ - { id: ruleId, type: 'alert', name: 'alert_0' }, + { id: ruleId, type: RULE_SAVED_OBJECT_TYPE, name: 'alert_0' }, { id: connectorId, type: 'action', name: 'action_0' }, ], migrationVersion: { @@ -329,7 +330,7 @@ export const legacyGetSiemNotificationRuleWeeklyActionsSOResult = ( alertThrottle: '7d', }, references: [ - { id: ruleId, type: 'alert', name: 'alert_0' }, + { id: ruleId, type: RULE_SAVED_OBJECT_TYPE, name: 'alert_0' }, { id: connectorId, type: 'action', name: 'action_0' }, ], migrationVersion: { diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts index 9678dff6898c8e..fe4bb567138616 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/retrieve_migrated_legacy_actions.ts @@ -6,6 +6,7 @@ */ import type { SavedObjectReference } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { RulesClientContext } from '../..'; import { RawRuleAction } from '../../../types'; import { find } from '../../methods/find'; @@ -52,7 +53,7 @@ export const retrieveMigratedLegacyActions: RetrieveMigratedLegacyActions = asyn options: { filter: 'alert.attributes.alertTypeId:(siem.notifications)', hasReference: { - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }, }, @@ -60,7 +61,7 @@ export const retrieveMigratedLegacyActions: RetrieveMigratedLegacyActions = asyn unsecuredSavedObjectsClient.find({ type: legacyRuleActionsSavedObjectType, hasReference: { - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }, }), diff --git a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/transform_legacy_actions.test.ts b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/transform_legacy_actions.test.ts index cea32ce3e19136..f7d9a70a3c53c8 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/transform_legacy_actions.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/siem_legacy_actions/transform_legacy_actions.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '../../../saved_objects'; import type { SavedObjectReference } from '@kbn/core/server'; import { transformFromLegacyActions } from './transform_legacy_actions'; @@ -48,7 +49,7 @@ describe('transformFromLegacyActions', () => { { name: 'alert_0', id: 'alert-1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ]); diff --git a/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts index 17794aeb4ebdfc..d69d84c7fd8c73 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/untrack_rule_alerts.ts @@ -15,6 +15,7 @@ import { EVENT_LOG_ACTIONS } from '../../plugin'; import { createAlertEventLogRecordObject } from '../../lib/create_alert_event_log_record_object'; import { RulesClientContext } from '../types'; import { RuleAttributes } from '../../data/rule/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export const untrackRuleAlerts = async ( context: RulesClientContext, @@ -67,7 +68,7 @@ export const untrackRuleAlerts = async ( savedObjects: [ { id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: attributes.alertTypeId, relation: SAVED_OBJECT_REL_PRIMARY, }, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/bulk_enable.ts b/x-pack/plugins/alerting/server/rules_client/methods/bulk_enable.ts index cac39ccb367d4c..0f01e88cfaa124 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/bulk_enable.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/bulk_enable.ts @@ -32,6 +32,7 @@ import { import { RulesClientContext, BulkOperationError, BulkOptions } from '../types'; import { validateScheduleLimit } from '../../application/rule/methods/get_schedule_frequency'; import { RuleAttributes } from '../../data/rule/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const getShouldScheduleTask = async ( context: RulesClientContext, @@ -118,7 +119,7 @@ const bulkEnableRulesWithOCC = async ( await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( { filter: filter ? nodeBuilder.and([filter, additionalFilter]) : additionalFilter, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, perPage: 100, ...(context.namespace ? { namespaces: [context.namespace] } : undefined), } @@ -241,7 +242,7 @@ const bulkEnableRulesWithOCC = async ( ruleAuditEvent({ action: RuleAuditAction.ENABLE, outcome: 'unknown', - savedObject: { type: 'alert', id: rule.id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: rule.id }, }) ); } catch (error) { diff --git a/x-pack/plugins/alerting/server/rules_client/methods/clear_expired_snoozes.ts b/x-pack/plugins/alerting/server/rules_client/methods/clear_expired_snoozes.ts index 90156246331f05..70f0e8a29eac25 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/clear_expired_snoozes.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/clear_expired_snoozes.ts @@ -6,7 +6,7 @@ */ import { RuleTypeParams, SanitizedRule } from '../../../common'; -import { partiallyUpdateAlert } from '../../saved_objects'; +import { partiallyUpdateRule } from '../../saved_objects'; import { isSnoozeExpired } from '../../lib'; import { RulesClientContext } from '../types'; import { updateMeta } from '../lib'; @@ -39,7 +39,7 @@ export async function clearExpiredSnoozes( const updateOptions = { version, refresh: false }; - await partiallyUpdateAlert( + await partiallyUpdateRule( context.unsecuredSavedObjectsClient, rule.id, updateAttributes, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/clone.ts b/x-pack/plugins/alerting/server/rules_client/methods/clone.ts index f11b5c69012c43..acc8b66d6fde85 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/clone.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/clone.ts @@ -19,6 +19,7 @@ import { getRuleExecutionStatusPendingAttributes } from '../../lib/rule_executio import { isDetectionEngineAADRuleType } from '../../saved_objects/migrations/utils'; import { createNewAPIKeySet, createRuleSavedObject } from '../lib'; import { RulesClientContext } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export type CloneArguments = [string, { newId?: string }]; @@ -33,9 +34,13 @@ export async function clone( ruleSavedObject = await withSpan( { name: 'encryptedSavedObjectsClient.getDecryptedAsInternalUser', type: 'rules' }, () => - context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }) + context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ) ); } catch (e) { // We'll skip invalidating the API key since we failed to load the decrypted saved object @@ -45,7 +50,7 @@ export async function clone( // Still attempt to load the object using SOC ruleSavedObject = await withSpan( { name: 'unsecuredSavedObjectsClient.get', type: 'rules' }, - () => context.unsecuredSavedObjectsClient.get('alert', id) + () => context.unsecuredSavedObjectsClient.get(RULE_SAVED_OBJECT_TYPE, id) ); } @@ -80,7 +85,7 @@ export async function clone( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.CREATE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -125,7 +130,7 @@ export async function clone( ruleAuditEvent({ action: RuleAuditAction.CREATE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); diff --git a/x-pack/plugins/alerting/server/rules_client/methods/delete.ts b/x-pack/plugins/alerting/server/rules_client/methods/delete.ts index 566945f0357fc0..53baa548d783c4 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/delete.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/delete.ts @@ -14,6 +14,7 @@ import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { untrackRuleAlerts, migrateLegacyActions } from '../lib'; import { RuleAttributes } from '../../data/rule/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function deleteRule(context: RulesClientContext, { id }: { id: string }) { return await retryIfConflicts( @@ -31,9 +32,13 @@ async function deleteWithOCC(context: RulesClientContext, { id }: { id: string } try { const decryptedAlert = - await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }); + await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ); apiKeyToInvalidate = decryptedAlert.attributes.apiKey; apiKeyCreatedByUser = decryptedAlert.attributes.apiKeyCreatedByUser; taskIdToRemove = decryptedAlert.attributes.scheduledTaskId; @@ -44,7 +49,10 @@ async function deleteWithOCC(context: RulesClientContext, { id }: { id: string } `delete(): Failed to load API key to invalidate on alert ${id}: ${e.message}` ); // Still attempt to load the scheduledTaskId using SOC - const alert = await context.unsecuredSavedObjectsClient.get('alert', id); + const alert = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); taskIdToRemove = alert.attributes.scheduledTaskId; attributes = alert.attributes; } @@ -60,7 +68,7 @@ async function deleteWithOCC(context: RulesClientContext, { id }: { id: string } context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.DELETE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -78,10 +86,10 @@ async function deleteWithOCC(context: RulesClientContext, { id }: { id: string } ruleAuditEvent({ action: RuleAuditAction.DELETE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); - const removeResult = await context.unsecuredSavedObjectsClient.delete('alert', id); + const removeResult = await context.unsecuredSavedObjectsClient.delete(RULE_SAVED_OBJECT_TYPE, id); await Promise.all([ taskIdToRemove ? context.taskManager.removeIfExists(taskIdToRemove) : null, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/disable.ts b/x-pack/plugins/alerting/server/rules_client/methods/disable.ts index d51a5793371f00..38b0dcc7e17d60 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/disable.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/disable.ts @@ -13,6 +13,7 @@ import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { untrackRuleAlerts, updateMeta, migrateLegacyActions } from '../lib'; import { RuleAttributes } from '../../data/rule/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function disable(context: RulesClientContext, { id }: { id: string }): Promise { return await retryIfConflicts( @@ -29,16 +30,23 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string try { const decryptedAlert = - await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }); + await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ); attributes = decryptedAlert.attributes; version = decryptedAlert.version; references = decryptedAlert.references; } catch (e) { context.logger.error(`disable(): Failed to load API key of alert ${id}: ${e.message}`); // Still attempt to load the attributes and version using SOC - const alert = await context.unsecuredSavedObjectsClient.get('alert', id); + const alert = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); attributes = alert.attributes; version = alert.version; references = alert.references; @@ -55,7 +63,7 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.DISABLE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -68,7 +76,7 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string ruleAuditEvent({ action: RuleAuditAction.DISABLE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -83,7 +91,7 @@ async function disableWithOCC(context: RulesClientContext, { id }: { id: string }); await context.unsecuredSavedObjectsClient.update( - 'alert', + RULE_SAVED_OBJECT_TYPE, id, updateMeta(context, { ...attributes, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/enable.ts b/x-pack/plugins/alerting/server/rules_client/methods/enable.ts index 53df42f012ad81..995e9891218020 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/enable.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/enable.ts @@ -16,6 +16,7 @@ import { RulesClientContext } from '../types'; import { updateMeta, createNewAPIKeySet, scheduleTask, migrateLegacyActions } from '../lib'; import { validateScheduleLimit } from '../../application/rule/methods/get_schedule_frequency'; import { getRuleCircuitBreakerErrorMessage } from '../../../common'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function enable(context: RulesClientContext, { id }: { id: string }): Promise { return await retryIfConflicts( @@ -33,9 +34,13 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } try { const decryptedAlert = - await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }); + await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ); existingApiKey = decryptedAlert.attributes.apiKey; attributes = decryptedAlert.attributes; version = decryptedAlert.version; @@ -43,7 +48,10 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } } catch (e) { context.logger.error(`enable(): Failed to load API key of alert ${id}: ${e.message}`); // Still attempt to load the attributes and version using SOC - const alert = await context.unsecuredSavedObjectsClient.get('alert', id); + const alert = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); attributes = alert.attributes; version = alert.version; references = alert.references; @@ -80,7 +88,7 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.ENABLE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -91,7 +99,7 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } ruleAuditEvent({ action: RuleAuditAction.ENABLE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -140,7 +148,7 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } // we call create with overwrite=true if (migratedActions.hasLegacyActions) { await context.unsecuredSavedObjectsClient.create( - 'alert', + RULE_SAVED_OBJECT_TYPE, { ...updateAttributes, actions: migratedActions.resultedActions, @@ -155,9 +163,14 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } } ); } else { - await context.unsecuredSavedObjectsClient.update('alert', id, updateAttributes, { - version, - }); + await context.unsecuredSavedObjectsClient.update( + RULE_SAVED_OBJECT_TYPE, + id, + updateAttributes, + { + version, + } + ); } } catch (e) { throw e; @@ -193,7 +206,7 @@ async function enableWithOCC(context: RulesClientContext, { id }: { id: string } schedule: attributes.schedule as IntervalSchedule, throwOnConflict: false, }); - await context.unsecuredSavedObjectsClient.update('alert', id, { + await context.unsecuredSavedObjectsClient.update(RULE_SAVED_OBJECT_TYPE, id, { scheduledTaskId: scheduledTask.id, }); } else { diff --git a/x-pack/plugins/alerting/server/rules_client/methods/find.ts b/x-pack/plugins/alerting/server/rules_client/methods/find.ts index 537dfef55aff0d..7ca51bcb16f19e 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/find.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/find.ts @@ -29,6 +29,7 @@ import { alertingAuthorizationFilterOpts } from '../common/constants'; import { getAlertFromRaw } from '../lib/get_alert_from_raw'; import type { IndexType, RulesClientContext } from '../types'; import { formatLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export interface FindParams { options?: FindOptions; @@ -133,7 +134,7 @@ export async function find( ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) : authorizationFilter) ?? filterKueryNode, fields: fields ? includeFieldsRequiredForAuthentication(fields) : fields, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); const siemRules: Rule[] = []; @@ -149,7 +150,7 @@ export async function find( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.FIND, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -179,7 +180,7 @@ export async function find( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.FIND, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ) ); diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get.ts b/x-pack/plugins/alerting/server/rules_client/methods/get.ts index 8b25f990d3cf12..3fb3a9e2e43c68 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get.ts @@ -12,6 +12,7 @@ import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { getAlertFromRaw } from '../lib/get_alert_from_raw'; import { RulesClientContext } from '../types'; import { formatLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export interface GetParams { id: string; @@ -29,7 +30,7 @@ export async function get( excludeFromPublicApi = false, }: GetParams ): Promise | SanitizedRuleWithLegacyId> { - const result = await context.unsecuredSavedObjectsClient.get('alert', id); + const result = await context.unsecuredSavedObjectsClient.get(RULE_SAVED_OBJECT_TYPE, id); try { await context.authorization.ensureAuthorized({ ruleTypeId: result.attributes.alertTypeId, @@ -41,7 +42,7 @@ export async function get( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -50,7 +51,7 @@ export async function get( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); const rule = getAlertFromRaw( 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 ebd1862d6b3f65..9ff65893da3a09 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 @@ -20,6 +20,7 @@ import { formatExecutionErrorsResult } from '../../lib/format_execution_log_erro import { parseDate } from '../common'; import { RulesClientContext } from '../types'; import { get } from './get'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const actionErrorLogDefaultFilter = 'event.provider:actions AND ((event.action:execute AND (event.outcome:failure OR kibana.alerting.status:warning)) OR (event.action:execute-timeout))'; @@ -53,7 +54,7 @@ export async function getActionErrorLog( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_ACTION_ERROR_LOG, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -63,7 +64,7 @@ export async function getActionErrorLog( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_ACTION_ERROR_LOG, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -76,7 +77,7 @@ export async function getActionErrorLog( try { const errorResult = await eventLogClient.findEventsBySavedObjectIds( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], { start: parsedDateStart.toISOString(), @@ -130,7 +131,7 @@ export async function getActionErrorLogWithAuth( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_ACTION_ERROR_LOG, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -143,7 +144,7 @@ export async function getActionErrorLogWithAuth( try { const errorResult = await eventLogClient.findEventsWithAuthFilter( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], authorizationTuple.filter as KueryNode, namespace, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_alert_summary.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_alert_summary.ts index 8d194b850816b0..7739b03372007d 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_alert_summary.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_alert_summary.ts @@ -13,6 +13,7 @@ import { parseDuration } from '../../../common/parse_duration'; import { parseDate } from '../common'; import { RulesClientContext } from '../types'; import { get } from './get'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export interface GetAlertSummaryParams { id: string; @@ -48,7 +49,7 @@ export async function getAlertSummary( try { const [queryResults, executionResults] = await Promise.all([ eventLogClient.findEventsBySavedObjectIds( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], { page: 1, @@ -62,7 +63,7 @@ export async function getAlertSummary( rule.legacyId !== null ? [rule.legacyId] : undefined ), eventLogClient.findEventsBySavedObjectIds( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], { page: 1, 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 734df53c9cb299..c063b8f90c614e 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 @@ -20,6 +20,7 @@ import { import { RulesClientContext } from '../types'; import { parseDate } from '../common'; import { get } from './get'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export interface GetRuleExecutionKPIParams { id: string; @@ -54,7 +55,7 @@ export async function getRuleExecutionKPI( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_RULE_EXECUTION_KPI, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -64,7 +65,7 @@ export async function getRuleExecutionKPI( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_RULE_EXECUTION_KPI, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -77,7 +78,7 @@ export async function getRuleExecutionKPI( try { const aggResult = await eventLogClient.aggregateEventsBySavedObjectIds( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], { start: parsedDateStart.toISOString(), @@ -138,7 +139,7 @@ export async function getGlobalExecutionKpiWithAuth( try { const aggResult = await eventLogClient.aggregateEventsWithAuthFilter( - 'alert', + RULE_SAVED_OBJECT_TYPE, authorizationTuple.filter as KueryNode, { start: parsedDateStart.toISOString(), 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 006109d71b4b50..f240b257bae6e3 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 @@ -22,6 +22,7 @@ import { IExecutionLogResult } from '../../../common'; import { parseDate } from '../common'; import { RulesClientContext } from '../types'; import { get } from './get'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export interface GetExecutionLogByIdParams { id: string; @@ -62,7 +63,7 @@ export async function getExecutionLogForRule( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_EXECUTION_LOG, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -72,7 +73,7 @@ export async function getExecutionLogForRule( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.GET_EXECUTION_LOG, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -85,7 +86,7 @@ export async function getExecutionLogForRule( try { const aggResult = await eventLogClient.aggregateEventsBySavedObjectIds( - 'alert', + RULE_SAVED_OBJECT_TYPE, [id], { start: parsedDateStart.toISOString(), @@ -151,7 +152,7 @@ export async function getGlobalExecutionLogWithAuth( try { const aggResult = await eventLogClient.aggregateEventsWithAuthFilter( - 'alert', + RULE_SAVED_OBJECT_TYPE, authorizationTuple.filter as KueryNode, { start: parsedDateStart.toISOString(), diff --git a/x-pack/plugins/alerting/server/rules_client/methods/mute_all.ts b/x-pack/plugins/alerting/server/rules_client/methods/mute_all.ts index 72a693aace7ace..273d794a52dc86 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/mute_all.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/mute_all.ts @@ -8,7 +8,7 @@ import { RawRule } from '../../types'; import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization'; import { retryIfConflicts } from '../../lib/retry_if_conflicts'; -import { partiallyUpdateAlert } from '../../saved_objects'; +import { partiallyUpdateRule, RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { updateMetaAttributes } from '../lib'; @@ -25,7 +25,7 @@ export async function muteAll(context: RulesClientContext, { id }: { id: string async function muteAllWithOCC(context: RulesClientContext, { id }: { id: string }) { const { attributes, version } = await context.unsecuredSavedObjectsClient.get( - 'alert', + RULE_SAVED_OBJECT_TYPE, id ); @@ -44,7 +44,7 @@ async function muteAllWithOCC(context: RulesClientContext, { id }: { id: string context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.MUTE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -55,7 +55,7 @@ async function muteAllWithOCC(context: RulesClientContext, { id }: { id: string ruleAuditEvent({ action: RuleAuditAction.MUTE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -70,7 +70,7 @@ async function muteAllWithOCC(context: RulesClientContext, { id }: { id: string }); const updateOptions = { version }; - await partiallyUpdateAlert( + await partiallyUpdateRule( context.unsecuredSavedObjectsClient, id, updateAttributes, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/run_soon.ts b/x-pack/plugins/alerting/server/rules_client/methods/run_soon.ts index 106f12ef50f6f4..8f2d605f500dc0 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/run_soon.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/run_soon.ts @@ -11,9 +11,13 @@ import { Rule } from '../../types'; import { ReadOperations, AlertingAuthorizationEntity } from '../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function runSoon(context: RulesClientContext, { id }: { id: string }) { - const { attributes } = await context.unsecuredSavedObjectsClient.get('alert', id); + const { attributes } = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); try { await context.authorization.ensureAuthorized({ ruleTypeId: attributes.alertTypeId, @@ -29,7 +33,7 @@ export async function runSoon(context: RulesClientContext, { id }: { id: string context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.RUN_SOON, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -40,7 +44,7 @@ export async function runSoon(context: RulesClientContext, { id }: { id: string ruleAuditEvent({ action: RuleAuditAction.RUN_SOON, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); diff --git a/x-pack/plugins/alerting/server/rules_client/methods/unmute_all.ts b/x-pack/plugins/alerting/server/rules_client/methods/unmute_all.ts index 52403e2d8f70e9..675387e0a600ac 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/unmute_all.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/unmute_all.ts @@ -8,7 +8,7 @@ import { RawRule } from '../../types'; import { WriteOperations, AlertingAuthorizationEntity } from '../../authorization'; import { retryIfConflicts } from '../../lib/retry_if_conflicts'; -import { partiallyUpdateAlert } from '../../saved_objects'; +import { partiallyUpdateRule, RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { updateMetaAttributes } from '../lib'; @@ -28,7 +28,7 @@ export async function unmuteAll( async function unmuteAllWithOCC(context: RulesClientContext, { id }: { id: string }) { const { attributes, version } = await context.unsecuredSavedObjectsClient.get( - 'alert', + RULE_SAVED_OBJECT_TYPE, id ); @@ -47,7 +47,7 @@ async function unmuteAllWithOCC(context: RulesClientContext, { id }: { id: strin context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.UNMUTE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -58,7 +58,7 @@ async function unmuteAllWithOCC(context: RulesClientContext, { id }: { id: strin ruleAuditEvent({ action: RuleAuditAction.UNMUTE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -73,7 +73,7 @@ async function unmuteAllWithOCC(context: RulesClientContext, { id }: { id: strin }); const updateOptions = { version }; - await partiallyUpdateAlert( + await partiallyUpdateRule( context.unsecuredSavedObjectsClient, id, updateAttributes, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/unmute_instance.ts b/x-pack/plugins/alerting/server/rules_client/methods/unmute_instance.ts index 86c894a7babd02..0b8e422f1a9462 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/unmute_instance.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/unmute_instance.ts @@ -12,6 +12,7 @@ import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { MuteOptions } from '../types'; import { RulesClientContext } from '../types'; import { updateMeta } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function unmuteInstance( context: RulesClientContext, @@ -35,7 +36,7 @@ async function unmuteInstanceWithOCC( } ) { const { attributes, version } = await context.unsecuredSavedObjectsClient.get( - 'alert', + RULE_SAVED_OBJECT_TYPE, alertId ); @@ -53,7 +54,7 @@ async function unmuteInstanceWithOCC( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.UNMUTE_ALERT, - savedObject: { type: 'alert', id: alertId }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: alertId }, error, }) ); @@ -64,7 +65,7 @@ async function unmuteInstanceWithOCC( ruleAuditEvent({ action: RuleAuditAction.UNMUTE_ALERT, outcome: 'unknown', - savedObject: { type: 'alert', id: alertId }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id: alertId }, }) ); @@ -73,7 +74,7 @@ async function unmuteInstanceWithOCC( const mutedInstanceIds = attributes.mutedInstanceIds || []; if (!attributes.muteAll && mutedInstanceIds.includes(alertInstanceId)) { await context.unsecuredSavedObjectsClient.update( - 'alert', + RULE_SAVED_OBJECT_TYPE, alertId, updateMeta(context, { updatedBy: await context.getUserName(), diff --git a/x-pack/plugins/alerting/server/rules_client/methods/update.ts b/x-pack/plugins/alerting/server/rules_client/methods/update.ts index e302b02a0e163a..8fb0de5f3519ca 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/update.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/update.ts @@ -37,6 +37,7 @@ import { validateScheduleLimit, ValidateScheduleLimitResult, } from '../../application/rule/methods/get_schedule_frequency'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; type ShouldIncrementRevision = (params?: RuleTypeParams) => boolean; @@ -80,16 +81,23 @@ async function updateWithOCC( try { alertSavedObject = - await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }); + await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ); } catch (e) { // We'll skip invalidating the API key since we failed to load the decrypted saved object context.logger.error( `update(): Failed to load API key to invalidate on alert ${id}: ${e.message}` ); // Still attempt to load the object using SOC - alertSavedObject = await context.unsecuredSavedObjectsClient.get('alert', id); + alertSavedObject = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); } const { @@ -127,7 +135,7 @@ async function updateWithOCC( context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.UPDATE, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -138,7 +146,7 @@ async function updateWithOCC( ruleAuditEvent({ action: RuleAuditAction.UPDATE, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); @@ -277,7 +285,7 @@ async function updateAlert( try { updatedObject = await context.unsecuredSavedObjectsClient.create( - 'alert', + RULE_SAVED_OBJECT_TYPE, createAttributes, { id, diff --git a/x-pack/plugins/alerting/server/rules_client/methods/update_api_key.ts b/x-pack/plugins/alerting/server/rules_client/methods/update_api_key.ts index d8d78264c448b6..ae9367b13963d2 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/update_api_key.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/update_api_key.ts @@ -12,6 +12,7 @@ import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_key import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { createNewAPIKeySet, updateMeta } from '../lib'; import { RulesClientContext } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export async function updateApiKey( context: RulesClientContext, @@ -32,9 +33,13 @@ async function updateApiKeyWithOCC(context: RulesClientContext, { id }: { id: st try { const decryptedAlert = - await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser('alert', id, { - namespace: context.namespace, - }); + await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( + RULE_SAVED_OBJECT_TYPE, + id, + { + namespace: context.namespace, + } + ); oldApiKeyToInvalidate = decryptedAlert.attributes.apiKey; oldApiKeyCreatedByUser = decryptedAlert.attributes.apiKeyCreatedByUser; attributes = decryptedAlert.attributes; @@ -45,7 +50,10 @@ async function updateApiKeyWithOCC(context: RulesClientContext, { id }: { id: st `updateApiKey(): Failed to load API key to invalidate on alert ${id}: ${e.message}` ); // Still attempt to load the attributes and version using SOC - const alert = await context.unsecuredSavedObjectsClient.get('alert', id); + const alert = await context.unsecuredSavedObjectsClient.get( + RULE_SAVED_OBJECT_TYPE, + id + ); attributes = alert.attributes; version = alert.version; } @@ -64,7 +72,7 @@ async function updateApiKeyWithOCC(context: RulesClientContext, { id }: { id: st context.auditLogger?.log( ruleAuditEvent({ action: RuleAuditAction.UPDATE_API_KEY, - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, error, }) ); @@ -92,14 +100,16 @@ async function updateApiKeyWithOCC(context: RulesClientContext, { id }: { id: st ruleAuditEvent({ action: RuleAuditAction.UPDATE_API_KEY, outcome: 'unknown', - savedObject: { type: 'alert', id }, + savedObject: { type: RULE_SAVED_OBJECT_TYPE, id }, }) ); context.ruleTypeRegistry.ensureRuleTypeEnabled(attributes.alertTypeId); try { - await context.unsecuredSavedObjectsClient.update('alert', id, updateAttributes, { version }); + await context.unsecuredSavedObjectsClient.update(RULE_SAVED_OBJECT_TYPE, id, updateAttributes, { + version, + }); } catch (e) { // Avoid unused API key await bulkMarkApiKeysForInvalidation( diff --git a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts index af03c5908daff7..e9317972474cd7 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/bulk_enable.test.ts @@ -34,6 +34,7 @@ import { } from './test_helpers'; import { TaskStatus } from '@kbn/task-manager-plugin/server'; import { migrateLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -767,12 +768,12 @@ describe('bulkEnableRules', () => { expect(auditLogger.log.mock.calls[0][0]?.event?.action).toEqual('rule_enable'); expect(auditLogger.log.mock.calls[0][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[0][0]?.kibana).toEqual({ - saved_object: { id: 'id1', type: 'alert' }, + saved_object: { id: 'id1', type: RULE_SAVED_OBJECT_TYPE }, }); expect(auditLogger.log.mock.calls[1][0]?.event?.action).toEqual('rule_enable'); expect(auditLogger.log.mock.calls[1][0]?.event?.outcome).toEqual('unknown'); expect(auditLogger.log.mock.calls[1][0]?.kibana).toEqual({ - saved_object: { id: 'id2', type: 'alert' }, + saved_object: { id: 'id2', type: RULE_SAVED_OBJECT_TYPE }, }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts index b64f1920455119..59dbfd8c87998a 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/clear_expired_snoozes.test.ts @@ -25,6 +25,7 @@ import { getBeforeSetup, mockedDateString } from './lib'; import { eventLoggerMock } from '@kbn/event-log-plugin/server/event_logger.mock'; import { TaskStatus } from '@kbn/task-manager-plugin/server'; import { RuleSnooze } from '../../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({ bulkMarkApiKeysForInvalidation: jest.fn(), @@ -113,7 +114,7 @@ describe('clearExpiredSnoozes()', () => { ]); await rulesClient.clearExpiredSnoozes({ rule: { ...attributes, id } }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { updatedAt: '2019-02-12T21:01:22.479Z', @@ -158,7 +159,7 @@ describe('clearExpiredSnoozes()', () => { ]); await rulesClient.clearExpiredSnoozes({ rule: { ...attributes, id } }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { updatedAt: '2019-02-12T21:01:22.479Z', @@ -208,7 +209,7 @@ describe('clearExpiredSnoozes()', () => { function setupTestWithSnoozeSchedule(snoozeSchedule: RuleSnooze) { const rule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'name', consumer: 'myApp', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts index a4e581414744a4..dbdfea132e2ef9 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/delete.test.ts @@ -24,6 +24,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup } from './lib'; import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; import { migrateLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -84,7 +85,7 @@ describe('delete()', () => { let rulesClient: RulesClient; const existingAlert = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', consumer: 'myApp', @@ -132,7 +133,7 @@ describe('delete()', () => { test('successfully removes an alert', async () => { const result = await rulesClient.delete({ id: '1' }); expect(result).toEqual({ success: true }); - expect(unsecuredSavedObjectsClient.delete).toHaveBeenCalledWith('alert', '1'); + expect(unsecuredSavedObjectsClient.delete).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); expect(taskManager.removeIfExists).toHaveBeenCalledWith('task-123'); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledTimes(1); expect(bulkMarkApiKeysForInvalidation).toHaveBeenCalledWith( @@ -140,9 +141,13 @@ describe('delete()', () => { expect.any(Object), expect.any(Object) ); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); }); @@ -151,10 +156,10 @@ describe('delete()', () => { const result = await rulesClient.delete({ id: '1' }); expect(result).toEqual({ success: true }); - expect(unsecuredSavedObjectsClient.delete).toHaveBeenCalledWith('alert', '1'); + expect(unsecuredSavedObjectsClient.delete).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); expect(taskManager.removeIfExists).toHaveBeenCalledWith('task-123'); expect(unsecuredSavedObjectsClient.create).not.toHaveBeenCalled(); - expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith('alert', '1'); + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); expect(rulesClientParams.logger.error).toHaveBeenCalledWith( 'delete(): Failed to load API key to invalidate on alert 1: Fail' ); @@ -298,7 +303,7 @@ describe('delete()', () => { action: 'rule_delete', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -316,7 +321,7 @@ describe('delete()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts index ca6c242539a9ae..01b9d551174cfa 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/disable.test.ts @@ -25,6 +25,7 @@ import { eventLoggerMock } from '@kbn/event-log-plugin/server/event_logger.mock' import { TaskStatus } from '@kbn/task-manager-plugin/server'; import { migrateLegacyActions } from '../lib'; import { migrateLegacyActionsMock } from '../lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -103,7 +104,7 @@ describe('disable()', () => { let rulesClient: RulesClient; const existingRule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { consumer: 'myApp', schedule: { interval: '10s' }, @@ -187,7 +188,7 @@ describe('disable()', () => { action: 'rule_disable', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -205,7 +206,7 @@ describe('disable()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -220,11 +221,15 @@ describe('disable()', () => { test('disables an rule', async () => { await rulesClient.disable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', @@ -294,11 +299,15 @@ describe('disable()', () => { }); await rulesClient.disable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', @@ -339,7 +348,7 @@ describe('disable()', () => { event: { action: 'untracked-instance', category: ['alerts'], - kind: 'alert', + kind: RULE_SAVED_OBJECT_TYPE, }, kibana: { alert: { @@ -359,7 +368,7 @@ describe('disable()', () => { id: '1', namespace: 'default', rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, type_id: 'myType', }, ], @@ -379,11 +388,15 @@ describe('disable()', () => { taskManager.get.mockRejectedValueOnce(new Error('Fail')); await rulesClient.disable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', @@ -428,12 +441,16 @@ describe('disable()', () => { test('falls back when getDecryptedAsInternalUser throws an error', async () => { encryptedSavedObjects.getDecryptedAsInternalUser.mockRejectedValueOnce(new Error('Fail')); await rulesClient.disable({ id: '1' }); - expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith('alert', '1'); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', @@ -522,11 +539,15 @@ describe('disable()', () => { }); await rulesClient.disable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', @@ -571,11 +592,15 @@ describe('disable()', () => { `"Failed to remove task"` ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { consumer: 'myApp', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts index 9ab3a919f01a59..aa587dfb99bfa8 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/enable.test.ts @@ -24,6 +24,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { migrateLegacyActions } from '../lib'; import { migrateLegacyActionsMock } from '../lib/siem_legacy_actions/retrieve_migrated_legacy_actions.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -81,7 +82,7 @@ describe('enable()', () => { const existingRule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'name', consumer: 'myApp', @@ -191,7 +192,7 @@ describe('enable()', () => { action: 'rule_enable', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -209,7 +210,7 @@ describe('enable()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -224,12 +225,16 @@ describe('enable()', () => { test('enables a rule', async () => { await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.create).not.toBeCalledWith('api_key_pending_invalidation'); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { name: 'name', @@ -280,13 +285,17 @@ describe('enable()', () => { }); await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.create).not.toBeCalledWith('api_key_pending_invalidation'); expect(rulesClientParams.createAPIKey).toHaveBeenCalledWith('Alerting: myType/name'); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { name: 'name', @@ -353,7 +362,7 @@ describe('enable()', () => { await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { name: 'name', @@ -412,7 +421,7 @@ describe('enable()', () => { encryptedSavedObjects.getDecryptedAsInternalUser.mockRejectedValue(new Error('Fail')); await rulesClient.enable({ id: '1' }); - expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith('alert', '1'); + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); expect(rulesClientParams.logger.error).toHaveBeenCalledWith( 'enable(): Failed to load API key of alert 1: Fail' ); @@ -451,9 +460,13 @@ describe('enable()', () => { test('enables task when scheduledTaskId is defined and task exists', async () => { await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalled(); expect(taskManager.bulkEnable).toHaveBeenCalledWith(['task-123']); }); @@ -464,9 +477,13 @@ describe('enable()', () => { `"Failed to enable task"` ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalled(); }); @@ -487,9 +504,13 @@ describe('enable()', () => { taskManager.get.mockRejectedValueOnce(new Error('Failed to get task!')); await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(2); expect(taskManager.bulkEnable).not.toHaveBeenCalled(); expect(taskManager.schedule).toHaveBeenCalledWith({ @@ -511,9 +532,14 @@ describe('enable()', () => { }, scope: ['alerting'], }); - expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith(2, 'alert', '1', { - scheduledTaskId: '1', - }); + expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith( + 2, + RULE_SAVED_OBJECT_TYPE, + '1', + { + scheduledTaskId: '1', + } + ); }); test('schedules task when scheduledTaskId is not defined', async () => { @@ -536,9 +562,13 @@ describe('enable()', () => { }); await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(2); expect(taskManager.bulkEnable).not.toHaveBeenCalled(); expect(taskManager.schedule).toHaveBeenCalledWith({ @@ -560,9 +590,14 @@ describe('enable()', () => { }, scope: ['alerting'], }); - expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith(2, 'alert', '1', { - scheduledTaskId: '1', - }); + expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith( + 2, + RULE_SAVED_OBJECT_TYPE, + '1', + { + scheduledTaskId: '1', + } + ); }); test('schedules task when task with scheduledTaskId exists but is unrecognized', async () => { @@ -582,9 +617,13 @@ describe('enable()', () => { taskManager.get.mockResolvedValue({ ...mockTask, status: TaskStatus.Unrecognized }); await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(2); expect(taskManager.bulkEnable).not.toHaveBeenCalled(); expect(taskManager.removeIfExists).toHaveBeenCalledWith('task-123'); @@ -607,9 +646,14 @@ describe('enable()', () => { }, scope: ['alerting'], }); - expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith(2, 'alert', '1', { - scheduledTaskId: '1', - }); + expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith( + 2, + RULE_SAVED_OBJECT_TYPE, + '1', + { + scheduledTaskId: '1', + } + ); }); test('throws error when scheduling task fails', async () => { @@ -637,9 +681,13 @@ describe('enable()', () => { ); await rulesClient.enable({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(2); expect(taskManager.bulkEnable).not.toHaveBeenCalled(); expect(taskManager.schedule).toHaveBeenCalled(); @@ -681,9 +729,14 @@ describe('enable()', () => { expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledTimes(2); expect(taskManager.schedule).toHaveBeenCalled(); expect(taskManager.bulkEnable).not.toHaveBeenCalled(); - expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith(2, 'alert', '1', { - scheduledTaskId: '1', - }); + expect(unsecuredSavedObjectsClient.update).toHaveBeenNthCalledWith( + 2, + RULE_SAVED_OBJECT_TYPE, + '1', + { + scheduledTaskId: '1', + } + ); }); describe('legacy actions migration for SIEM', () => { @@ -722,7 +775,7 @@ describe('enable()', () => { }); // to mitigate AAD issues, we call create with overwrite=true and actions related props expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, expect.objectContaining({ ...existingDecryptedSiemRule.attributes, actions: ['fake-action-1'], diff --git a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts index 3aea832752dfa4..a6fa7514696257 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/find.test.ts @@ -26,6 +26,7 @@ import { RegistryRuleType } from '../../rule_type_registry'; import { schema } from '@kbn/config-schema'; import { enabledRule1, enabledRule2, siemRule1, siemRule2 } from './test_helpers'; import { formatLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/format_legacy_actions', () => { return { @@ -108,7 +109,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -221,7 +222,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -322,7 +323,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -524,7 +525,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -555,7 +556,7 @@ describe('find()', () => { }, { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '20s' }, @@ -738,7 +739,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', schedule: { interval: '10s' }, @@ -769,7 +770,7 @@ describe('find()', () => { }, { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '20s' }, @@ -854,7 +855,7 @@ describe('find()', () => { saved_objects: [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], alertTypeId: 'myType', @@ -893,7 +894,7 @@ describe('find()', () => { fields: ['tags', 'alertTypeId', 'consumer'], filter: null, sortField: undefined, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }); expect(ensureRuleTypeIsAuthorized).toHaveBeenCalledWith('myType', 'myApp', 'rule'); }); @@ -909,7 +910,7 @@ describe('find()', () => { action: 'rule_find', outcome: 'success', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -948,7 +949,7 @@ describe('find()', () => { action: 'rule_find', outcome: 'failure', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, error: { code: 'Error', message: 'Unauthorized', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts index 0d29a3fc402d12..c8eaa3eb319eca 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get.test.ts @@ -23,6 +23,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { RecoveredActionGroup } from '../../../common'; import { formatLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/format_legacy_actions', () => { return { @@ -76,7 +77,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -143,7 +144,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -224,7 +225,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -327,7 +328,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -402,7 +403,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -455,7 +456,7 @@ describe('get()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -498,7 +499,7 @@ describe('get()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', consumer: 'myApp', @@ -561,7 +562,7 @@ describe('get()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -583,7 +584,7 @@ describe('get()', () => { action: 'rule_get', outcome: 'success', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -602,7 +603,7 @@ describe('get()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -617,7 +618,7 @@ describe('get()', () => { describe('legacy actions migration for SIEM', () => { const rule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts index 0fe46a07e4e7f8..d6c8f0a0df3ec6 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts @@ -25,6 +25,7 @@ import { SavedObject } from '@kbn/core/server'; import { RawRule } from '../../types'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, mockedDateString, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -74,7 +75,7 @@ const RuleIntervalSeconds = 1; const BaseRuleSavedObject: SavedObject = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', @@ -139,7 +140,7 @@ const findResults = { }, { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', type_id: 'example.always-firing', }, @@ -188,7 +189,7 @@ const findResults = { }, { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', type_id: 'example.always-firing', }, @@ -237,7 +238,7 @@ const findResults = { }, { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', type_id: 'example.always-firing', }, @@ -286,7 +287,7 @@ const findResults = { }, { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', type_id: 'example.always-firing', }, @@ -335,7 +336,7 @@ const findResults = { }, { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', type_id: 'example.always-firing', }, @@ -450,7 +451,7 @@ describe('getActionErrorLog()', () => { expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { page: 1, @@ -480,7 +481,7 @@ describe('getActionErrorLog()', () => { expect(eventLogClient.findEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.findEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { page: 3, @@ -554,7 +555,7 @@ describe('getActionErrorLog()', () => { action: 'rule_get_action_error_log', outcome: 'success', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -576,7 +577,7 @@ describe('getActionErrorLog()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts index dee5cb2ab9a81a..671dcc59c886f2 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_state.test.ts @@ -20,6 +20,7 @@ import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; import { AlertingAuthorization } from '../../authorization/alerting_authorization'; import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { getBeforeSetup } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -64,7 +65,7 @@ describe('getAlertState()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -121,7 +122,7 @@ describe('getAlertState()', () => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -176,7 +177,7 @@ describe('getAlertState()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', consumer: 'myApp', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts index 1521dfdefced36..ba0e2d7a1a4856 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_alert_summary.test.ts @@ -25,6 +25,7 @@ import { SavedObject } from '@kbn/core/server'; import { EventsFactory } from '../../lib/alert_summary_from_event_log.test'; import { RawRule } from '../../types'; import { getBeforeSetup, mockedDateString, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -78,7 +79,7 @@ const RuleIntervalSeconds = 1; const BaseRuleSavedObject: SavedObject = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts index f1d2dbcacf8fda..c4419ef8386a57 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts @@ -26,6 +26,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, mockedDateString, setGlobalDate } from './lib'; import { getExecutionLogAggregation } from '../../lib/get_execution_log_aggregation'; import { fromKueryExpression } from '@kbn/es-query'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -75,7 +76,7 @@ const RuleIntervalSeconds = 1; const BaseRuleSavedObject: SavedObject = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', @@ -444,7 +445,7 @@ describe('getExecutionLogForRule()', () => { expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { aggs: getExecutionLogAggregation({ @@ -470,7 +471,7 @@ describe('getExecutionLogForRule()', () => { expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { aggs: getExecutionLogAggregation({ @@ -496,7 +497,7 @@ describe('getExecutionLogForRule()', () => { expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { aggs: getExecutionLogAggregation({ @@ -522,7 +523,7 @@ describe('getExecutionLogForRule()', () => { expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds).toHaveBeenCalledTimes(1); expect(eventLogClient.aggregateEventsBySavedObjectIds.mock.calls[0]).toEqual([ - 'alert', + RULE_SAVED_OBJECT_TYPE, ['1'], { aggs: getExecutionLogAggregation({ @@ -662,7 +663,7 @@ describe('getExecutionLogForRule()', () => { action: 'rule_get_execution_log', outcome: 'success', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -684,7 +685,7 @@ describe('getExecutionLogForRule()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts index 12da7211fdc12b..20c0759e1d628b 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/lib.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/lib.ts @@ -13,6 +13,7 @@ import { TaskStatus } from '@kbn/task-manager-plugin/server'; import { ConstructorOptions } from '../rules_client'; import { RuleTypeRegistry } from '../../rule_type_registry'; import { RecoveredActionGroup } from '../../../common'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export const mockedDateString = '2019-02-12T21:01:22.479Z'; @@ -69,7 +70,7 @@ export function getBeforeSetup( enabled: false, }); taskManager.bulkRemove.mockResolvedValue({ - statuses: [{ id: 'taskId', type: 'alert', success: true }], + statuses: [{ id: 'taskId', type: RULE_SAVED_OBJECT_TYPE, success: true }], }); const actionsClient = actionsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts index 2b6e2793aa648d..cf585cc67a417d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_all.test.ts @@ -20,6 +20,7 @@ import { AlertingAuthorization } from '../../authorization/alerting_authorizatio import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -67,7 +68,7 @@ describe('muteAll()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -88,7 +89,7 @@ describe('muteAll()', () => { await rulesClient.muteAll({ id: '1' }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { muteAll: true, @@ -107,7 +108,7 @@ describe('muteAll()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -171,7 +172,7 @@ describe('muteAll()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -196,7 +197,7 @@ describe('muteAll()', () => { action: 'rule_mute', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -205,7 +206,7 @@ describe('muteAll()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -235,7 +236,7 @@ describe('muteAll()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts index 4d7f1a52699cc3..3aae21df3133dd 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/mute_instance.test.ts @@ -20,6 +20,7 @@ import { AlertingAuthorization } from '../../authorization/alerting_authorizatio import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -67,7 +68,7 @@ describe('muteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -82,7 +83,7 @@ describe('muteInstance()', () => { await rulesClient.muteInstance({ alertId: '1', alertInstanceId: '2' }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { mutedInstanceIds: ['2'], @@ -99,7 +100,7 @@ describe('muteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -119,7 +120,7 @@ describe('muteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -140,7 +141,7 @@ describe('muteInstance()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -204,7 +205,7 @@ describe('muteInstance()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -223,7 +224,7 @@ describe('muteInstance()', () => { action: 'rule_alert_mute', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -232,7 +233,7 @@ describe('muteInstance()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -258,7 +259,7 @@ describe('muteInstance()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts index 70c6388c41ff45..13ab4778f82bc7 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/resolve.test.ts @@ -23,6 +23,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { RecoveredActionGroup } from '../../../common'; import { formatLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/format_legacy_actions', () => { return { @@ -77,7 +78,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -160,7 +161,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { legacyId: 'some-legacy-id', alertTypeId: '123', @@ -243,7 +244,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -333,7 +334,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -395,7 +396,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -442,7 +443,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', consumer: 'myApp', @@ -514,7 +515,7 @@ describe('resolve()', () => { unsecuredSavedObjectsClient.resolve.mockResolvedValueOnce({ saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, @@ -544,7 +545,7 @@ describe('resolve()', () => { action: 'rule_resolve', outcome: 'success', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -563,7 +564,7 @@ describe('resolve()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -578,7 +579,7 @@ describe('resolve()', () => { describe('legacy actions migration for SIEM', () => { const rule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: '123', schedule: { interval: '10s' }, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts index 9040096eba8b0b..b156838704e0bd 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/run_soon.test.ts @@ -21,6 +21,7 @@ import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { TaskStatus } from '@kbn/task-manager-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -64,7 +65,7 @@ describe('runSoon()', () => { const existingRule = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'name', consumer: 'myApp', @@ -154,7 +155,7 @@ describe('runSoon()', () => { action: 'rule_run_soon', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -172,7 +173,7 @@ describe('runSoon()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/test_helpers.ts b/x-pack/plugins/alerting/server/rules_client/tests/test_helpers.ts index 8b2db346865770..f060187775a8e4 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/test_helpers.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/test_helpers.ts @@ -7,6 +7,7 @@ import { AlertConsumers } from '@kbn/rule-data-utils'; import type { SavedObject } from '@kbn/core-saved-objects-server'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; export const savedObjectWith500Error = { id: 'id2', @@ -30,7 +31,7 @@ export const savedObjectWith409Error = { export const defaultRule = { id: 'id1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { name: 'fakeName', consumer: 'fakeConsumer', @@ -44,7 +45,7 @@ export const defaultRule = { export const defaultRuleForBulkDelete = { id: 'id1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { tags: ['ups'], params: { param: 1 }, diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts index c8cb134b129d71..f8329f20fc432e 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_all.test.ts @@ -20,6 +20,7 @@ import { AlertingAuthorization } from '../../authorization/alerting_authorizatio import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -67,7 +68,7 @@ describe('unmuteAll()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -88,7 +89,7 @@ describe('unmuteAll()', () => { await rulesClient.unmuteAll({ id: '1' }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { muteAll: false, @@ -107,7 +108,7 @@ describe('unmuteAll()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -171,7 +172,7 @@ describe('unmuteAll()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -196,7 +197,7 @@ describe('unmuteAll()', () => { action: 'rule_unmute', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -205,7 +206,7 @@ describe('unmuteAll()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -235,7 +236,7 @@ describe('unmuteAll()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts index 4df037b8728f0d..8d9232c4381c3a 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/unmute_instance.test.ts @@ -20,6 +20,7 @@ import { AlertingAuthorization } from '../../authorization/alerting_authorizatio import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; const taskManager = taskManagerMock.createStart(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -67,7 +68,7 @@ describe('unmuteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -82,7 +83,7 @@ describe('unmuteInstance()', () => { await rulesClient.unmuteInstance({ alertId: '1', alertInstanceId: '2' }); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { mutedInstanceIds: [], @@ -97,7 +98,7 @@ describe('unmuteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -117,7 +118,7 @@ describe('unmuteInstance()', () => { const rulesClient = new RulesClient(rulesClientParams); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -138,7 +139,7 @@ describe('unmuteInstance()', () => { beforeEach(() => { unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [ { @@ -202,7 +203,7 @@ describe('unmuteInstance()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -221,7 +222,7 @@ describe('unmuteInstance()', () => { action: 'rule_alert_unmute', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -230,7 +231,7 @@ describe('unmuteInstance()', () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); unsecuredSavedObjectsClient.get.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], schedule: { interval: '10s' }, @@ -256,7 +257,7 @@ describe('unmuteInstance()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts index c151e4f75e99e4..aa03a71d93e141 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update.test.ts @@ -28,6 +28,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; import { migrateLegacyActions } from '../lib'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../lib/siem_legacy_actions/migrate_legacy_actions', () => { return { @@ -106,7 +107,7 @@ describe('update()', () => { let actionsClient: jest.Mocked; const existingAlert = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -238,7 +239,7 @@ describe('update()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -376,14 +377,18 @@ describe('update()', () => { "updatedAt": 2019-02-12T21:01:22.479Z, } `); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledTimes(1); expect(bulkMarkApiKeysForInvalidationMock).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.create.mock.calls[0]).toHaveLength(3); - expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "actions": Array [ @@ -537,7 +542,7 @@ describe('update()', () => { actionsClient.isPreconfigured.mockReturnValueOnce(true); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -628,7 +633,7 @@ describe('update()', () => { expect(unsecuredSavedObjectsClient.create).toHaveBeenNthCalledWith( 1, - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -728,9 +733,13 @@ describe('update()', () => { "updatedAt": 2019-02-12T21:01:22.479Z, } `); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); expect(actionsClient.isPreconfigured).toHaveBeenCalledTimes(3); }); @@ -789,7 +798,7 @@ describe('update()', () => { actionsClient.isSystemAction.mockReturnValueOnce(true); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -872,7 +881,7 @@ describe('update()', () => { expect(unsecuredSavedObjectsClient.create).toHaveBeenNthCalledWith( 1, - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -964,9 +973,13 @@ describe('update()', () => { "updatedAt": 2019-02-12T21:01:22.479Z, } `); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); expect(actionsClient.isSystemAction).toHaveBeenCalledTimes(3); }); @@ -1017,7 +1030,7 @@ describe('update()', () => { })); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -1077,7 +1090,7 @@ describe('update()', () => { expect(extractReferencesFn).toHaveBeenCalledWith(ruleParams); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -1161,7 +1174,7 @@ describe('update()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -1254,7 +1267,7 @@ describe('update()', () => { expect.any(Object) ); expect(unsecuredSavedObjectsClient.create.mock.calls[0]).toHaveLength(3); - expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "actions": Array [ @@ -1321,7 +1334,7 @@ describe('update()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, schedule: { interval: '1m' }, @@ -1407,7 +1420,7 @@ describe('update()', () => { `); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledTimes(1); expect(unsecuredSavedObjectsClient.create.mock.calls[0]).toHaveLength(3); - expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "actions": Array [ @@ -1563,7 +1576,7 @@ describe('update()', () => { it('should trim alert name in the API key name', async () => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, name: ' my alert name ', @@ -1613,7 +1626,7 @@ describe('update()', () => { it('swallows error when invalidate API key throws', async () => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -1721,7 +1734,7 @@ describe('update()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -1840,7 +1853,7 @@ describe('update()', () => { ], }, }); - expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith('alert', '1'); + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); expect(rulesClientParams.logger.error).toHaveBeenCalledWith( 'update(): Failed to load API key to invalidate on alert 1: Fail' ); @@ -1920,7 +1933,7 @@ describe('update()', () => { }); encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({ id: alertId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], enabled: true, @@ -1947,7 +1960,7 @@ describe('update()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: alertId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: updatedSchedule, @@ -2374,7 +2387,7 @@ describe('update()', () => { actionsClient.isPreconfigured.mockReturnValueOnce(true); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -2436,7 +2449,7 @@ describe('update()', () => { expect(unsecuredSavedObjectsClient.create).toHaveBeenNthCalledWith( 1, - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -2502,9 +2515,13 @@ describe('update()', () => { "updatedAt": 2019-02-12T21:01:22.479Z, } `); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); expect(actionsClient.isPreconfigured).toHaveBeenCalledTimes(1); }); @@ -2549,7 +2566,7 @@ describe('update()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -2700,7 +2717,7 @@ describe('update()', () => { beforeEach(() => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { alertTypeId: 'myType', consumer: 'myApp', @@ -2779,7 +2796,7 @@ describe('update()', () => { beforeEach(() => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -2817,7 +2834,7 @@ describe('update()', () => { action: 'rule_update', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -2850,7 +2867,7 @@ describe('update()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { @@ -2885,7 +2902,7 @@ describe('update()', () => { ]); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -2980,7 +2997,7 @@ describe('update()', () => { }, }); expect(unsecuredSavedObjectsClient.create).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, { actions: [ { @@ -3031,7 +3048,7 @@ describe('update()', () => { beforeEach(() => { unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -3093,7 +3110,7 @@ describe('update()', () => { }); unsecuredSavedObjectsClient.create.mockResolvedValueOnce({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, schedule: { interval: '1m' }, @@ -3190,7 +3207,7 @@ describe('update()', () => { expect(bulkMarkApiKeysForInvalidationMock).not.toHaveBeenCalled(); expect(unsecuredSavedObjectsClient.create.mock.calls[0]).toHaveLength(3); - expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual('alert'); + expect(unsecuredSavedObjectsClient.create.mock.calls[0][0]).toEqual(RULE_SAVED_OBJECT_TYPE); expect(unsecuredSavedObjectsClient.create.mock.calls[0][1]).toMatchInlineSnapshot(` Object { "actions": Array [ diff --git a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts index f9cd570afa430e..de54ab9f8d5f1d 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/update_api_key.test.ts @@ -21,6 +21,7 @@ import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from './lib'; import { bulkMarkApiKeysForInvalidation } from '../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation'; +import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; jest.mock('../../invalidate_pending_api_keys/bulk_mark_api_keys_for_invalidation', () => ({ bulkMarkApiKeysForInvalidation: jest.fn(), @@ -73,7 +74,7 @@ describe('updateApiKey()', () => { let rulesClient: RulesClient; const existingAlert = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { revision: 0, schedule: { interval: '10s' }, @@ -117,11 +118,15 @@ describe('updateApiKey()', () => { }); await rulesClient.updateApiKey({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { schedule: { interval: '10s' }, @@ -174,11 +179,15 @@ describe('updateApiKey()', () => { }); await rulesClient.updateApiKey({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { schedule: { interval: '10s' }, @@ -226,11 +235,15 @@ describe('updateApiKey()', () => { }); await rulesClient.updateApiKey({ id: '1' }); expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled(); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { schedule: { interval: '10s' }, @@ -282,12 +295,16 @@ describe('updateApiKey()', () => { encryptedSavedObjects.getDecryptedAsInternalUser.mockRejectedValueOnce(new Error('Fail')); await rulesClient.updateApiKey({ id: '1' }); - expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith('alert', '1'); - expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith('alert', '1', { - namespace: 'default', - }); + expect(unsecuredSavedObjectsClient.get).toHaveBeenCalledWith(RULE_SAVED_OBJECT_TYPE, '1'); + expect(encryptedSavedObjects.getDecryptedAsInternalUser).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + '1', + { + namespace: 'default', + } + ); expect(unsecuredSavedObjectsClient.update).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { schedule: { interval: '10s' }, @@ -401,7 +418,7 @@ describe('updateApiKey()', () => { action: 'rule_update_api_key', outcome: 'unknown', }), - kibana: { saved_object: { id: '1', type: 'alert' } }, + kibana: { saved_object: { id: '1', type: RULE_SAVED_OBJECT_TYPE } }, }) ); }); @@ -419,7 +436,7 @@ describe('updateApiKey()', () => { kibana: { saved_object: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, }, error: { diff --git a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts index d36c4a72d2bd23..821a04601c62de 100644 --- a/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_conflict_retries.test.ts @@ -24,6 +24,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { RetryForConflictsAttempts } from './lib/retry_if_conflicts'; import { TaskStatus } from '@kbn/task-manager-plugin/server/task'; import { RecoveredActionGroup } from '../common'; +import { RULE_SAVED_OBJECT_TYPE } from './saved_objects'; jest.mock('./application/rule/methods/get_schedule_frequency', () => ({ validateScheduleLimit: jest.fn(), @@ -227,7 +228,7 @@ function expectSuccess( // tests to run when the method is expected to fail function expectConflict(success: boolean, err: Error, method: 'update' | 'create' = 'update') { const conflictErrorMessage = SavedObjectsErrorHelpers.createConflictError( - 'alert', + RULE_SAVED_OBJECT_TYPE, MockAlertId ).message; @@ -249,7 +250,7 @@ function mockSavedObjectUpdateConflictErrorTimes(times: number) { // default success value const mockUpdateValue = { id: MockAlertId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'scheduled-task-id', @@ -263,10 +264,10 @@ function mockSavedObjectUpdateConflictErrorTimes(times: number) { // queue up specified number of errors before a success call for (let i = 0; i < times; i++) { unsecuredSavedObjectsClient.update.mockRejectedValueOnce( - SavedObjectsErrorHelpers.createConflictError('alert', MockAlertId) + SavedObjectsErrorHelpers.createConflictError(RULE_SAVED_OBJECT_TYPE, MockAlertId) ); unsecuredSavedObjectsClient.create.mockRejectedValueOnce( - SavedObjectsErrorHelpers.createConflictError('alert', MockAlertId) + SavedObjectsErrorHelpers.createConflictError(RULE_SAVED_OBJECT_TYPE, MockAlertId) ); } } @@ -276,9 +277,9 @@ function setupRawAlertMocks( overrides: Record = {}, attributeOverrides: Record = {} ) { - const rawAlert = { + const rawRule = { id: MockAlertId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, tags: ['foo'], @@ -297,10 +298,10 @@ function setupRawAlertMocks( version: '123', ...overrides, }; - const decryptedRawAlert = { - ...rawAlert, + const decryptedRawRule = { + ...rawRule, attributes: { - ...rawAlert.attributes, + ...rawRule.attributes, apiKey: Buffer.from('123:abc').toString('base64'), }, }; @@ -310,11 +311,11 @@ function setupRawAlertMocks( // splitting this out as it's easier to set a breakpoint :-) unsecuredSavedObjectsClient.get.mockImplementation(async () => { - return cloneDeep(rawAlert); + return cloneDeep(rawRule); }); encryptedSavedObjects.getDecryptedAsInternalUser.mockImplementation(async () => { - return cloneDeep(decryptedRawAlert); + return cloneDeep(decryptedRawRule); }); } 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 0532a48be01e11..76f4943172a4b8 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -26,6 +26,7 @@ import { AlertingAuthorization } from './authorization'; import { AlertingAuthorizationClientFactory } from './alerting_authorization_client_factory'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; import { mockRouter } from '@kbn/core-http-router-server-mocks'; +import { RULE_SAVED_OBJECT_TYPE } from './saved_objects'; jest.mock('./rules_client'); jest.mock('./authorization/alerting_authorization'); @@ -85,7 +86,7 @@ test('creates a rules client with proper constructor arguments when security is expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], - includedHiddenTypes: ['alert', 'api_key_pending_invalidation'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE, 'api_key_pending_invalidation'], }); expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request); @@ -133,7 +134,7 @@ test('creates a rules client with proper constructor arguments', async () => { expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], - includedHiddenTypes: ['alert', 'api_key_pending_invalidation'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE, 'api_key_pending_invalidation'], }); expect(alertingAuthorizationClientFactory.create).toHaveBeenCalledWith(request); diff --git a/x-pack/plugins/alerting/server/rules_client_factory.ts b/x-pack/plugins/alerting/server/rules_client_factory.ts index 6f2930429256eb..6b637eed5cd1fb 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.ts @@ -28,6 +28,7 @@ import { AlertingAuthorizationClientFactory } from './alerting_authorization_cli import { AlertingRulesConfig } from './config'; import { GetAlertIndicesAlias } from './lib'; import { AlertsService } from './alerts_service/alerts_service'; +import { RULE_SAVED_OBJECT_TYPE } from './saved_objects'; export interface RulesClientFactoryOpts { logger: Logger; taskManager: TaskManagerStartContract; @@ -113,7 +114,7 @@ export class RulesClientFactory { maxScheduledPerMinute: this.maxScheduledPerMinute, unsecuredSavedObjectsClient: savedObjects.getScopedClient(request, { excludedExtensions: [SECURITY_EXTENSION_ID], - includedHiddenTypes: ['alert', 'api_key_pending_invalidation'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE, 'api_key_pending_invalidation'], }), authorization: this.authorization.create(request), actionsAuthorization: actions.getActionsAuthorizationWithRequest(request), diff --git a/x-pack/plugins/alerting/server/saved_objects/get_import_warnings.test.ts b/x-pack/plugins/alerting/server/saved_objects/get_import_warnings.test.ts index 1eff02d7322310..85c35693b2b6a5 100644 --- a/x-pack/plugins/alerting/server/saved_objects/get_import_warnings.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/get_import_warnings.test.ts @@ -6,6 +6,7 @@ */ import { SavedObject } from '@kbn/core/server'; +import { RULE_SAVED_OBJECT_TYPE } from '.'; import { RawRule } from '../types'; import { getImportWarnings } from './get_import_warnings'; @@ -14,7 +15,7 @@ describe('getImportWarnings', () => { const savedObjectRules = [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name1', @@ -43,7 +44,7 @@ describe('getImportWarnings', () => { }, { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name2', diff --git a/x-pack/plugins/alerting/server/saved_objects/index.ts b/x-pack/plugins/alerting/server/saved_objects/index.ts index 9006bf1cab1b61..385a5dd25d6bf6 100644 --- a/x-pack/plugins/alerting/server/saved_objects/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/index.ts @@ -23,7 +23,7 @@ import { RawRule } from '../types'; import { getImportWarnings } from './get_import_warnings'; import { isRuleExportable } from './is_rule_exportable'; import { RuleTypeRegistry } from '../rule_type_registry'; -export { partiallyUpdateAlert } from './partially_update_alert'; +export { partiallyUpdateRule } from './partially_update_rule'; export { getLatestRuleVersion, getMinimumCompatibleVersion } from './rule_model_versions'; import { RULES_SETTINGS_SAVED_OBJECT_TYPE, @@ -31,10 +31,12 @@ import { } from '../../common'; import { ruleModelVersions } from './rule_model_versions'; +export const RULE_SAVED_OBJECT_TYPE = 'alert'; + // Use caution when removing items from this array! Any field which has // ever existed in the rule SO must be included in this array to prevent // decryption failures during migration. -export const AlertAttributesExcludedFromAAD = [ +export const RuleAttributesExcludedFromAAD = [ 'scheduledTaskId', 'muteAll', 'mutedInstanceIds', @@ -51,11 +53,11 @@ export const AlertAttributesExcludedFromAAD = [ 'running', ]; -// useful for Pick which is a +// useful for Pick which is a // type which is a subset of RawAlert with just attributes excluded from AAD -// useful for Pick -export type AlertAttributesExcludedFromAADType = +// useful for Pick +export type RuleAttributesExcludedFromAADType = | 'scheduledTaskId' | 'muteAll' | 'mutedInstanceIds' @@ -80,7 +82,7 @@ export function setupSavedObjects( getSearchSourceMigrations: () => MigrateFunctionsObject ) { savedObjects.registerType({ - name: 'alert', + name: RULE_SAVED_OBJECT_TYPE, indexPattern: ALERTING_CASES_SAVED_OBJECT_INDEX, hidden: true, namespaceType: 'multiple-isolated', @@ -146,9 +148,9 @@ export function setupSavedObjects( // Encrypted attributes encryptedSavedObjects.registerType({ - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributesToEncrypt: new Set(['apiKey']), - attributesToExcludeFromAAD: new Set(AlertAttributesExcludedFromAAD), + attributesToExcludeFromAAD: new Set(RuleAttributesExcludedFromAAD), }); // Encrypted attributes diff --git a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts index bf330be87257a3..7ed188915c869c 100644 --- a/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/is_rule_exportable.test.ts @@ -16,6 +16,7 @@ import { isRuleExportable } from './is_rule_exportable'; import { inMemoryMetricsMock } from '../monitoring/in_memory_metrics.mock'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { AlertingConfig } from '../config'; +import { RULE_SAVED_OBJECT_TYPE } from '.'; let ruleTypeRegistryParams: ConstructorOptions; let logger: MockedLogger; @@ -67,7 +68,7 @@ describe('isRuleExportable', () => { isRuleExportable( { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', @@ -127,7 +128,7 @@ describe('isRuleExportable', () => { isRuleExportable( { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', @@ -190,7 +191,7 @@ describe('isRuleExportable', () => { isRuleExportable( { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations/7.16/index.ts b/x-pack/plugins/alerting/server/saved_objects/migrations/7.16/index.ts index bf2870eb613bb6..3984f3e5fb96e9 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations/7.16/index.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations/7.16/index.ts @@ -9,6 +9,7 @@ import { SavedObjectAttribute, SavedObjectReference } from '@kbn/core-saved-obje import { SavedObjectUnsanitizedDoc } from '@kbn/core-saved-objects-server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { isString } from 'lodash/fp'; +import { RULE_SAVED_OBJECT_TYPE } from '../..'; import { RawRule, RawRuleAction } from '../../../types'; import { extractRefsFromGeoContainmentAlert } from '../../geo_containment/migrations'; import { createEsoMigration, isSecuritySolutionLegacyNotification, pipeMigrations } from '../utils'; @@ -126,7 +127,7 @@ function addRuleIdsToLegacyNotificationReferences( } else { const existingReferences = references ?? []; const existingReferenceFound = existingReferences.find((reference) => { - return reference.id === ruleAlertId && reference.type === 'alert'; + return reference.id === ruleAlertId && reference.type === RULE_SAVED_OBJECT_TYPE; }); if (existingReferenceFound) { // skip this if the references already exists for some uncommon reason so we do not add an additional one. @@ -135,7 +136,7 @@ function addRuleIdsToLegacyNotificationReferences( const savedObjectReference: SavedObjectReference = { id: ruleAlertId, name: 'param:alert_0', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }; const newReferences = [...existingReferences, savedObjectReference]; return { ...doc, references: newReferences }; diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts b/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts index 93b8c647f71541..566911f00171d5 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations/index.test.ts @@ -15,6 +15,7 @@ import { migrationMocks } from '@kbn/core/server/mocks'; import { SavedObjectsUtils } from '@kbn/core-saved-objects-utils-server'; import { RuleType, ruleTypeMappings } from '@kbn/securitysolution-rules'; import { isAnyActionSupportIncidents } from './7.11'; +import { RULE_SAVED_OBJECT_TYPE } from '..'; const migrationContext = migrationMocks.createContext(); const encryptedSavedObjectsSetup = encryptedSavedObjectsMock.createSetup(); @@ -1811,7 +1812,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); @@ -1867,7 +1868,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }; @@ -1882,7 +1883,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); @@ -1923,7 +1924,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); @@ -1944,7 +1945,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }; @@ -1959,7 +1960,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); @@ -2002,7 +2003,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }; @@ -2017,7 +2018,7 @@ describe('successful migrations', () => { { name: 'param:alert_0', id: '123', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ], }); @@ -3208,6 +3209,6 @@ function getMockData( references: [], updated_at: withSavedObjectUpdatedAt ? getUpdatedAt() : undefined, id: uuidv4(), - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }; } diff --git a/x-pack/plugins/alerting/server/saved_objects/partially_update_alert.test.ts b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts similarity index 61% rename from x-pack/plugins/alerting/server/saved_objects/partially_update_alert.test.ts rename to x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts index 7560632d12e5af..2cdcd14d2dea5e 100644 --- a/x-pack/plugins/alerting/server/saved_objects/partially_update_alert.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.test.ts @@ -11,14 +11,15 @@ import { SavedObjectsErrorHelpers, } from '@kbn/core/server'; -import { partiallyUpdateAlert, PartiallyUpdateableAlertAttributes } from './partially_update_alert'; +import { partiallyUpdateRule, PartiallyUpdateableRuleAttributes } from './partially_update_rule'; import { savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { RULE_SAVED_OBJECT_TYPE } from '.'; const MockSavedObjectsClientContract = savedObjectsClientMock.create(); const MockISavedObjectsRepository = MockSavedObjectsClientContract as unknown as jest.Mocked; -describe('partially_update_alert', () => { +describe('partially_update_rule', () => { beforeEach(() => { jest.resetAllMocks(); }); @@ -28,52 +29,77 @@ describe('partially_update_alert', () => { test('should work with no options', async () => { soClient.update.mockResolvedValueOnce(MockUpdateValue); - await partiallyUpdateAlert(soClient, MockAlertId, DefaultAttributes); - expect(soClient.update).toHaveBeenCalledWith('alert', MockAlertId, DefaultAttributes, {}); + await partiallyUpdateRule(soClient, MockRuleId, DefaultAttributes); + expect(soClient.update).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + MockRuleId, + DefaultAttributes, + {} + ); }); test('should work with extraneous attributes ', async () => { - const attributes = InvalidAttributes as unknown as PartiallyUpdateableAlertAttributes; + const attributes = InvalidAttributes as unknown as PartiallyUpdateableRuleAttributes; soClient.update.mockResolvedValueOnce(MockUpdateValue); - await partiallyUpdateAlert(soClient, MockAlertId, attributes); - expect(soClient.update).toHaveBeenCalledWith('alert', MockAlertId, DefaultAttributes, {}); + await partiallyUpdateRule(soClient, MockRuleId, attributes); + expect(soClient.update).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + MockRuleId, + DefaultAttributes, + {} + ); }); test('should handle SO errors', async () => { soClient.update.mockRejectedValueOnce(new Error('wops')); await expect( - partiallyUpdateAlert(soClient, MockAlertId, DefaultAttributes) + partiallyUpdateRule(soClient, MockRuleId, DefaultAttributes) ).rejects.toThrowError('wops'); }); test('should handle the version option', async () => { soClient.update.mockResolvedValueOnce(MockUpdateValue); - await partiallyUpdateAlert(soClient, MockAlertId, DefaultAttributes, { version: '1.2.3' }); - expect(soClient.update).toHaveBeenCalledWith('alert', MockAlertId, DefaultAttributes, { - version: '1.2.3', - }); + await partiallyUpdateRule(soClient, MockRuleId, DefaultAttributes, { version: '1.2.3' }); + expect(soClient.update).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + MockRuleId, + DefaultAttributes, + { + version: '1.2.3', + } + ); }); test('should handle the ignore404 option', async () => { const err = SavedObjectsErrorHelpers.createGenericNotFoundError(); soClient.update.mockRejectedValueOnce(err); - await partiallyUpdateAlert(soClient, MockAlertId, DefaultAttributes, { ignore404: true }); - expect(soClient.update).toHaveBeenCalledWith('alert', MockAlertId, DefaultAttributes, {}); + await partiallyUpdateRule(soClient, MockRuleId, DefaultAttributes, { ignore404: true }); + expect(soClient.update).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + MockRuleId, + DefaultAttributes, + {} + ); }); test('should handle the namespace option', async () => { soClient.update.mockResolvedValueOnce(MockUpdateValue); - await partiallyUpdateAlert(soClient, MockAlertId, DefaultAttributes, { - namespace: 'bat.cave', - }); - expect(soClient.update).toHaveBeenCalledWith('alert', MockAlertId, DefaultAttributes, { + await partiallyUpdateRule(soClient, MockRuleId, DefaultAttributes, { namespace: 'bat.cave', }); + expect(soClient.update).toHaveBeenCalledWith( + RULE_SAVED_OBJECT_TYPE, + MockRuleId, + DefaultAttributes, + { + namespace: 'bat.cave', + } + ); }); }); }); @@ -100,11 +126,11 @@ const DefaultAttributes = { const InvalidAttributes = { ...DefaultAttributes, foo: 'bar' }; -const MockAlertId = 'alert-id'; +const MockRuleId = 'rule-id'; const MockUpdateValue = { - id: MockAlertId, - type: 'alert', + id: MockRuleId, + type: RULE_SAVED_OBJECT_TYPE, attributes: { actions: [], scheduledTaskId: 'scheduled-task-id', diff --git a/x-pack/plugins/alerting/server/saved_objects/partially_update_alert.ts b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts similarity index 63% rename from x-pack/plugins/alerting/server/saved_objects/partially_update_alert.ts rename to x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts index 2c275a5f602fc8..8d79fe300c7e9f 100644 --- a/x-pack/plugins/alerting/server/saved_objects/partially_update_alert.ts +++ b/x-pack/plugins/alerting/server/saved_objects/partially_update_rule.ts @@ -13,13 +13,17 @@ import { } from '@kbn/core/server'; import { RawRule } from '../types'; -import { AlertAttributesExcludedFromAAD, AlertAttributesExcludedFromAADType } from '.'; +import { + RuleAttributesExcludedFromAAD, + RuleAttributesExcludedFromAADType, + RULE_SAVED_OBJECT_TYPE, +} from '.'; -export type PartiallyUpdateableAlertAttributes = Partial< - Pick +export type PartiallyUpdateableRuleAttributes = Partial< + Pick >; -export interface PartiallyUpdateAlertSavedObjectOptions { +interface PartiallyUpdateRuleSavedObjectOptions { refresh?: SavedObjectsUpdateOptions['refresh']; version?: string; ignore404?: boolean; @@ -29,16 +33,16 @@ export interface PartiallyUpdateAlertSavedObjectOptions { // typed this way so we can send a SavedObjectClient or SavedObjectRepository type SavedObjectClientForUpdate = Pick; -// direct, partial update to an alert saved object via scoped SavedObjectsClient +// direct, partial update to a rule saved object via scoped SavedObjectsClient // using namespace set in the client -export async function partiallyUpdateAlert( +export async function partiallyUpdateRule( savedObjectsClient: SavedObjectClientForUpdate, id: string, - attributes: PartiallyUpdateableAlertAttributes, - options: PartiallyUpdateAlertSavedObjectOptions = {} + attributes: PartiallyUpdateableRuleAttributes, + options: PartiallyUpdateRuleSavedObjectOptions = {} ): Promise { // ensure we only have the valid attributes excluded from AAD - const attributeUpdates = pick(attributes, AlertAttributesExcludedFromAAD); + const attributeUpdates = pick(attributes, RuleAttributesExcludedFromAAD); const updateOptions: SavedObjectsUpdateOptions = pick( options, 'namespace', @@ -47,7 +51,12 @@ export async function partiallyUpdateAlert( ); try { - await savedObjectsClient.update('alert', id, attributeUpdates, updateOptions); + await savedObjectsClient.update( + RULE_SAVED_OBJECT_TYPE, + id, + attributeUpdates, + updateOptions + ); } catch (err) { if (options?.ignore404 && SavedObjectsErrorHelpers.isNotFoundError(err)) { return; diff --git a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts index 1269a9a7763079..7b11ab75f868db 100644 --- a/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts +++ b/x-pack/plugins/alerting/server/saved_objects/transform_rule_for_export.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '.'; import { transformRulesForExport } from './transform_rule_for_export'; jest.mock('../lib/rule_execution_status', () => ({ getRuleExecutionStatusPendingAttributes: () => ({ @@ -18,7 +19,7 @@ describe('transform rule for export', () => { const mockRules = [ { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: true, name: 'rule-name', @@ -51,7 +52,7 @@ describe('transform rule for export', () => { }, { id: '2', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, attributes: { enabled: false, name: 'disabled-rule', diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts index 2fbb7132e0a6f0..c08fb5490fbb93 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.test.ts @@ -36,6 +36,7 @@ import { mockAAD } from './fixtures'; import { schema } from '@kbn/config-schema'; import { alertsClientMock } from '../alerts_client/alerts_client.mock'; import { ExecutionResponseType } from '@kbn/actions-plugin/server/create_execute_function'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; jest.mock('./inject_action_params', () => ({ injectActionParams: jest.fn(), @@ -359,13 +360,13 @@ describe('Execution Handler', () => { }, source: asSavedObjectExecutionSource({ id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }), relatedSavedObjects: [ { id: '1', namespace: 'test1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: 'test', }, ], @@ -1683,8 +1684,10 @@ describe('Execution Handler', () => { executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', id: '1', params: {}, - relatedSavedObjects: [{ id: '1', namespace: 'test1', type: 'alert', typeId: 'test' }], - source: { source: { id: '1', type: 'alert' }, type: 'SAVED_OBJECT' }, + relatedSavedObjects: [ + { id: '1', namespace: 'test1', type: RULE_SAVED_OBJECT_TYPE, typeId: 'test' }, + ], + source: { source: { id: '1', type: RULE_SAVED_OBJECT_TYPE }, type: 'SAVED_OBJECT' }, spaceId: 'test1', }, ]); diff --git a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts index e5fbe92238a0c0..29f56b630eaf80 100644 --- a/x-pack/plugins/alerting/server/task_runner/execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/execution_handler.ts @@ -51,6 +51,7 @@ import { isSummaryActionOnInterval, isSummaryActionThrottled, } from './rule_action_helper'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; enum Reasons { MUTED = 'muted', @@ -554,13 +555,13 @@ export class ExecutionHandler< consumer: ruleConsumer, source: asSavedObjectExecutionSource({ id: ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }), executionId, relatedSavedObjects: [ { id: ruleId, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, namespace: namespace.namespace, typeId: this.ruleType.id, }, diff --git a/x-pack/plugins/alerting/server/task_runner/fixtures.ts b/x-pack/plugins/alerting/server/task_runner/fixtures.ts index c1c4b442de13ed..b975f213040133 100644 --- a/x-pack/plugins/alerting/server/task_runner/fixtures.ts +++ b/x-pack/plugins/alerting/server/task_runner/fixtures.ts @@ -20,6 +20,7 @@ import { getDefaultMonitoring } from '../lib/monitoring'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { EVENT_LOG_ACTIONS } from '../plugin'; import { RawRule } from '../types'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; interface GeneratorParams { [key: string]: string | number | boolean | undefined | object[] | boolean[] | object; @@ -81,7 +82,7 @@ export const generateSavedObjectParams = ({ history?: RuleMonitoring['run']['history']; alertsCount?: Record; }) => [ - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { monitoring: { @@ -213,7 +214,7 @@ export const mockedRuleTypeSavedObject: Rule = { export const mockedRawRuleSO: SavedObject = { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, references: [], attributes: { legacyId: '1', @@ -419,14 +420,14 @@ export const generateEnqueueFunctionInput = ({ { id: '1', namespace: undefined, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, typeId: RULE_TYPE_ID, }, ], source: { source: { id: '1', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, type: 'SAVED_OBJECT', }, 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 5371e56ff07b23..380d436c95e652 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 @@ -18,6 +18,7 @@ import { MONITORING_HISTORY_LIMIT, RuleExecutionStatusErrorReasons } from '../.. import { ErrorWithReason, getReasonFromError } from '../lib/error_with_reason'; import { alertingEventLoggerMock } from '../lib/alerting_event_logger/alerting_event_logger.mock'; import { mockedRawRuleSO, mockedRule } from './fixtures'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; // create mocks const rulesClient = rulesClientMock.create(); @@ -199,7 +200,7 @@ describe('rule_loader', () => { expect(contextMock.spaceIdToNamespace.mock.calls[0]).toEqual(['default']); const esoArgs = encryptedSavedObjects.getDecryptedAsInternalUser.mock.calls[0]; - expect(esoArgs).toEqual(['alert', ruleId, { namespace: undefined }]); + expect(esoArgs).toEqual([RULE_SAVED_OBJECT_TYPE, ruleId, { namespace: undefined }]); }); test('succeeds with non-default space', async () => { @@ -218,7 +219,7 @@ describe('rule_loader', () => { }); const esoArgs = encryptedSavedObjects.getDecryptedAsInternalUser.mock.calls[0]; - expect(esoArgs).toEqual(['alert', ruleId, { namespace: spaceId }]); + expect(esoArgs).toEqual([RULE_SAVED_OBJECT_TYPE, ruleId, { namespace: spaceId }]); }); test('fails', async () => { diff --git a/x-pack/plugins/alerting/server/task_runner/rule_loader.ts b/x-pack/plugins/alerting/server/task_runner/rule_loader.ts index f6bb71aef74532..fb037b802ec9b2 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_loader.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_loader.ts @@ -24,6 +24,7 @@ import { } from '../types'; import { MONITORING_HISTORY_LIMIT, RuleTypeParams } from '../../common'; import { AlertingEventLogger } from '../lib/alerting_event_logger/alerting_event_logger'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; export interface RuleData extends LoadedIndirectParams { indirectParams: RawRule; @@ -114,7 +115,7 @@ export async function getRuleAttributes( const namespace = context.spaceIdToNamespace(spaceId); const rawRule = await context.encryptedSavedObjectsClient.getDecryptedAsInternalUser( - 'alert', + RULE_SAVED_OBJECT_TYPE, ruleId, { namespace } ); diff --git a/x-pack/plugins/alerting/server/task_runner/running_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/running_handler.test.ts index ce3a3c6680e7b0..3ebb122b3a19a6 100644 --- a/x-pack/plugins/alerting/server/task_runner/running_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/running_handler.test.ts @@ -6,11 +6,11 @@ */ import { ISavedObjectsRepository, Logger } from '@kbn/core/server'; -import { partiallyUpdateAlert } from '../saved_objects/partially_update_alert'; +import { partiallyUpdateRule } from '../saved_objects/partially_update_rule'; import { RunningHandler } from './running_handler'; -jest.mock('../saved_objects/partially_update_alert', () => ({ - partiallyUpdateAlert: jest.fn(), +jest.mock('../saved_objects/partially_update_rule', () => ({ + partiallyUpdateRule: jest.fn(), })); describe('isRunning handler', () => { @@ -20,7 +20,7 @@ describe('isRunning handler', () => { } as unknown as Logger; const ruleTypeId = 'myType'; beforeEach(() => { - (partiallyUpdateAlert as jest.Mock).mockClear(); + (partiallyUpdateRule as jest.Mock).mockClear(); (logger.error as jest.Mock).mockClear(); jest.useFakeTimers(); }); @@ -29,23 +29,23 @@ describe('isRunning handler', () => { }); test('Should resolve if nothing got started', async () => { - (partiallyUpdateAlert as jest.Mock).mockImplementation(() => Promise.resolve('resolve')); + (partiallyUpdateRule as jest.Mock).mockImplementation(() => Promise.resolve('resolve')); const runHandler = new RunningHandler(soClient, logger, ruleTypeId); const resp = await runHandler.waitFor(); - expect(partiallyUpdateAlert).toHaveBeenCalledTimes(0); + expect(partiallyUpdateRule).toHaveBeenCalledTimes(0); expect(logger.error).toHaveBeenCalledTimes(0); expect(resp).toBe(undefined); }); - test('Should return the promise from partiallyUpdateAlert when the update isRunning has been a success', async () => { - (partiallyUpdateAlert as jest.Mock).mockImplementation(() => Promise.resolve('resolve')); + test('Should return the promise from partiallyUpdateRule when the update isRunning has been a success', async () => { + (partiallyUpdateRule as jest.Mock).mockImplementation(() => Promise.resolve('resolve')); const runHandler = new RunningHandler(soClient, logger, ruleTypeId); runHandler.start('9876543210'); jest.runAllTimers(); const resp = await runHandler.waitFor(); - expect(partiallyUpdateAlert).toHaveBeenCalledTimes(1); - expect((partiallyUpdateAlert as jest.Mock).mock.calls[0]).toMatchInlineSnapshot(` + expect(partiallyUpdateRule).toHaveBeenCalledTimes(1); + expect((partiallyUpdateRule as jest.Mock).mock.calls[0]).toMatchInlineSnapshot(` Array [ [MockFunction], "9876543210", @@ -64,15 +64,13 @@ describe('isRunning handler', () => { }); test('Should reject when the update isRunning has been a failure', async () => { - (partiallyUpdateAlert as jest.Mock).mockImplementation(() => - Promise.reject(new Error('error')) - ); + (partiallyUpdateRule as jest.Mock).mockImplementation(() => Promise.reject(new Error('error'))); const runHandler = new RunningHandler(soClient, logger, ruleTypeId); runHandler.start('9876543210'); jest.runAllTimers(); await expect(runHandler.waitFor()).rejects.toThrow(); - expect(partiallyUpdateAlert).toHaveBeenCalledTimes(1); + expect(partiallyUpdateRule).toHaveBeenCalledTimes(1); expect(logger.error).toHaveBeenCalledTimes(1); }); }); diff --git a/x-pack/plugins/alerting/server/task_runner/running_handler.ts b/x-pack/plugins/alerting/server/task_runner/running_handler.ts index 118f13ab6eed96..1602e9421ecef5 100644 --- a/x-pack/plugins/alerting/server/task_runner/running_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/running_handler.ts @@ -6,7 +6,7 @@ */ import { ISavedObjectsRepository, Logger } from '@kbn/core/server'; -import { partiallyUpdateAlert } from '../saved_objects/partially_update_alert'; +import { partiallyUpdateRule } from '../saved_objects/partially_update_rule'; const TIME_TO_WAIT = 2000; @@ -45,7 +45,7 @@ export class RunningHandler { private setRunning(ruleId: string, namespace?: string) { this.isUpdating = true; - this.runningPromise = partiallyUpdateAlert( + this.runningPromise = partiallyUpdateRule( this.client, ruleId, { running: true }, 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 ee55378d087953..23d5d5f576ce3e 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 @@ -82,6 +82,7 @@ import { alertsServiceMock } from '../alerts_service/alerts_service.mock'; import { getMockMaintenanceWindow } from '../data/maintenance_window/test_helpers'; import { alertsClientMock } from '../alerts_client/alerts_client.mock'; import { MaintenanceWindow } from '../application/maintenance_window/types'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; jest.mock('uuid', () => ({ v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -2101,7 +2102,10 @@ describe('Task Runner', () => { test('reschedules for smaller interval if es connectivity error encountered and schedule interval is greater than connectivity retry', async () => { rulesClient.getAlertFromRaw.mockImplementation(() => { - throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError('alert', '1'); + throw SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError( + RULE_SAVED_OBJECT_TYPE, + '1' + ); }); const taskRunner = new TaskRunner({ 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 4a1245f29ee828..532dd7b1e12ba1 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -43,7 +43,7 @@ import { import { asErr, asOk, isErr, isOk, map, resolveErr, Result } from '../lib/result_type'; import { taskInstanceToAlertTaskInstance } from './alert_task_instance'; import { isAlertSavedObjectNotFoundError, isEsUnavailableError } from '../lib/is_alerting_error'; -import { partiallyUpdateAlert } from '../saved_objects'; +import { partiallyUpdateRule, RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; import { AlertInstanceContext, AlertInstanceState, @@ -221,7 +221,7 @@ export class TaskRunner< // eslint-disable-next-line no-empty } catch {} try { - await partiallyUpdateAlert( + await partiallyUpdateRule( client, ruleId, { ...attributes, running: false }, @@ -473,7 +473,7 @@ export class TaskRunner< }; const savedObjectsClient = this.context.savedObjects.getScopedClient(fakeRequest, { - includedHiddenTypes: ['alert', 'action'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE, 'action'], }); const dataViews = await this.context.dataViews.dataViewsServiceFactory( 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 46783154a6a4ad..0ce2f758ade399 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 @@ -58,6 +58,7 @@ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { rulesSettingsClientMock } from '../rules_settings_client.mock'; import { maintenanceWindowClientMock } from '../maintenance_window_client.mock'; import { alertsServiceMock } from '../alerts_service/alerts_service.mock'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; jest.mock('uuid', () => ({ v4: () => '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -222,7 +223,7 @@ describe('Task Runner Cancel', () => { expect( taskRunnerFactoryInitializerParams.internalSavedObjectsRepository.update ).toHaveBeenCalledWith( - 'alert', + RULE_SAVED_OBJECT_TYPE, '1', { executionStatus: { diff --git a/x-pack/plugins/alerting/server/usage/task.ts b/x-pack/plugins/alerting/server/usage/task.ts index e7008056677d09..507970d436d6f2 100644 --- a/x-pack/plugins/alerting/server/usage/task.ts +++ b/x-pack/plugins/alerting/server/usage/task.ts @@ -20,6 +20,7 @@ import { getExecutionTimeoutsPerDayCount, } from './lib/get_telemetry_from_event_log'; import { stateSchemaByVersion, emptyState, type LatestTaskStateSchema } from './task_state'; +import { RULE_SAVED_OBJECT_TYPE } from '../saved_objects'; export const TELEMETRY_TASK_TYPE = 'alerting_telemetry'; @@ -90,7 +91,7 @@ export function telemetryTaskRunner( const getAlertIndex = () => core .getStartServices() - .then(([coreStart]) => coreStart.savedObjects.getIndexForType('alert')); + .then(([coreStart]) => coreStart.savedObjects.getIndexForType(RULE_SAVED_OBJECT_TYPE)); return { async run() { diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts index bc7e7d331ccebf..731149159b6813 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_groups/service_groups.cy.ts @@ -82,7 +82,7 @@ describe('Service groups', () => { it('creates a service group', () => { cy.getByTestSubj('apmCreateServiceGroupButton').click(); - cy.getByTestSubj('apmGroupNameInput').type('go services'); + cy.getByTestSubj('apmGroupNameInput').type('go services{enter}'); cy.contains('Select services').click(); cy.getByTestSubj('headerFilterKuerybar').type('agent.name:"go"{enter}'); cy.contains('synth-go-1'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts index 0bce81a620a510..19c07645fb37f2 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/alerts_table.cy.ts @@ -38,7 +38,9 @@ describe('Errors table', () => { it('Alerts table with the search bar is populated', () => { cy.visitKibana(serviceOverviewHref); cy.contains('opbeans-java'); - cy.contains('All'); + cy.get( + '[data-test-subj="environmentFilter"] [data-test-subj="comboBoxSearchInput"]' + ).should('have.value', 'All'); cy.contains('Active'); cy.contains('Recovered'); cy.getByTestSubj('globalQueryBar').should('exist'); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts index 35184a59880d74..7508612d0acc5f 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts @@ -226,9 +226,9 @@ describe('Service Overview', () => { 'suggestionsRequest' ); - cy.getByTestSubj('environmentFilter').find('input').type('production', { - force: true, - }); + cy.getByTestSubj('environmentFilter') + .find('input') + .type('{selectall}production', { force: true }); cy.expectAPIsToHaveBeenCalledWith({ apisIntercepted: ['@suggestionsRequest'], diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts index e0ca47df79996f..1d9d34d7b9a2d4 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts @@ -107,7 +107,10 @@ describe('Agent configuration', () => { cy.contains('Create configuration'); cy.contains('Edit').click(); cy.wait('@serviceEnvironmentApi'); - cy.contains('production'); + cy.getByTestSubj('serviceEnviromentComboBox') + .find('input') + .invoke('val') + .should('contain', 'production'); }); it('displays All label when selecting all option', () => { cy.intercept( @@ -129,6 +132,9 @@ describe('Agent configuration', () => { cy.contains('Environment All'); cy.contains('Edit').click(); cy.wait('@serviceEnvironmentApi'); - cy.contains('All'); + cy.getByTestSubj('serviceEnviromentComboBox') + .find('input') + .invoke('val') + .should('contain', 'All'); }); }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts index bfa0aaa79d987a..11025b29dd0e7d 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/storage_explorer/storage_explorer.cy.ts @@ -130,7 +130,7 @@ describe('Storage Explorer', () => { it('with the correct environment when changing the environment', () => { cy.wait(mainAliasNames); - cy.getByTestSubj('environmentFilter').type('production'); + cy.getByTestSubj('environmentFilter').type('{selectall}production'); cy.contains('button', 'production').click({ force: true }); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_stacktrace_data.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_stacktrace_data.ts new file mode 100644 index 00000000000000..85eeb2cd456efb --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/generate_span_stacktrace_data.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 { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { synthtrace } from '../../../synthtrace'; + +function getAPMGeneratedStacktrace() { + const apmGeneratedStacktrace = apm + .service({ + name: 'apm-generated', + environment: 'production', + agentName: 'java', + }) + .instance('instance a'); + + return Array.from( + timerange( + new Date('2022-01-01T00:00:00.000Z'), + new Date('2022-01-01T00:01:00.000Z') + ) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return apmGeneratedStacktrace + .transaction({ transactionName: `Transaction A` }) + .defaults({ + 'service.language.name': 'java', + }) + .timestamp(timestamp) + .duration(1000) + .success() + .children( + apmGeneratedStacktrace + .span({ + spanName: `Span A`, + spanType: 'internal', + 'span.stacktrace': [ + { + library_frame: false, + exclude_from_grouping: false, + filename: 'OutputBuffer.java', + classname: 'org.apache.catalina.connector.OutputBuffer', + line: { number: 825 }, + module: 'org.apache.catalina.connector', + function: 'flushByteBuffer', + }, + ], + }) + .timestamp(timestamp + 50) + .duration(100) + .failure() + ); + }) + ); +} + +function getOtelGeneratedStacktrace() { + const apmGeneratedStacktrace = apm + .service({ + name: 'otel-generated', + environment: 'production', + agentName: 'java', + }) + .instance('instance a'); + + return Array.from( + timerange( + new Date('2022-01-01T00:00:00.000Z'), + new Date('2022-01-01T00:01:00.000Z') + ) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return apmGeneratedStacktrace + .transaction({ transactionName: `Transaction A` }) + .timestamp(timestamp) + .duration(1000) + .defaults({ + 'service.language.name': 'java', + }) + .success() + .children( + apmGeneratedStacktrace + .span({ + spanName: `Span A`, + spanType: 'internal', + 'code.stacktrace': + 'java.lang.Throwable\n\tat co.elastic.otel.ElasticSpanProcessor.captureStackTrace(ElasticSpanProcessor.java:81)', + }) + .timestamp(timestamp + 50) + .duration(100) + .failure() + ); + }) + ); +} + +export function generateSpanStacktraceData() { + const apmGeneratedStacktrace = getAPMGeneratedStacktrace(); + const otelGeneratedStacktrace = getOtelGeneratedStacktrace(); + + synthtrace.index([...apmGeneratedStacktrace, ...otelGeneratedStacktrace]); +} diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_stacktrace.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_stacktrace.cy.ts new file mode 100644 index 00000000000000..dbc4a1072ffa01 --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/transaction_details/span_stacktrace.cy.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 url from 'url'; +import { synthtrace } from '../../../synthtrace'; +import { generateSpanStacktraceData } from './generate_span_stacktrace_data'; + +const start = '2022-01-01T00:00:00.000Z'; +const end = '2022-01-01T00:15:00.000Z'; + +function getServiceInventoryUrl({ serviceName }: { serviceName: string }) { + return url.format({ + pathname: `/app/apm/services/${serviceName}`, + query: { + rangeFrom: start, + rangeTo: end, + environment: 'ENVIRONMENT_ALL', + kuery: '', + serviceGroup: '', + transactionType: 'request', + comparisonEnabled: true, + offset: '1d', + }, + }); +} + +describe('Span stacktrace', () => { + beforeEach(() => { + cy.loginAsViewerUser(); + }); + describe('span flyout', () => { + before(() => { + generateSpanStacktraceData(); + }); + + after(() => { + synthtrace.clean(); + }); + it('Shows APM agent generated stacktrace', () => { + cy.visitKibana(getServiceInventoryUrl({ serviceName: 'apm-generated' })); + cy.contains('Transaction A').click(); + cy.contains('Span A').click(); + cy.getByTestSubj('spanStacktraceTab').click(); + cy.contains( + 'at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:825)' + ); + }); + + it('Shows Otel generated stacktrace', () => { + cy.visitKibana(getServiceInventoryUrl({ serviceName: 'otel-generated' })); + cy.contains('Transaction A').click(); + cy.contains('Span A').click(); + cy.getByTestSubj('spanStacktraceTab').click(); + cy.contains( + `java.lang.Throwable at co.elastic.otel.ElasticSpanProcessor.captureStackTrace(ElasticSpanProcessor.java:81)` + ); + }); + }); +}); diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts index da8b1d418f3a62..f4341fe938092c 100644 --- a/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/apm/ftr_e2e/cypress/support/commands.ts @@ -94,14 +94,16 @@ Cypress.Commands.add( .nextAll() .find('[data-test-subj="superDatePickerAbsoluteDateInput"]') .clear({ force: true }) - .type(moment(start).format(format), { force: true }); + .type(moment(start).format(format), { force: true }) + .type('{enter}'); cy.getByTestSubj('superDatePickerendDatePopoverButton').click(); cy.contains('End date') .nextAll() .find('[data-test-subj="superDatePickerAbsoluteDateInput"]') .clear({ force: true }) - .type(moment(end).format(format), { force: true }); + .type(moment(end).format(format), { force: true }) + .type('{enter}'); } ); diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx index 59b06577b2757d..f32bd7be896d21 100644 --- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/waterfall/span_flyout/index.tsx @@ -25,6 +25,7 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { isEmpty } from 'lodash'; import React, { Fragment } from 'react'; +import { PlaintextStacktrace } from '../../../../../error_group_details/error_sampler/plaintext_stacktrace'; import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { useFetcher, isPending } from '../../../../../../../hooks/use_fetcher'; @@ -204,6 +205,7 @@ function SpanFlyoutBody({ flyoutDetailTab?: string; }) { const stackframes = span.span.stacktrace; + const plaintextStacktrace = span.code?.stacktrace; const codeLanguage = parentTransaction?.service.language?.name; const spanDb = span.span.db; const spanTypes = getSpanTypes(span); @@ -232,10 +234,11 @@ function SpanFlyoutBody({ ), }, - ...(!isEmpty(stackframes) + ...(!isEmpty(stackframes) || !isEmpty(plaintextStacktrace) ? [ { id: 'stack-trace', + 'data-test-subj': 'spanStacktraceTab', name: i18n.translate( 'xpack.apm.transactionDetails.spanFlyout.stackTraceTabLabel', { @@ -245,10 +248,17 @@ function SpanFlyoutBody({ content: ( - + {stackframes ? ( + + ) : ( + + )} ), }, diff --git a/x-pack/plugins/apm/public/components/shared/stacktrace/index.tsx b/x-pack/plugins/apm/public/components/shared/stacktrace/index.tsx index 4a3646dbb78c1c..379dd5700406ee 100644 --- a/x-pack/plugins/apm/public/components/shared/stacktrace/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/stacktrace/index.tsx @@ -17,6 +17,7 @@ import { Stackframe as StackframeComponent } from './stackframe'; interface Props { stackframes?: Stackframe[]; codeLanguage?: string; + stackTrace?: string; } export function Stacktrace({ stackframes = [], codeLanguage }: Props) { diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap index 17f22a43a1c43c..02ed85e387ecb5 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/__snapshots__/transaction_action_menu.test.tsx.snap @@ -3,32 +3,28 @@ exports[`TransactionActionMenu component matches the snapshot 1`] = `
-
- -
+ + +
`; diff --git a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx index 20e3d2ad0c948c..764f2a11c02cce 100644 --- a/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/transaction_action_menu/transaction_action_menu.test.tsx @@ -419,9 +419,9 @@ describe('TransactionActionMenu component', () => { component .getByTestId(`${key}.value`) .querySelector( - '[data-test-subj="comboBoxInput"] span' - ) as HTMLSpanElement - ).textContent, + '[data-test-subj="comboBoxSearchInput"]' + ) as HTMLInputElement + ).value, }; }; expect(getFilterKeyValue('service.name')).toEqual({ diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx index edae01e0b60439..8ef39fcbc8c734 100644 --- a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx +++ b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, within } from '@testing-library/react'; import { HttpStart } from '@kbn/core/public'; import React from 'react'; import { @@ -80,9 +80,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_onPrem' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + let commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -128,12 +136,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); - expect( - component.getByTestId('policySelector_onPrem') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_onPrem' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -164,12 +177,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); - expect( - component.getByTestId('policySelector_onPrem') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_onPrem' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -206,12 +224,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); - expect( - component.getByTestId('policySelector_cloud') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_cloud' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -245,12 +268,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Elastic Cloud agent policy') - ).toBeInTheDocument(); - expect( - component.getByTestId('policySelector_policy-elastic-agent-on-cloud') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_policy-elastic-agent-on-cloud' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Elastic Cloud agent policy'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -280,9 +308,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_onPrem' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -340,12 +376,17 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); - expect( - component.getByTestId('policySelector_onPrem') - ).toBeInTheDocument(); + + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_onPrem' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` @@ -379,10 +420,16 @@ describe('TutorialConfigAgent', () => { kibanaVersion="8.0.0" /> ); - expect( - await screen.findByText('Default Standalone configuration') - ).toBeInTheDocument(); - expect(component.getByTestId('policySelector_cloud')).toBeInTheDocument(); + const policySelectorWrapper = await screen.findByTestId( + 'policySelector_cloud' + ); + expect(policySelectorWrapper).toBeInTheDocument(); + + const input = within(policySelectorWrapper).getByTestId( + 'comboBoxSearchInput' + ); + expect(input).toHaveValue('Default Standalone configuration'); + const commands = component.getByTestId('commands').innerHTML; expect(commands).not.toEqual(''); expect(commands).toMatchInlineSnapshot(` diff --git a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts index befd25abb22f20..4968ceba47e68e 100644 --- a/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts +++ b/x-pack/plugins/apm/server/routes/historical_data/has_historical_agent_data.ts @@ -8,10 +8,29 @@ import { ProcessorEvent } from '@kbn/observability-plugin/common'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; -// Note: this logic is duplicated in tutorials/apm/envs/on_prem export async function hasHistoricalAgentData(apmEventClient: APMEventClient) { + const hasDataInWarmOrHotDataTiers = await hasDataRequest(apmEventClient, [ + 'data_hot', + 'data_warm', + ]); + + if (hasDataInWarmOrHotDataTiers) { + return true; + } + + const hasDataUnbounded = await hasDataRequest(apmEventClient); + + return hasDataUnbounded; +} + +type DataTier = 'data_hot' | 'data_warm' | 'data_cold' | 'data_frozen'; +async function hasDataRequest( + apmEventClient: APMEventClient, + dataTiers?: DataTier[] +) { + const query = dataTiers ? { terms: { _tier: dataTiers } } : undefined; + const params = { - terminate_after: 1, apm: { events: [ ProcessorEvent.error, @@ -20,8 +39,10 @@ export async function hasHistoricalAgentData(apmEventClient: APMEventClient) { ], }, body: { + terminate_after: 1, track_total_hits: 1, size: 0, + query, }, }; diff --git a/x-pack/plugins/apm/server/routes/services/__snapshots__/queries.test.ts.snap b/x-pack/plugins/apm/server/routes/services/__snapshots__/queries.test.ts.snap deleted file mode 100644 index 03c3f038ad311a..00000000000000 --- a/x-pack/plugins/apm/server/routes/services/__snapshots__/queries.test.ts.snap +++ /dev/null @@ -1,313 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`services queries fetches the agent status 1`] = ` -Object { - "apm": Object { - "events": Array [ - "error", - "metric", - "transaction", - ], - }, - "body": Object { - "size": 0, - "track_total_hits": 1, - }, - "terminate_after": 1, -} -`; - -exports[`services queries fetches the service agent name 1`] = ` -Object { - "apm": Object { - "events": Array [ - "error", - "transaction", - "metric", - ], - }, - "body": Object { - "_source": Array [ - "agent.name", - "service.runtime.name", - "cloud.provider", - "cloud.service.name", - ], - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "term": Object { - "service.name": "foo", - }, - }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 0, - "lte": 50000, - }, - }, - }, - Object { - "exists": Object { - "field": "agent.name", - }, - }, - ], - "should": Array [ - Object { - "exists": Object { - "field": "service.runtime.name", - }, - }, - Object { - "exists": Object { - "field": "cloud.provider", - }, - }, - Object { - "exists": Object { - "field": "cloud.service.name", - }, - }, - ], - }, - }, - "size": 1, - "sort": Object { - "_score": Object { - "order": "desc", - }, - }, - "track_total_hits": 1, - }, - "terminate_after": 1, -} -`; - -exports[`services queries fetches the service items 1`] = ` -Array [ - Object { - "apm": Object { - "sources": Array [ - Object { - "documentType": "transactionEvent", - "rollupInterval": "none", - }, - ], - }, - "body": Object { - "aggs": Object { - "sample": Object { - "aggs": Object { - "overflowCount": Object { - "sum": Object { - "field": "service_transaction.aggregation.overflow_count", - }, - }, - "services": Object { - "aggs": Object { - "transactionType": Object { - "aggs": Object { - "avg_duration": Object { - "avg": Object { - "field": "transaction.duration.us", - }, - }, - "environments": Object { - "terms": Object { - "field": "service.environment", - }, - }, - "sample": Object { - "top_metrics": Object { - "metrics": Array [ - Object { - "field": "agent.name", - }, - ], - "sort": Object { - "@timestamp": "desc", - }, - }, - }, - "successful": Object { - "filter": Object { - "bool": Object { - "filter": Array [ - Object { - "terms": Object { - "event.outcome": Array [ - "success", - ], - }, - }, - ], - }, - }, - }, - "successful_or_failed": Object { - "filter": Object { - "bool": Object { - "filter": Array [ - Object { - "terms": Object { - "event.outcome": Array [ - "failure", - "success", - ], - }, - }, - ], - }, - }, - }, - }, - "terms": Object { - "field": "transaction.type", - }, - }, - }, - "terms": Object { - "field": "service.name", - "size": 1000, - }, - }, - }, - "random_sampler": Object { - "probability": 1, - "seed": 0, - }, - }, - }, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 0, - "lte": 50000, - }, - }, - }, - ], - }, - }, - "size": 0, - "track_total_hits": false, - }, - }, - Object { - "apm": Object { - "events": Array [ - "metric", - "error", - ], - }, - "body": Object { - "aggs": Object { - "sample": Object { - "aggs": Object { - "services": Object { - "aggs": Object { - "environments": Object { - "terms": Object { - "field": "service.environment", - }, - }, - "latest": Object { - "top_metrics": Object { - "metrics": Array [ - Object { - "field": "agent.name", - }, - ], - "sort": Object { - "@timestamp": "desc", - }, - }, - }, - }, - "terms": Object { - "field": "service.name", - "size": 1000, - }, - }, - }, - "random_sampler": Object { - "probability": 1, - "seed": 0, - }, - }, - }, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 0, - "lte": 50000, - }, - }, - }, - ], - }, - }, - "size": 0, - "track_total_hits": false, - }, - }, - undefined, -] -`; - -exports[`services queries fetches the service transaction types 1`] = ` -Object { - "apm": Object { - "sources": Array [ - Object { - "documentType": "transactionMetric", - "rollupInterval": "1m", - }, - ], - }, - "body": Object { - "aggs": Object { - "types": Object { - "terms": Object { - "field": "transaction.type", - "size": 100, - }, - }, - }, - "query": Object { - "bool": Object { - "filter": Array [ - Object { - "term": Object { - "service.name": "foo", - }, - }, - Object { - "range": Object { - "@timestamp": Object { - "format": "epoch_millis", - "gte": 0, - "lte": 50000, - }, - }, - }, - ], - }, - }, - "size": 0, - "track_total_hits": false, - }, -} -`; diff --git a/x-pack/plugins/apm/server/routes/services/queries.test.ts b/x-pack/plugins/apm/server/routes/services/queries.test.ts deleted file mode 100644 index 7d45899aa84c0e..00000000000000 --- a/x-pack/plugins/apm/server/routes/services/queries.test.ts +++ /dev/null @@ -1,90 +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 { ApmDocumentType } from '../../../common/document_type'; -import { ENVIRONMENT_ALL } from '../../../common/environment_filter_values'; -import { RollupInterval } from '../../../common/rollup'; -import { - inspectSearchParams, - SearchParamsMock, -} from '../../utils/test_helpers'; -import { hasHistoricalAgentData } from '../historical_data/has_historical_agent_data'; -import { getServicesItems } from './get_services/get_services_items'; -import { getServiceAgent } from './get_service_agent'; -import { getServiceTransactionTypes } from './get_service_transaction_types'; - -describe('services queries', () => { - let mock: SearchParamsMock; - - afterEach(() => { - mock.teardown(); - }); - - it('fetches the service agent name', async () => { - mock = await inspectSearchParams(({ mockApmEventClient }) => - getServiceAgent({ - serviceName: 'foo', - apmEventClient: mockApmEventClient, - start: 0, - end: 50000, - }) - ); - - expect(mock.params).toMatchSnapshot(); - }); - - it('fetches the service transaction types', async () => { - mock = await inspectSearchParams(({ mockApmEventClient }) => - getServiceTransactionTypes({ - serviceName: 'foo', - apmEventClient: mockApmEventClient, - start: 0, - end: 50000, - documentType: ApmDocumentType.TransactionMetric, - rollupInterval: RollupInterval.OneMinute, - }) - ); - - expect(mock.params).toMatchSnapshot(); - }); - - it('fetches the service items', async () => { - mock = await inspectSearchParams( - ({ mockApmEventClient, mockApmAlertsClient }) => - getServicesItems({ - mlClient: undefined, - apmEventClient: mockApmEventClient, - documentType: ApmDocumentType.TransactionEvent, - rollupInterval: RollupInterval.None, - logger: {} as any, - environment: ENVIRONMENT_ALL.value, - kuery: '', - start: 0, - end: 50000, - serviceGroup: null, - randomSampler: { - probability: 1, - seed: 0, - }, - apmAlertsClient: mockApmAlertsClient, - useDurationSummary: false, - }) - ); - - const allParams = mock.spy.mock.calls.map((call) => call[1]); - - expect(allParams).toMatchSnapshot(); - }); - - it('fetches the agent status', async () => { - mock = await inspectSearchParams(({ mockApmEventClient }) => - hasHistoricalAgentData(mockApmEventClient) - ); - - expect(mock.params).toMatchSnapshot(); - }); -}); diff --git a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts index 1cac68f74b8b7b..301a4c96dfa358 100644 --- a/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts +++ b/x-pack/plugins/apm/typings/es_schemas/raw/span_raw.ts @@ -71,6 +71,9 @@ export interface SpanRaw extends APMBaseDoc { id: string; }; child?: { id: string[] }; + code?: { + stacktrace?: string; + }; http?: Http; url?: Url; } diff --git a/x-pack/plugins/canvas/public/components/popover/popover.tsx b/x-pack/plugins/canvas/public/components/popover/popover.tsx index 2ef1d4efc10d38..85bf9520b2758d 100644 --- a/x-pack/plugins/canvas/public/components/popover/popover.tsx +++ b/x-pack/plugins/canvas/public/components/popover/popover.tsx @@ -17,7 +17,6 @@ interface Props { ownFocus?: boolean; tooltip?: string; panelClassName?: string; - anchorClassName?: string; anchorPosition?: string; panelPaddingSize?: 'none' | 's' | 'm' | 'l'; id?: string; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap index 5d2efe2903bf36..b661ee6e992e7e 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/__snapshots__/app.test.tsx.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; +exports[` App renders properly 1`] = `"
markdown mock
markdown mock

Page level controls

My Canvas Workpad

There is a new region landmark with page level controls at the end of the document.

"`; diff --git a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap index db2b294c9074a3..da3ad71c3f0346 100644 --- a/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap +++ b/x-pack/plugins/canvas/shareable_runtime/components/footer/settings/__snapshots__/settings.test.tsx.snap @@ -9,7 +9,7 @@ exports[` can navigate Autoplay Settings 1`] = ` aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: -16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -102,7 +102,7 @@ exports[` can navigate Autoplay Settings 2`] = ` aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-isOpen-hasTransform-top" + class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-light-isOpen-hasTransform-top" data-popover-open="true" data-popover-panel="true" role="dialog" @@ -345,7 +345,7 @@ exports[` can navigate Toolbar Settings, closes when activated 1`] = aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: -16px; left: -22px; will-change: transform, opacity; z-index: 2000;" @@ -438,7 +438,7 @@ exports[` can navigate Toolbar Settings, closes when activated 2`] = aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-isOpen-hasTransform-top" + class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-light-isOpen-hasTransform-top" data-popover-open="true" data-popover-panel="true" role="dialog" @@ -615,7 +615,7 @@ exports[` can navigate Toolbar Settings, closes when activated 3`] = aria-describedby="generated-id" aria-live="off" aria-modal="true" - class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-hasTransform" + class="euiPanel euiPanel--plain euiPopover__panel emotion-euiPanel-grow-m-plain-euiPopover__panel-light-hasTransform" data-popover-panel="true" role="dialog" style="top: -16px; left: -22px; z-index: 2000;" 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 dcec2558aad467..e88b5e52c08481 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 @@ -8,6 +8,10 @@ import userEvent from '@testing-library/user-event'; import { waitFor } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks/dom'; +import { + waitForEuiPopoverOpen, + waitForEuiContextMenuPanelTransition, +} from '@elastic/eui/lib/test/rtl'; import { useActions } from './use_actions'; import { basicCase } from '../../containers/mock'; @@ -69,13 +73,12 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByText('Actions')).toBeInTheDocument(); - expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); - expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); - }); + expect(res.getByText('Actions')).toBeInTheDocument(); + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); }); it('change the status of the case', async () => { @@ -89,24 +92,16 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); - }); + userEvent.click(res.getByTestId(`case-action-status-panel-${basicCase.id}`)); + await waitForEuiContextMenuPanelTransition(); - userEvent.click(res.getByTestId(`case-action-status-panel-${basicCase.id}`), undefined, { - skipPointerEventsCheck: true, - }); + expect(res.getByTestId('cases-bulk-action-status-open')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-in-progress')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-status-closed')).toBeInTheDocument(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-status-open')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-status-in-progress')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-status-closed')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-bulk-action-status-in-progress'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-status-in-progress')); await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); @@ -124,25 +119,17 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId(`case-action-severity-panel-${basicCase.id}`), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)); + await waitForEuiContextMenuPanelTransition(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-severity-low')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-severity-medium')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-severity-high')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-severity-critical')).toBeInTheDocument(); - }); + expect(res.getByTestId('cases-bulk-action-severity-low')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-severity-medium')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-severity-high')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-severity-critical')).toBeInTheDocument(); - userEvent.click(res.getByTestId('cases-bulk-action-severity-medium'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-severity-medium')); await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); @@ -167,14 +154,9 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-action-copy-id'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-action-copy-id')); expect(navigator.clipboard.writeText).toHaveBeenCalledWith(basicCase.id); @@ -195,14 +177,9 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-bulk-action-delete'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-delete')); await waitFor(() => { expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); @@ -224,22 +201,15 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-bulk-action-delete'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-delete')); await waitFor(() => { expect(res.getByTestId('confirm-delete-case-modal')).toBeInTheDocument(); }); - userEvent.click(res.getByTestId('confirmModalCancelButton'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('confirmModalCancelButton')); expect(res.queryByTestId('confirm-delete-case-modal')).toBeFalsy(); }); @@ -257,14 +227,9 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-tags')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-bulk-action-tags'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-tags')); await waitFor(() => { expect(res.getByTestId('cases-edit-tags-flyout')).toBeInTheDocument(); @@ -297,14 +262,9 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId('cases-bulk-action-assignees')).toBeInTheDocument(); - }); - - userEvent.click(res.getByTestId('cases-bulk-action-assignees'), undefined, { - skipPointerEventsCheck: true, - }); + userEvent.click(res.getByTestId('cases-bulk-action-assignees')); await waitFor(() => { expect(res.getByTestId('cases-edit-assignees-flyout')).toBeInTheDocument(); @@ -338,14 +298,13 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); - expect(res.getByTestId(`actions-separator-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); - }); + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.getByTestId(`actions-separator-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); }); it('shows the correct actions with no delete permissions', async () => { @@ -358,14 +317,13 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeInTheDocument(); - expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); - expect(res.queryByTestId('cases-bulk-action-delete')).toBeFalsy(); - expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); - }); + expect(res.getByTestId(`case-action-status-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeInTheDocument(); + expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); + expect(res.queryByTestId('cases-bulk-action-delete')).toBeFalsy(); + expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); }); it('shows the correct actions with only delete permissions', async () => { @@ -378,14 +336,13 @@ describe('useActions', () => { const res = appMockRender.render(comp); userEvent.click(res.getByTestId(`case-action-popover-button-${basicCase.id}`)); + await waitForEuiPopoverOpen(); - await waitFor(() => { - expect(res.queryByTestId(`case-action-status-panel-${basicCase.id}`)).toBeFalsy(); - expect(res.queryByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeFalsy(); - expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); - expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); - expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); - }); + expect(res.queryByTestId(`case-action-status-panel-${basicCase.id}`)).toBeFalsy(); + expect(res.queryByTestId(`case-action-severity-panel-${basicCase.id}`)).toBeFalsy(); + expect(res.getByTestId('cases-action-copy-id')).toBeInTheDocument(); + expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); + expect(res.queryByTestId(`actions-separator-${basicCase.id}`)).toBeFalsy(); }); it('returns null if the user does not have update or delete permissions', async () => { diff --git a/x-pack/plugins/cases/public/components/case_view/components/edit_category.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/edit_category.test.tsx index 33c893d6f6b461..16804fb9580a38 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/edit_category.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/edit_category.test.tsx @@ -242,7 +242,7 @@ describe('EditCategory ', () => { await waitFor(() => { expect(screen.getByTestId('categories-list')).toBeInTheDocument(); - expect(screen.getByText('My category')).toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('My category'); }); expect(screen.getByTestId('edit-category-submit')).toBeDisabled(); @@ -265,7 +265,7 @@ describe('EditCategory ', () => { await waitFor(() => { expect(screen.getByTestId('categories-list')).toBeInTheDocument(); - expect(screen.getByText('My category')).toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('My category'); }); userEvent.click(screen.getByTestId('edit-category-cancel')); @@ -276,7 +276,7 @@ describe('EditCategory ', () => { await waitFor(() => { expect(screen.getByTestId('categories-list')).toBeInTheDocument(); - expect(screen.getByText('category from the API')).toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('category from the API'); }); }); diff --git a/x-pack/plugins/cases/public/components/category/category_component.test.tsx b/x-pack/plugins/cases/public/components/category/category_component.test.tsx index 2b0d7ef39007b9..6eb95600cd58c4 100644 --- a/x-pack/plugins/cases/public/components/category/category_component.test.tsx +++ b/x-pack/plugins/cases/public/components/category/category_component.test.tsx @@ -47,7 +47,7 @@ describe('Category ', () => { it('renders category correctly', () => { render(); - expect(screen.getByText('new-category')).toBeInTheDocument(); + expect(screen.getByRole('combobox')).toHaveValue('new-category'); }); it('renders allow to add new category option', async () => { @@ -56,7 +56,7 @@ describe('Category ', () => { userEvent.type(screen.getByRole('combobox'), 'new{enter}'); expect(onChange).toBeCalledWith('new'); - expect(screen.getByText('new')).toBeInTheDocument(); + expect(screen.getByRole('combobox')).toHaveValue('new'); }); it('renders current option list', async () => { @@ -97,10 +97,10 @@ describe('Category ', () => { expect(onChange).toHaveBeenCalledWith('hi'); }); - userEvent.type(screen.getByRole('combobox'), 'Hi{enter}'); + userEvent.type(screen.getByRole('combobox'), ' there{enter}'); await waitFor(() => { - expect(onChange).toHaveBeenCalledWith('Hi'); + expect(onChange).toHaveBeenCalledWith('hi there'); }); }); }); diff --git a/x-pack/plugins/cases/public/components/create/assignees.test.tsx b/x-pack/plugins/cases/public/components/create/assignees.test.tsx index 9a32ab5f1ffd92..002cd2976f6051 100644 --- a/x-pack/plugins/cases/public/components/create/assignees.test.tsx +++ b/x-pack/plugins/cases/public/components/create/assignees.test.tsx @@ -198,7 +198,7 @@ describe('Assignees', () => { }); act(() => { - userEvent.click(screen.getByText('Turtle')); + userEvent.click(screen.getByText('Turtle'), undefined, { skipPointerEventsCheck: true }); }); // ensure that the similar user is still available for selection diff --git a/x-pack/plugins/cloud_security_posture/common/constants.ts b/x-pack/plugins/cloud_security_posture/common/constants.ts index 5e56b1131f10ff..7f4f8c796f4c16 100644 --- a/x-pack/plugins/cloud_security_posture/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/common/constants.ts @@ -26,11 +26,14 @@ export const BENCHMARKS_API_CURRENT_VERSION = '1'; export const FIND_CSP_BENCHMARK_RULE_ROUTE_PATH = '/internal/cloud_security_posture/rules/_find'; export const FIND_CSP_BENCHMARK_RULE_API_CURRENT_VERSION = '1'; -export const DETECTION_RULE_ALERTS_STATUS_API_CURRENT_VERSION = '1'; -export const DETECTION_RULE_RULES_API_CURRENT_VERSION = '2023-10-31'; +export const CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH = + '/internal/cloud_security_posture/rules/_bulk_action'; +export const CSP_BENCHMARK_RULES_BULK_ACTION_API_CURRENT_VERSION = '1'; export const GET_DETECTION_RULE_ALERTS_STATUS_PATH = '/internal/cloud_security_posture/detection_engine_rules/alerts/_status'; +export const DETECTION_RULE_ALERTS_STATUS_API_CURRENT_VERSION = '1'; +export const DETECTION_RULE_RULES_API_CURRENT_VERSION = '2023-10-31'; export const CLOUD_SECURITY_POSTURE_PACKAGE_NAME = 'cloud_security_posture'; // TODO: REMOVE CSP_LATEST_FINDINGS_DATA_VIEW and replace it with LATEST_FINDINGS_INDEX_PATTERN @@ -88,6 +91,8 @@ export const INTERNAL_FEATURE_FLAGS = { } as const; export const CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE = 'csp-rule-template'; +export const INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE = 'cloud-security-posture-settings'; +export const INTERNAL_CSP_SETTINGS_SAVED_OBJECT_ID = 'csp-internal-settings'; export const CLOUDBEAT_VANILLA = 'cloudbeat/cis_k8s'; export const CLOUDBEAT_EKS = 'cloudbeat/cis_eks'; diff --git a/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts b/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts index 0b7b90339dff15..cef3e445b91a89 100644 --- a/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts +++ b/x-pack/plugins/cloud_security_posture/common/types/rules/v3.ts @@ -129,3 +129,36 @@ export interface FindCspBenchmarkRuleResponse { page: number; perPage: number; } + +export const cspBenchmarkRules = schema.arrayOf( + schema.object({ + benchmark_id: schema.string(), + benchmark_version: schema.string(), + rule_number: schema.string(), + }) +); + +export const cspBenchmarkRulesBulkActionRequestSchema = schema.object({ + action: schema.oneOf([schema.literal('mute'), schema.literal('unmute')]), + rules: cspBenchmarkRules, +}); + +export type CspBenchmarkRules = TypeOf; + +export type CspBenchmarkRulesBulkActionRequestSchema = TypeOf< + typeof cspBenchmarkRulesBulkActionRequestSchema +>; + +const rulesStates = schema.recordOf( + schema.string(), + schema.object({ + muted: schema.boolean(), + }) +); + +export const cspSettingsSchema = schema.object({ + rules: rulesStates, +}); + +export type CspBenchmarkRulesStates = TypeOf; +export type CspSettings = TypeOf; diff --git a/x-pack/plugins/cloud_security_posture/server/plugin.ts b/x-pack/plugins/cloud_security_posture/server/plugin.ts index 8b77581efd39da..58a143b220857b 100755 --- a/x-pack/plugins/cloud_security_posture/server/plugin.ts +++ b/x-pack/plugins/cloud_security_posture/server/plugin.ts @@ -35,7 +35,7 @@ import type { CspServerPluginStartServices, } from './types'; import { setupRoutes } from './routes/setup_routes'; -import { setupSavedObjects } from './saved_objects'; +import { cspBenchmarkRule, cspSettings } from './saved_objects'; import { initializeCspIndices } from './create_indices/create_indices'; import { initializeCspTransforms } from './create_transforms/create_transforms'; import { @@ -50,6 +50,7 @@ import { } from './tasks/findings_stats_task'; import { registerCspmUsageCollector } from './lib/telemetry/collectors/register'; import { CloudSecurityPostureConfig } from './config'; +import { CspBenchmarkRule, CspSettings } from '../common/types/latest'; export class CspPlugin implements @@ -80,7 +81,8 @@ export class CspPlugin core: CoreSetup, plugins: CspServerPluginSetupDeps ): CspServerPluginSetup { - setupSavedObjects(core.savedObjects); + core.savedObjects.registerType(cspBenchmarkRule); + core.savedObjects.registerType(cspSettings); setupRoutes({ core, diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.test.ts new file mode 100644 index 00000000000000..1bb2232d2834d1 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.test.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 expect from 'expect'; +import { setRulesStates, buildRuleKey } from './utils'; + +describe('CSP Rule State Management', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should set rules states correctly', () => { + const ruleIds = ['rule1', 'rule3']; + const newState = true; + + const updatedRulesStates = setRulesStates(ruleIds, newState); + + expect(updatedRulesStates).toEqual({ + rule1: { muted: true }, + rule3: { muted: true }, + }); + }); + + it('should build a rule key with the provided benchmarkId, benchmarkVersion, and ruleNumber', () => { + const benchmarkId = 'randomId'; + const benchmarkVersion = 'v1'; + const ruleNumber = '001'; + + const result = buildRuleKey(benchmarkId, benchmarkVersion, ruleNumber); + + expect(result).toBe(`${benchmarkId};${benchmarkVersion};${ruleNumber}`); + }); +}); 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 new file mode 100644 index 00000000000000..a87df39341741b --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.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 { transformError } from '@kbn/securitysolution-es-utils'; +import { + CspBenchmarkRulesBulkActionRequestSchema, + CspBenchmarkRulesStates, + cspBenchmarkRulesBulkActionRequestSchema, +} from '../../../../common/types/rules/v3'; +import { CspRouter } from '../../../types'; + +import { CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH } from '../../../../common/constants'; +import { bulkActionBenchmarkRulesHandler } from './v1'; + +export const defineBulkActionCspBenchmarkRulesRoute = (router: CspRouter) => + router.versioned + .post({ + access: 'internal', + path: CSP_BENCHMARK_RULES_BULK_ACTION_ROUTE_PATH, + }) + .addVersion( + { + version: '1', + validate: { + request: { + body: cspBenchmarkRulesBulkActionRequestSchema, + }, + }, + }, + async (context, request, response) => { + if (!(await context.fleet).authz.fleet.all) { + return response.forbidden(); + } + const cspContext = await context.csp; + + try { + const requestBody: CspBenchmarkRulesBulkActionRequestSchema = request.body; + + const benchmarkRulesToUpdate = requestBody.rules; + + const handlerResponse = await bulkActionBenchmarkRulesHandler( + cspContext.encryptedSavedObjects, + benchmarkRulesToUpdate, + requestBody.action + ); + + const updatedBenchmarkRules: CspBenchmarkRulesStates = handlerResponse; + return response.ok({ + body: { + updated_benchmark_rules: updatedBenchmarkRules, + message: 'The bulk operation has been executed successfully.', + }, + }); + } catch (err) { + const error = transformError(err); + + cspContext.logger.error(`Bulk action failed: ${error.message}`); + return response.customError({ + body: { message: error.message }, + statusCode: error.statusCode || 500, // Default to 500 if no specific status code is provided + }); + } + } + ); diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.ts new file mode 100644 index 00000000000000..3442b3f050b90c --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/utils.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 { + SavedObjectsClientContract, + SavedObjectsUpdateResponse, +} from '@kbn/core-saved-objects-api-server'; +import { CspBenchmarkRulesStates, CspSettings } from '../../../../common/types/rules/v3'; + +import { + INTERNAL_CSP_SETTINGS_SAVED_OBJECT_ID, + INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE, +} from '../../../../common/constants'; + +export const updateRulesStates = async ( + encryptedSoClient: SavedObjectsClientContract, + newRulesStates: CspBenchmarkRulesStates +): Promise> => { + return await encryptedSoClient.update( + INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE, + INTERNAL_CSP_SETTINGS_SAVED_OBJECT_ID, + { rules: newRulesStates }, + // if there is no saved object yet, insert a new SO + { upsert: { rules: newRulesStates } } + ); +}; + +export const setRulesStates = (ruleIds: string[], state: boolean): CspBenchmarkRulesStates => { + const rulesStates: CspBenchmarkRulesStates = {}; + ruleIds.forEach((ruleId) => { + rulesStates[ruleId] = { muted: state }; + }); + return rulesStates; +}; + +export const buildRuleKey = (benchmarkId: string, benchmarkVersion: string, ruleNumber: string) => { + return `${benchmarkId};${benchmarkVersion};${ruleNumber}`; +}; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/v1.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/v1.ts new file mode 100644 index 00000000000000..42895b5eb694d1 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/v1.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 { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import { CspBenchmarkRules, CspBenchmarkRulesStates } from '../../../../common/types/rules/v3'; +import { buildRuleKey, setRulesStates, updateRulesStates } from './utils'; + +const muteStatesMap = { + mute: true, + unmute: false, +}; + +export const bulkActionBenchmarkRulesHandler = async ( + encryptedSoClient: SavedObjectsClientContract, + rulesToUpdate: CspBenchmarkRules, + action: 'mute' | 'unmute' +): Promise => { + const ruleKeys = rulesToUpdate.map((rule) => + buildRuleKey(rule.benchmark_id, rule.benchmark_version, rule.rule_number) + ); + + const newRulesStates = setRulesStates(ruleKeys, muteStatesMap[action]); + + const newCspSettings = await updateRulesStates(encryptedSoClient, newRulesStates); + + return newCspSettings.attributes.rules!; +}; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.test.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.test.ts index ffec7d5b9b2610..2a0130c0f0fd74 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.test.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { getSortedCspBenchmarkRulesTemplates } from './v1'; +import { getSortedCspBenchmarkRulesTemplates } from './utils'; import { CspBenchmarkRule } from '../../../../common/types/latest'; describe('getSortedCspBenchmarkRules', () => { diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts index aa4856fd9bada7..728fca1c0ae7cd 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/find.ts @@ -9,11 +9,10 @@ import { FindCspBenchmarkRuleRequest, FindCspBenchmarkRuleResponse, findCspBenchmarkRuleRequestSchema, -} from '../../../../common/types/latest'; - +} from '../../../../common/types/rules/v3'; import { FIND_CSP_BENCHMARK_RULE_ROUTE_PATH } from '../../../../common/constants'; import { CspRouter } from '../../../types'; -import { findRuleHandler as findRuleHandlerV1 } from './v1'; +import { findBenchmarkRuleHandler as findRuleHandlerV1 } from './v1'; export const defineFindCspBenchmarkRuleRoute = (router: CspRouter) => router.versioned diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/utils.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/utils.ts new file mode 100644 index 00000000000000..0601a4eb25577c --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/utils.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import semverValid from 'semver/functions/valid'; +import semverCompare from 'semver/functions/compare'; +import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; +import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../benchmarks/benchmarks'; +import { getBenchmarkFromPackagePolicy } from '../../../../common/utils/helpers'; + +import type { CspBenchmarkRule } from '../../../../common/types/latest'; + +export const getSortedCspBenchmarkRulesTemplates = (cspBenchmarkRules: CspBenchmarkRule[]) => { + return cspBenchmarkRules.slice().sort((a, b) => { + const ruleNumberA = a?.metadata?.benchmark?.rule_number; + const ruleNumberB = b?.metadata?.benchmark?.rule_number; + + const versionA = semverValid(ruleNumberA); + const versionB = semverValid(ruleNumberB); + + if (versionA !== null && versionB !== null) { + return semverCompare(versionA, versionB); + } else { + return String(ruleNumberA).localeCompare(String(ruleNumberB)); + } + }); +}; + +export const getBenchmarkIdFromPackagePolicyId = async ( + soClient: SavedObjectsClientContract, + packagePolicyId: string +): Promise => { + const res = await soClient.get( + PACKAGE_POLICY_SAVED_OBJECT_TYPE, + packagePolicyId + ); + return getBenchmarkFromPackagePolicy(res.attributes.inputs); +}; diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/v1.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/v1.ts index 6bd0d14a2f540a..4971098cb8067e 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/v1.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/find/v1.ts @@ -4,49 +4,17 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import semverValid from 'semver/functions/valid'; -import semverCompare from 'semver/functions/compare'; -import { NewPackagePolicy } from '@kbn/fleet-plugin/common'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { getBenchmarkFilter } from '../../../../common/utils/helpers'; import { CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE } from '../../../../common/constants'; -import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../benchmarks/benchmarks'; -import { getBenchmarkFromPackagePolicy } from '../../../../common/utils/helpers'; - +import { getBenchmarkIdFromPackagePolicyId, getSortedCspBenchmarkRulesTemplates } from './utils'; +import type { CspBenchmarkRule } from '../../../../common/types/latest'; import type { - CspBenchmarkRule, FindCspBenchmarkRuleRequest, FindCspBenchmarkRuleResponse, -} from '../../../../common/types/latest'; - -export const getSortedCspBenchmarkRulesTemplates = (cspBenchmarkRules: CspBenchmarkRule[]) => { - return cspBenchmarkRules.slice().sort((a, b) => { - const ruleNumberA = a?.metadata?.benchmark?.rule_number; - const ruleNumberB = b?.metadata?.benchmark?.rule_number; - - const versionA = semverValid(ruleNumberA); - const versionB = semverValid(ruleNumberB); - - if (versionA !== null && versionB !== null) { - return semverCompare(versionA, versionB); - } else { - return String(ruleNumberA).localeCompare(String(ruleNumberB)); - } - }); -}; - -export const getBenchmarkIdFromPackagePolicyId = async ( - soClient: SavedObjectsClientContract, - packagePolicyId: string -): Promise => { - const res = await soClient.get( - PACKAGE_POLICY_SAVED_OBJECT_TYPE, - packagePolicyId - ); - return getBenchmarkFromPackagePolicy(res.attributes.inputs); -}; +} from '../../../../common/types/rules/v3'; -export const findRuleHandler = async ( +export const findBenchmarkRuleHandler = async ( soClient: SavedObjectsClientContract, options: FindCspBenchmarkRuleRequest ): Promise => { diff --git a/x-pack/plugins/cloud_security_posture/server/routes/setup_routes.ts b/x-pack/plugins/cloud_security_posture/server/routes/setup_routes.ts index 49022dd1f5fe64..88570781ed066e 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/setup_routes.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/setup_routes.ts @@ -7,6 +7,7 @@ import type { CoreSetup, Logger } from '@kbn/core/server'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; +import { INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE } from '../../common/constants'; import type { CspRequestHandlerContext, CspServerPluginStart, @@ -19,6 +20,7 @@ import { defineGetBenchmarksRoute } from './benchmarks/benchmarks'; import { defineGetCspStatusRoute } from './status/status'; import { defineFindCspBenchmarkRuleRoute } from './benchmark_rules/find/find'; import { defineGetDetectionEngineAlertsStatus } from './detection_engine/get_detection_engine_alerts_count_by_rule_tags'; +import { defineBulkActionCspBenchmarkRulesRoute } from './benchmark_rules/bulk_action/bulk_action'; /** * 1. Registers routes @@ -40,6 +42,7 @@ export async function setupRoutes({ defineGetCspStatusRoute(router); defineFindCspBenchmarkRuleRoute(router); defineGetDetectionEngineAlertsStatus(router); + defineBulkActionCspBenchmarkRulesRoute(router); core.http.registerRouteHandlerContext( PLUGIN_ID, @@ -61,6 +64,9 @@ export async function setupRoutes({ logger, esClient: coreContext.elasticsearch.client, soClient: coreContext.savedObjects.client, + encryptedSavedObjects: coreContext.savedObjects.getClient({ + includedHiddenTypes: [INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE], + }), agentPolicyService: fleet.agentPolicyService, agentService: fleet.agentService, packagePolicyService: fleet.packagePolicyService, diff --git a/x-pack/plugins/cloud_security_posture/server/saved_objects/csp_settings.ts b/x-pack/plugins/cloud_security_posture/server/saved_objects/csp_settings.ts new file mode 100644 index 00000000000000..d163ca6e26f051 --- /dev/null +++ b/x-pack/plugins/cloud_security_posture/server/saved_objects/csp_settings.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 { SavedObjectsType } from '@kbn/core/server'; +import { SECURITY_SOLUTION_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { cspSettingsSchema } from '../../common/types/rules/v3'; +import { cspSettingsSavedObjectMapping } from './mappings'; +import { INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE } from '../../common/constants'; + +export const cspSettings: SavedObjectsType = { + name: INTERNAL_CSP_SETTINGS_SAVED_OBJECT_TYPE, + indexPattern: SECURITY_SOLUTION_SAVED_OBJECT_INDEX, + hidden: true, + namespaceType: 'agnostic', + schemas: { + '8.12.0': cspSettingsSchema, + }, + mappings: cspSettingsSavedObjectMapping, +}; diff --git a/x-pack/plugins/cloud_security_posture/server/saved_objects/index.ts b/x-pack/plugins/cloud_security_posture/server/saved_objects/index.ts index 7217fd8606ed9a..98b08c2fad402e 100644 --- a/x-pack/plugins/cloud_security_posture/server/saved_objects/index.ts +++ b/x-pack/plugins/cloud_security_posture/server/saved_objects/index.ts @@ -5,4 +5,5 @@ * 2.0. */ -export { setupSavedObjects } from './saved_objects'; +export { cspBenchmarkRule } from './csp_benchmark_rule'; +export { cspSettings } from './csp_settings'; diff --git a/x-pack/plugins/cloud_security_posture/server/saved_objects/mappings.ts b/x-pack/plugins/cloud_security_posture/server/saved_objects/mappings.ts index f672d271c8b5f1..e2e880f72a7c95 100644 --- a/x-pack/plugins/cloud_security_posture/server/saved_objects/mappings.ts +++ b/x-pack/plugins/cloud_security_posture/server/saved_objects/mappings.ts @@ -60,3 +60,8 @@ export const cspBenchmarkRuleSavedObjectMapping: SavedObjectsTypeMappingDefiniti }, }, }; + +export const cspSettingsSavedObjectMapping: SavedObjectsTypeMappingDefinition = { + dynamic: false, + properties: {}, +}; diff --git a/x-pack/plugins/cloud_security_posture/server/saved_objects/saved_objects.ts b/x-pack/plugins/cloud_security_posture/server/saved_objects/saved_objects.ts deleted file mode 100644 index eed21b5b919160..00000000000000 --- a/x-pack/plugins/cloud_security_posture/server/saved_objects/saved_objects.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { SavedObjectsServiceSetup } from '@kbn/core/server'; -import { SECURITY_SOLUTION_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; -import { rulesV1, rulesV2, rulesV3 } from '../../common/types'; -import { cspBenchmarkRuleSavedObjectMapping } from './mappings'; -import { cspBenchmarkRuleMigrations } from './migrations'; - -import { CspBenchmarkRule } from '../../common/types/latest'; - -import { CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE } from '../../common/constants'; - -export function setupSavedObjects(savedObjects: SavedObjectsServiceSetup) { - savedObjects.registerType({ - name: CSP_BENCHMARK_RULE_SAVED_OBJECT_TYPE, - indexPattern: SECURITY_SOLUTION_SAVED_OBJECT_INDEX, - hidden: false, - namespaceType: 'agnostic', - management: { - importableAndExportable: true, - visibleInManagement: true, - }, - schemas: { - '8.3.0': rulesV1.cspBenchmarkRuleSchema, - '8.4.0': rulesV2.cspBenchmarkRuleSchema, - '8.7.0': rulesV3.cspBenchmarkRuleSchema, - }, - migrations: cspBenchmarkRuleMigrations, - mappings: cspBenchmarkRuleSavedObjectMapping, - }); -} diff --git a/x-pack/plugins/cloud_security_posture/server/types.ts b/x-pack/plugins/cloud_security_posture/server/types.ts index 3c84de12decf68..b6e83939b6ca74 100644 --- a/x-pack/plugins/cloud_security_posture/server/types.ts +++ b/x-pack/plugins/cloud_security_posture/server/types.ts @@ -69,6 +69,7 @@ export interface CspApiRequestHandlerContext { logger: Logger; esClient: IScopedClusterClient; soClient: SavedObjectsClientContract; + encryptedSavedObjects: SavedObjectsClientContract; agentPolicyService: AgentPolicyServiceInterface; agentService: AgentService; packagePolicyService: PackagePolicyClient; diff --git a/x-pack/plugins/dataset_quality/common/api_types.ts b/x-pack/plugins/dataset_quality/common/api_types.ts index 4f9936d65e0147..70a5c3e5971481 100644 --- a/x-pack/plugins/dataset_quality/common/api_types.ts +++ b/x-pack/plugins/dataset_quality/common/api_types.ts @@ -7,7 +7,7 @@ import * as rt from 'io-ts'; -export const datasetStatRt = rt.intersection([ +export const dataStreamStatRt = rt.intersection([ rt.type({ name: rt.string, }), @@ -19,6 +19,8 @@ export const datasetStatRt = rt.intersection([ }), ]); +export type DataStreamStat = rt.TypeOf; + export const integrationIconRt = rt.intersection([ rt.type({ path: rt.string, @@ -39,9 +41,12 @@ export const integrationRt = rt.intersection([ title: rt.string, version: rt.string, icons: rt.array(integrationIconRt), + datasets: rt.record(rt.string, rt.string), }), ]); +export type Integration = rt.TypeOf; + export const degradedDocsRt = rt.type({ dataset: rt.string, percentage: rt.number, @@ -52,7 +57,7 @@ export type DegradedDocs = rt.TypeOf; export const getDataStreamsStatsResponseRt = rt.exact( rt.intersection([ rt.type({ - dataStreamsStats: rt.array(datasetStatRt), + dataStreamsStats: rt.array(dataStreamStatRt), }), rt.type({ integrations: rt.array(integrationRt), diff --git a/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts b/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts index 2456284eb3cdcc..0f48ae45aac7ea 100644 --- a/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts +++ b/x-pack/plugins/dataset_quality/common/data_streams_stats/data_stream_stat.ts @@ -9,17 +9,21 @@ import { Integration } from './integration'; import { DataStreamStatType, IntegrationType } from './types'; export class DataStreamStat { + rawName: string; name: DataStreamStatType['name']; + namespace: string; title: string; size?: DataStreamStatType['size']; - sizeBytes?: DataStreamStatType['size_bytes']; - lastActivity?: DataStreamStatType['last_activity']; + sizeBytes?: DataStreamStatType['sizeBytes']; + lastActivity?: DataStreamStatType['lastActivity']; integration?: IntegrationType; degradedDocs?: number; private constructor(dataStreamStat: DataStreamStat) { + this.rawName = dataStreamStat.name; this.name = dataStreamStat.name; this.title = dataStreamStat.title ?? dataStreamStat.name; + this.namespace = dataStreamStat.namespace; this.size = dataStreamStat.size; this.sizeBytes = dataStreamStat.sizeBytes; this.lastActivity = dataStreamStat.lastActivity; @@ -31,11 +35,13 @@ export class DataStreamStat { const [_type, dataset, namespace] = dataStreamStat.name.split('-'); const dataStreamStatProps = { - name: dataStreamStat.name, - title: `${dataset}-${namespace}`, + rawName: dataStreamStat.name, + name: dataset, + title: dataStreamStat.integration?.datasets?.[dataset] ?? dataset, + namespace, size: dataStreamStat.size, - sizeBytes: dataStreamStat.size_bytes, - lastActivity: dataStreamStat.last_activity, + sizeBytes: dataStreamStat.sizeBytes, + lastActivity: dataStreamStat.lastActivity, integration: dataStreamStat.integration ? Integration.create(dataStreamStat.integration) : undefined, diff --git a/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx b/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx index 94223e10f316f6..cdda4dfa004b1e 100644 --- a/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx +++ b/x-pack/plugins/dataset_quality/public/components/dataset_quality/columns.tsx @@ -5,34 +5,39 @@ * 2.0. */ -import React from 'react'; import { + EuiBadge, EuiBasicTableColumn, EuiCode, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSkeletonRectangle, - EuiText, EuiToolTip, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { PackageIcon } from '@kbn/fleet-plugin/public'; -import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; +import { PackageIcon } from '@kbn/fleet-plugin/public'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import React from 'react'; import { DEGRADED_QUALITY_MINIMUM_PERCENTAGE, POOR_QUALITY_MINIMUM_PERCENTAGE, } from '../../../common/constants'; import { DataStreamStat } from '../../../common/data_streams_stats/data_stream_stat'; import loggingIcon from '../../icons/logging.svg'; +import { LogExplorerLink } from '../log_explorer_link'; import { QualityIndicator, QualityPercentageIndicator } from '../quality_indicator'; const nameColumnName = i18n.translate('xpack.datasetQuality.nameColumnName', { defaultMessage: 'Dataset Name', }); +const namespaceColumnName = i18n.translate('xpack.datasetQuality.namespaceColumnName', { + defaultMessage: 'Namespace', +}); + const sizeColumnName = i18n.translate('xpack.datasetQuality.sizeColumnName', { defaultMessage: 'Size', }); @@ -41,6 +46,17 @@ const degradedDocsColumnName = i18n.translate('xpack.datasetQuality.degradedDocs defaultMessage: 'Degraded Docs', }); +const lastActivityColumnName = i18n.translate('xpack.datasetQuality.lastActivityColumnName', { + defaultMessage: 'Last Activity', +}); + +const actionsColumnName = i18n.translate('xpack.datasetQuality.actionsColumnName', { + defaultMessage: 'Actions', +}); +const openActionName = i18n.translate('xpack.datasetQuality.openActionName', { + defaultMessage: 'Open', +}); + const degradedDocsDescription = (minimimPercentage: number) => i18n.translate('xpack.datasetQuality.degradedDocsQualityDescription', { defaultMessage: 'greater than {minimimPercentage}%', @@ -60,22 +76,19 @@ const degradedDocsColumnTooltip = ( visualQueue: ( - - - {` ${degradedDocsDescription(POOR_QUALITY_MINIMUM_PERCENTAGE)}`} - + - - - {` ${degradedDocsDescription(DEGRADED_QUALITY_MINIMUM_PERCENTAGE)}`} - + - - - {' 0%'} - + ), @@ -83,10 +96,6 @@ const degradedDocsColumnTooltip = ( /> ); -const lastActivityColumnName = i18n.translate('xpack.datasetQuality.lastActivityColumnName', { - defaultMessage: 'Last Activity', -}); - export const getDatasetQualitTableColumns = ({ fieldFormats, loadingDegradedStats, @@ -122,6 +131,14 @@ export const getDatasetQualitTableColumns = ({ ); }, }, + { + name: namespaceColumnName, + field: 'namespace', + sortable: true, + render: (_, dataStreamStat: DataStreamStat) => ( + {dataStreamStat.namespace} + ), + }, { name: sizeColumnName, field: 'size', @@ -147,10 +164,7 @@ export const getDatasetQualitTableColumns = ({ contentAriaLabel="Example description" > - - - - {`${dataStreamStat.degradedDocs ?? 0}%`} + ), @@ -164,5 +178,12 @@ export const getDatasetQualitTableColumns = ({ .convert(timestamp), sortable: true, }, + { + name: actionsColumnName, + render: (dataStreamStat: DataStreamStat) => ( + + ), + width: '100px', + }, ]; }; diff --git a/x-pack/plugins/dataset_quality/public/components/log_explorer_link.tsx b/x-pack/plugins/dataset_quality/public/components/log_explorer_link.tsx new file mode 100644 index 00000000000000..11227d0a6bd3a5 --- /dev/null +++ b/x-pack/plugins/dataset_quality/public/components/log_explorer_link.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiLink } from '@elastic/eui'; +import React from 'react'; +import { getRouterLinkProps } from '@kbn/router-utils'; +import { + SingleDatasetLocatorParams, + SINGLE_DATASET_LOCATOR_ID, +} from '@kbn/deeplinks-observability'; +import { DataStreamStat } from '../../common/data_streams_stats/data_stream_stat'; +import { useKibanaContextForPlugin } from '../utils'; + +export const LogExplorerLink = React.memo( + ({ dataStreamStat, title }: { dataStreamStat: DataStreamStat; title: string }) => { + const { + services: { share }, + } = useKibanaContextForPlugin(); + const params: SingleDatasetLocatorParams = { + dataset: dataStreamStat.name, + timeRange: { + from: 'now-1d', + to: 'now', + }, + integration: dataStreamStat.integration?.name, + filterControls: { + namespace: { + mode: 'include', + values: [dataStreamStat.namespace], + }, + }, + }; + + const singleDatasetLocator = + share.url.locators.get(SINGLE_DATASET_LOCATOR_ID); + + const urlToLogExplorer = singleDatasetLocator?.getRedirectUrl(params); + + const navigateToLogExplorer = () => { + singleDatasetLocator?.navigate(params) as Promise; + }; + + const logExplorerLinkProps = getRouterLinkProps({ + href: urlToLogExplorer, + onClick: navigateToLogExplorer, + }); + + return {title}; + } +); diff --git a/x-pack/plugins/dataset_quality/public/components/quality_indicator/indicator.tsx b/x-pack/plugins/dataset_quality/public/components/quality_indicator/indicator.tsx index a356ff204425fa..8344f046e02102 100644 --- a/x-pack/plugins/dataset_quality/public/components/quality_indicator/indicator.tsx +++ b/x-pack/plugins/dataset_quality/public/components/quality_indicator/indicator.tsx @@ -5,17 +5,21 @@ * 2.0. */ -import { EuiIcon, useEuiTheme } from '@elastic/eui'; -import React from 'react'; - -export function QualityIndicator({ quality }: { quality: 'good' | 'degraded' | 'poor' }) { - const { euiTheme } = useEuiTheme(); +import { EuiHealth } from '@elastic/eui'; +import React, { ReactNode } from 'react'; +export function QualityIndicator({ + quality, + description, +}: { + quality: 'good' | 'degraded' | 'poor'; + description: string | ReactNode; +}) { const qualityColors = { - poor: euiTheme.colors.dangerText, - degraded: euiTheme.colors.warningText, - good: euiTheme.colors.successText, + poor: 'danger', + degraded: 'warning', + good: 'success', }; - return ; + return {description}; } diff --git a/x-pack/plugins/dataset_quality/public/components/quality_indicator/percentage_indicator.tsx b/x-pack/plugins/dataset_quality/public/components/quality_indicator/percentage_indicator.tsx index b3f9d8e3b852cc..f5034bddab8c25 100644 --- a/x-pack/plugins/dataset_quality/public/components/quality_indicator/percentage_indicator.tsx +++ b/x-pack/plugins/dataset_quality/public/components/quality_indicator/percentage_indicator.tsx @@ -5,6 +5,8 @@ * 2.0. */ +import { EuiText } from '@elastic/eui'; +import { FormattedNumber } from '@kbn/i18n-react'; import React from 'react'; import { DEGRADED_QUALITY_MINIMUM_PERCENTAGE, @@ -20,5 +22,11 @@ export function QualityPercentageIndicator({ percentage = 0 }: { percentage?: nu ? 'degraded' : 'good'; - return ; + const description = ( + + % + + ); + + return ; } diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts index 6154e3bc11a248..b79b4eeec01162 100644 --- a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams/index.ts @@ -6,8 +6,8 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; +import { DataStreamTypes } from '../../../types/default_api_types'; import { dataStreamService } from '../../../services'; -import { DataStreamTypes } from '../../../types/data_stream'; export async function getDataStreams(options: { esClient: ElasticsearchClient; diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts index 830c3b162573f0..a0104afc1d5fe5 100644 --- a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/get_data_streams_stats.test.ts @@ -79,32 +79,32 @@ describe('getDataStreams', () => { { name: 'logs-elastic_agent-default', size: '1gb', - size_bytes: 1170805528, - last_activity: 1698916071000, + sizeBytes: 1170805528, + lastActivity: 1698916071000, }, { name: 'logs-elastic_agent.filebeat-default', size: '1.3mb', - size_bytes: 1459100, - last_activity: 1698902209996, + sizeBytes: 1459100, + lastActivity: 1698902209996, }, { name: 'logs-elastic_agent.fleet_server-default', size: '2.9mb', - size_bytes: 3052148, - last_activity: 1698914110010, + sizeBytes: 3052148, + lastActivity: 1698914110010, }, { name: 'logs-elastic_agent.metricbeat-default', size: '1.6mb', - size_bytes: 1704807, - last_activity: 1698672046707, + sizeBytes: 1704807, + lastActivity: 1698672046707, }, { name: 'logs-test.test-default', size: '6.2mb', - size_bytes: 6570447, - last_activity: 1698913802000, + sizeBytes: 6570447, + lastActivity: 1698913802000, }, ]); }); diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts index 9ec252d0963575..a78f2fec53e29f 100644 --- a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_data_streams_stats/index.ts @@ -6,8 +6,8 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; +import { DataStreamTypes } from '../../../types/default_api_types'; import { dataStreamService } from '../../../services'; -import { DataStreamTypes } from '../../../types/data_stream'; export async function getDataStreamsStats(options: { esClient: ElasticsearchClient; @@ -24,9 +24,9 @@ export async function getDataStreamsStats(options: { const mappedDataStreams = matchingDataStreamsStats.map((dataStream) => { return { name: dataStream.data_stream, - size: dataStream.store_size, - size_bytes: dataStream.store_size_bytes, - last_activity: dataStream.maximum_timestamp, + size: dataStream.store_size?.toString(), + sizeBytes: dataStream.store_size_bytes, + lastActivity: dataStream.maximum_timestamp, }; }); diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_degraded_docs.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_degraded_docs.ts index 4bbe01d219322d..1af5a603f36384 100644 --- a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_degraded_docs.ts +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_degraded_docs.ts @@ -14,7 +14,7 @@ import { DATA_STREAM_TYPE, _IGNORED, } from '../../../common/es_fields'; -import { DataStreamTypes } from '../../types/data_stream'; +import { DataStreamTypes } from '../../types/default_api_types'; import { createDatasetQualityESClient, wildcardQuery } from '../../utils'; export async function getDegradedDocsPaginated(options: { diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/get_integrations.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_integrations.ts new file mode 100644 index 00000000000000..7871571b607b6d --- /dev/null +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/get_integrations.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 { PackageClient } from '@kbn/fleet-plugin/server'; +import { DataStreamStat, Integration } from '../../../common/api_types'; + +export async function getIntegrations(options: { + packageClient: PackageClient; + dataStreams: DataStreamStat[]; +}): Promise { + const { packageClient, dataStreams } = options; + + const packages = await packageClient.getPackages(); + const installedPackages = dataStreams.map((item) => item.integration); + + return Promise.all( + packages + .filter((pkg) => installedPackages.includes(pkg.name)) + .map(async (p) => ({ + name: p.name, + title: p.title, + version: p.version, + icons: p.icons, + datasets: await getDatasets({ + packageClient, + name: p.name, + version: p.version, + }), + })) + ); +} + +const getDatasets = async (options: { + packageClient: PackageClient; + name: string; + version: string; +}) => { + const { packageClient, name, version } = options; + + const pkg = await packageClient.getPackage(name, version); + + return pkg.packageInfo.data_streams?.reduce( + (acc, curr) => ({ + ...acc, + [curr.dataset]: curr.title, + }), + {} + ); +}; diff --git a/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts b/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts index 7be8c102060d6d..4f95331d97651e 100644 --- a/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts +++ b/x-pack/plugins/dataset_quality/server/routes/data_streams/routes.ts @@ -7,20 +7,19 @@ import * as t from 'io-ts'; import { keyBy, merge, values } from 'lodash'; -import { DataStreamStat } from '../../types/data_stream'; -import { dataStreamTypesRt, rangeRt } from '../../types/default_api_types'; -import { Integration } from '../../types/integration'; +import { typeRt, rangeRt } from '../../types/default_api_types'; import { createDatasetQualityServerRoute } from '../create_datasets_quality_server_route'; import { getDataStreams } from './get_data_streams'; import { getDataStreamsStats } from './get_data_streams_stats'; import { getDegradedDocsPaginated } from './get_degraded_docs'; -import { DegradedDocs } from '../../../common/api_types'; +import { DegradedDocs, DataStreamStat, Integration } from '../../../common/api_types'; +import { getIntegrations } from './get_integrations'; const statsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/stats', params: t.type({ query: t.intersection([ - dataStreamTypesRt, + typeRt, t.partial({ datasetQuery: t.string, }), @@ -41,7 +40,6 @@ const statsRoute = createDatasetQualityServerRoute({ const fleetPluginStart = await plugins.fleet.start(); const packageClient = fleetPluginStart.packageService.asInternalUser; - const packages = await packageClient.getPackages(); const [dataStreams, dataStreamsStats] = await Promise.all([ getDataStreams({ @@ -52,22 +50,11 @@ const statsRoute = createDatasetQualityServerRoute({ getDataStreamsStats({ esClient, ...params.query }), ]); - const installedPackages = dataStreams.items.map((item) => item.integration); - - const integrations = packages - .filter((pkg) => installedPackages.includes(pkg.name)) - .map((p) => ({ - name: p.name, - title: p.title, - version: p.version, - icons: p.icons, - })); - return { dataStreamsStats: values( merge(keyBy(dataStreams.items, 'name'), keyBy(dataStreamsStats.items, 'name')) ), - integrations, + integrations: await getIntegrations({ packageClient, dataStreams: dataStreams.items }), }; }, }); @@ -77,7 +64,7 @@ const degradedDocsRoute = createDatasetQualityServerRoute({ params: t.type({ query: t.intersection([ rangeRt, - dataStreamTypesRt, + typeRt, t.partial({ datasetQuery: t.string, }), diff --git a/x-pack/plugins/dataset_quality/server/types/data_stream.ts b/x-pack/plugins/dataset_quality/server/types/data_stream.ts deleted file mode 100644 index 1ccac8199a8b67..00000000000000 --- a/x-pack/plugins/dataset_quality/server/types/data_stream.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. - */ - -import { ByteSize } from '@elastic/elasticsearch/lib/api/types'; -import { Integration } from './integration'; -export interface DataStreamStat { - name: string; - size?: ByteSize; - size_bytes?: number; - last_activity?: number; - integration?: Integration; -} - -export type DataStreamTypes = 'logs' | 'metrics' | 'traces' | 'synthetics' | 'profiling'; diff --git a/x-pack/plugins/dataset_quality/server/types/default_api_types.ts b/x-pack/plugins/dataset_quality/server/types/default_api_types.ts index e36bb1e58f65a2..6148832dad140b 100644 --- a/x-pack/plugins/dataset_quality/server/types/default_api_types.ts +++ b/x-pack/plugins/dataset_quality/server/types/default_api_types.ts @@ -8,16 +8,21 @@ import * as t from 'io-ts'; import { isoToEpochRt } from '@kbn/io-ts-utils'; -export const dataStreamTypesRt = t.partial({ - type: t.union([ - t.literal('logs'), - t.literal('metrics'), - t.literal('traces'), - t.literal('synthetics'), - t.literal('profiling'), - ]), +// https://github.com/gcanti/io-ts/blob/master/index.md#union-of-string-literals +export const dataStreamTypesRt = t.keyof({ + logs: null, + metrics: null, + traces: null, + synthetics: null, + profiling: null, }); +export const typeRt = t.partial({ + type: dataStreamTypesRt, +}); + +export type DataStreamTypes = t.TypeOf; + export const rangeRt = t.type({ start: isoToEpochRt, end: isoToEpochRt, diff --git a/x-pack/plugins/dataset_quality/tsconfig.json b/x-pack/plugins/dataset_quality/tsconfig.json index 5d1bf785b81adc..65f77bac100aa7 100644 --- a/x-pack/plugins/dataset_quality/tsconfig.json +++ b/x-pack/plugins/dataset_quality/tsconfig.json @@ -25,7 +25,9 @@ "@kbn/field-types", "@kbn/io-ts-utils", "@kbn/observability-plugin", - "@kbn/es-types" + "@kbn/es-types", + "@kbn/deeplinks-observability", + "@kbn/router-utils", ], "exclude": [ "target/**/*", 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 6fb1e2b873eb9e..b5b87aa7e2bc32 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 @@ -116,7 +116,7 @@ export const Connectors: React.FC = ({ isCrawler }) => { > {i18n.translate( 'xpack.enterpriseSearch.connectors.newConnectorsClientButtonLabel', - { defaultMessage: 'New Connectors Client' } + { defaultMessage: 'New Connector Client' } )} , ] diff --git a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts index 1062356a5dbebc..8807eabe14da78 100644 --- a/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts +++ b/x-pack/plugins/enterprise_search/server/lib/ml/fetch_ml_models.ts @@ -6,6 +6,7 @@ */ import { MlTrainedModelConfig, MlTrainedModelStats } from '@elastic/elasticsearch/lib/api/types'; +import { i18n } from '@kbn/i18n'; import { MlTrainedModels } from '@kbn/ml-plugin/server'; import { MlModelDeploymentState, MlModel } from '../../../common/types/ml'; @@ -207,7 +208,9 @@ const getUserFriendlyTitle = (modelId: string, modelType: string) => { return MODEL_TITLES_BY_TYPE[modelType] !== undefined ? MODEL_TITLES_BY_TYPE[modelType]! : modelId === LANG_IDENT_MODEL_ID - ? 'Lanugage Identification' + ? i18n.translate('xpack.enterpriseSearch.content.ml_inference.lang_ident', { + defaultMessage: 'Language Identification', + }) : modelId; }; diff --git a/x-pack/plugins/exploratory_view/e2e/journeys/step_duration.journey.ts b/x-pack/plugins/exploratory_view/e2e/journeys/step_duration.journey.ts index a109740d74496f..86291929afcc3f 100644 --- a/x-pack/plugins/exploratory_view/e2e/journeys/step_duration.journey.ts +++ b/x-pack/plugins/exploratory_view/e2e/journeys/step_duration.journey.ts @@ -59,9 +59,7 @@ journey('Step Duration series', async ({ page, params }) => { await page.click(byTestId('seriesBreakdown')); await page.click('button[role="option"]:has-text("Step name")'); await page.click('.euiComboBox__inputWrap'); - await page.click( - 'text=Search Monitor nameCombo box. Selected. Combo box input. Search Monitor name. Ty' - ); + await page.click('[role="combobox"][placeholder="Search Monitor name"]'); await page.click('button[role="option"]:has-text("test-monitor - inline")'); await page.click('button:has-text("Apply changes")'); }); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.test.tsx index 5f451e6e7c86b4..e8f6ee48dc206e 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.test.tsx @@ -11,12 +11,14 @@ import { DataViewState } from '../hooks/use_app_data_view'; import { render } from '../rtl_helpers'; import { AddToCaseAction } from '../header/add_to_case_action'; import { ActionTypes } from './use_actions'; +import * as lensHook from './use_embeddable_attributes'; jest.mock('../header/add_to_case_action', () => ({ AddToCaseAction: jest.fn(() =>
mockAddToCaseAction
), })); const mockLensAttrs = { + title: '', hidePanelTitles: true, description: '', visualizationType: 'lnsMetric', @@ -102,17 +104,19 @@ describe('Embeddable', () => { jest.clearAllMocks(); }); + jest.spyOn(lensHook, 'useEmbeddableAttributes').mockReturnValue(mockLensAttrs as any); + it('renders title', async () => { const { container, getByText } = render( ); expect(container.querySelector(`[data-test-subj="exploratoryView-title"]`)).toBeInTheDocument(); @@ -123,12 +127,12 @@ describe('Embeddable', () => { const { container } = render( ); expect( @@ -140,12 +144,12 @@ describe('Embeddable', () => { const { container } = render( ); @@ -174,13 +178,13 @@ describe('Embeddable', () => { render( ); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx index c3405225b2e018..ed06d786124f39 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/embeddable/embeddable.tsx @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { i18n } from '@kbn/i18n'; import { Position } from '@elastic/charts'; import React, { useState } from 'react'; @@ -17,28 +18,22 @@ import { import { ViewMode } from '@kbn/embeddable-plugin/common'; import { observabilityFeatureId } from '@kbn/observability-shared-plugin/public'; import styled from 'styled-components'; -import { useTheme, useKibanaSpace } from '@kbn/observability-shared-plugin/public'; -import { HeatMapLensAttributes } from '../configurations/lens_attributes/heatmap_attributes'; -import { SingleMetricLensAttributes } from '../configurations/lens_attributes/single_metric_attributes'; -import { AllSeries, ReportTypes } from '../../../..'; -import { LayerConfig, LensAttributes } from '../configurations/lens_attributes'; +import { AllSeries } from '../../../..'; import { AppDataType, ReportViewType } from '../types'; -import { getLayerConfigs } from '../hooks/use_lens_attributes'; import { OperationTypeComponent } from '../series_editor/columns/operation_type_select'; import { DataViewState } from '../hooks/use_app_data_view'; import { ReportConfigMap } from '../contexts/exploratory_view_config'; -import { obsvReportConfigMap } from '../obsv_exploratory_view'; import { ActionTypes, useActions } from './use_actions'; import { AddToCaseAction } from '../header/add_to_case_action'; +import { useEmbeddableAttributes } from './use_embeddable_attributes'; export interface ExploratoryEmbeddableProps { id?: string; appendTitle?: JSX.Element; - attributes?: AllSeries; + attributes: AllSeries; axisTitlesVisibility?: XYState['axisTitlesVisibilitySettings']; gridlinesVisibilitySettings?: XYState['gridlinesVisibilitySettings']; customHeight?: string; - customLensAttrs?: any; // Takes LensAttributes customTimeRange?: { from: string; to: string }; // required if rendered with LensAttributes dataTypesIndexPatterns?: Partial>; isSingleMetric?: boolean; @@ -69,77 +64,42 @@ export interface ExploratoryEmbeddableComponentProps extends ExploratoryEmbeddab } // eslint-disable-next-line import/no-default-export -export default function Embeddable({ - appendTitle, - attributes = [], - axisTitlesVisibility, - gridlinesVisibilitySettings, - customHeight, - customLensAttrs, - customTimeRange, - dataViewState, - legendIsVisible, - legendPosition, - lens, - onBrushEnd, - caseOwner = observabilityFeatureId, - reportConfigMap = {}, - reportType, - showCalculationMethod = false, - title, - withActions = true, - lensFormulaHelper, - hideTicks, - align, - noLabel, - fontSize = 27, - lineHeight = 32, - searchSessionId, - onLoad, -}: ExploratoryEmbeddableComponentProps) { +export default function Embeddable(props: ExploratoryEmbeddableComponentProps) { + const { + appendTitle, + attributes = [], + axisTitlesVisibility, + gridlinesVisibilitySettings, + customHeight, + customTimeRange, + legendIsVisible, + legendPosition, + lens, + onBrushEnd, + caseOwner = observabilityFeatureId, + reportType, + showCalculationMethod = false, + title, + withActions = true, + hideTicks, + align, + noLabel, + fontSize = 27, + lineHeight = 32, + searchSessionId, + onLoad, + } = props; const LensComponent = lens?.EmbeddableComponent; const LensSaveModalComponent = lens?.SaveModalComponent; const [isSaveOpen, setIsSaveOpen] = useState(false); const [isAddToCaseOpen, setAddToCaseOpen] = useState(false); - const spaceId = useKibanaSpace(); - const series = Object.entries(attributes)[0]?.[1]; const [operationType, setOperationType] = useState(series?.operationType); - const theme = useTheme(); - - const layerConfigs: LayerConfig[] = getLayerConfigs( - attributes, - reportType, - theme, - dataViewState, - { ...reportConfigMap, ...obsvReportConfigMap }, - spaceId.space?.id - ); - let lensAttributes; - let attributesJSON = customLensAttrs; - if (!customLensAttrs) { - try { - if (reportType === ReportTypes.SINGLE_METRIC) { - lensAttributes = new SingleMetricLensAttributes( - layerConfigs, - reportType, - lensFormulaHelper! - ); - attributesJSON = lensAttributes?.getJSON('lnsLegacyMetric'); - } else if (reportType === ReportTypes.HEATMAP) { - lensAttributes = new HeatMapLensAttributes(layerConfigs, reportType, lensFormulaHelper!); - attributesJSON = lensAttributes?.getJSON('lnsHeatmap'); - } else { - lensAttributes = new LensAttributes(layerConfigs, reportType, lensFormulaHelper); - attributesJSON = lensAttributes?.getJSON(); - } - // eslint-disable-next-line no-empty - } catch (error) {} - } + const attributesJSON = useEmbeddableAttributes(props); const timeRange = customTimeRange ?? series?.time; @@ -182,17 +142,20 @@ export default function Embeddable({ }; } - if (!attributesJSON && layerConfigs.length < 1) { + if (!attributesJSON) { return null; } if (!LensComponent) { - return No lens component; + return ( + + {i18n.translate('xpack.exploratoryView.embeddable.noLensComponentTextLabel', { + defaultMessage: 'No lens component', + })} + + ); } - attributesJSON.state.searchSessionId = searchSessionId; - attributesJSON.searchSessionId = searchSessionId; - return ( { + const spaceId = useKibanaSpace(); + const theme = useTheme(); + + return useMemo(() => { + try { + const layerConfigs: LayerConfig[] = getLayerConfigs( + attributes, + reportType, + theme, + dataViewState, + { ...reportConfigMap, ...obsvReportConfigMap }, + spaceId.space?.id + ); + + if (reportType === ReportTypes.SINGLE_METRIC) { + const lensAttributes = new SingleMetricLensAttributes( + layerConfigs, + reportType, + lensFormulaHelper! + ); + return lensAttributes?.getJSON('lnsLegacyMetric'); + } else if (reportType === ReportTypes.HEATMAP) { + const lensAttributes = new HeatMapLensAttributes( + layerConfigs, + reportType, + lensFormulaHelper! + ); + return lensAttributes?.getJSON('lnsHeatmap'); + } else { + const lensAttributes = new LensAttributes(layerConfigs, reportType, lensFormulaHelper); + return lensAttributes?.getJSON(); + } + } catch (error) { + console.error(error); + } + }, [ + attributes, + dataViewState, + lensFormulaHelper, + reportConfigMap, + reportType, + spaceId.space?.id, + theme, + ]); +}; diff --git a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/series_editor/columns/report_definition_col.test.tsx b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/series_editor/columns/report_definition_col.test.tsx index 980c02a0ab1531..17f62937812ee0 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/series_editor/columns/report_definition_col.test.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/exploratory_view/series_editor/columns/report_definition_col.test.tsx @@ -39,7 +39,7 @@ describe('Series Builder ReportDefinitionCol', function () { await waitFor(() => { expect(screen.getByText('Web Application')).toBeInTheDocument(); expect(screen.getByText('Environment')).toBeInTheDocument(); - expect(screen.getByText('Search Environment')).toBeInTheDocument(); + expect(screen.getByPlaceholderText('Search Environment')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/exploratory_view/public/components/shared/field_value_suggestions/field_value_selection.tsx b/x-pack/plugins/exploratory_view/public/components/shared/field_value_suggestions/field_value_selection.tsx index 888033d8183cd7..4cf81e2a9976d7 100644 --- a/x-pack/plugins/exploratory_view/public/components/shared/field_value_suggestions/field_value_selection.tsx +++ b/x-pack/plugins/exploratory_view/public/components/shared/field_value_suggestions/field_value_selection.tsx @@ -175,7 +175,7 @@ export function FieldValueSelection({ isOpen={isPopoverOpen || forceOpen} closePopover={closePopover} anchorPosition={anchorPosition} - style={{ width: '100%' }} + display="block" > - p.package?.name === FLEET_APM_PACKAGE || p.package?.name === FLEET_SERVER_PACKAGE || - p.package?.name === FLEET_SYNTHETICS_PACKAGE + p.package?.name === FLEET_SYNTHETICS_PACKAGE || + p.package?.name === FLEET_APM_PACKAGE ); if (isRestrictedToSameClusterES) { diff --git a/x-pack/plugins/fleet/cypress/e2e/package_policy_pipelines_and_mappings_real.cy.ts b/x-pack/plugins/fleet/cypress/e2e/package_policy_pipelines_and_mappings_real.cy.ts index c1cf0ef4e0b092..6cbf5a881f5d58 100644 --- a/x-pack/plugins/fleet/cypress/e2e/package_policy_pipelines_and_mappings_real.cy.ts +++ b/x-pack/plugins/fleet/cypress/e2e/package_policy_pipelines_and_mappings_real.cy.ts @@ -100,7 +100,7 @@ describe('Input package create and edit package policy', () => { editPackagePolicyandShowAdvanced(INPUT_TEST_PACKAGE, packagePolicyName); cy.getBySel(POLICY_EDITOR.EDIT_MAPPINGS_BTN).click(); cy.getBySel(CONFIRM_MODAL.CONFIRM_BUTTON).click(); - cy.get('body').should('contain', `logs-${datasetName}@custom`); + cy.get('body').should('contain', `logs${datasetName}@custom`); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx index e027317bf621aa..8c2983ee9fd83a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.test.tsx @@ -533,7 +533,7 @@ describe('useOutputOptions', () => { `); }); - it('should only enable remote es output for monitoring output', async () => { + it('should enable remote es output for data and monitoring output', async () => { const testRenderer = createFleetTestRendererMock(); mockedUseLicence.mockReturnValue({ hasAtLeast: () => true, @@ -545,7 +545,8 @@ describe('useOutputOptions', () => { expect(result.current.isLoading).toBeTruthy(); await waitForNextUpdate(); - expect(result.current.dataOutputOptions.length).toEqual(1); + expect(result.current.dataOutputOptions.length).toEqual(2); + expect(result.current.dataOutputOptions[1].value).toEqual('remote1'); expect(result.current.monitoringOutputOptions.length).toEqual(2); expect(result.current.monitoringOutputOptions[1].value).toEqual('remote1'); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.tsx index 9ee8b1f2257353..15681ea1dfbb66 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/hooks.tsx @@ -16,7 +16,7 @@ import { useGetDownloadSources, useGetFleetServerHosts, } from '../../../../hooks'; -import { LICENCE_FOR_PER_POLICY_OUTPUT, outputType } from '../../../../../../../common/constants'; +import { LICENCE_FOR_PER_POLICY_OUTPUT } from '../../../../../../../common/constants'; import { getAllowedOutputTypeForPolicy, policyHasFleetServer, @@ -99,28 +99,26 @@ export function useOutputOptions(agentPolicy: Partial item.type !== outputType.RemoteElasticsearch) - .map((item) => { - const isOutputTypeUnsupported = !allowedOutputTypes.includes(item.type); + ...outputsRequest.data.items.map((item) => { + const isOutputTypeUnsupported = !allowedOutputTypes.includes(item.type); - return { - value: item.id, - inputDisplay: getOutputLabel( - item.name, - isOutputTypeUnsupported ? ( - - ) : undefined - ), - disabled: !isPolicyPerOutputAllowed || isOutputTypeUnsupported, - }; - }), + return { + value: item.id, + inputDisplay: getOutputLabel( + item.name, + isOutputTypeUnsupported ? ( + + ) : undefined + ), + disabled: !isPolicyPerOutputAllowed || isOutputTypeUnsupported, + }; + }), ]; }, [outputsRequest, isPolicyPerOutputAllowed, allowedOutputTypes]); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx index 7850ae3a3128d8..1a18b6e27f5ebc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { act, fireEvent, waitFor } from '@testing-library/react'; +import { act, fireEvent, waitFor, within } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../../../../../mock'; @@ -54,8 +54,9 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 3, }); - const el = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); - expect(el?.textContent).toBe('Immediately'); + const container = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); + const input = within(container).getByRole('combobox'); + expect(input?.value).toBe('Immediately'); }); it('should set the default to Immediately if there is less than 10 agents using selected agents', async () => { @@ -64,8 +65,9 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 3, }); - const el = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); - expect(el?.textContent).toBe('Immediately'); + const container = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); + const input = within(container).getByRole('combobox'); + expect(input?.value).toBe('Immediately'); }); it('should set the default to 1 hour if there is more than 10 agents', async () => { @@ -74,8 +76,9 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 13, }); - const el = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); - expect(el?.textContent).toBe('1 hour'); + const container = utils.getByTestId('agentUpgradeModal.MaintenanceCombobox'); + const input = within(container).getByRole('combobox'); + expect(input?.value).toBe('1 hour'); }); }); @@ -98,9 +101,11 @@ describe('AgentUpgradeAgentModal', () => { agentCount: 1, }); - const el = utils.getByTestId('agentUpgradeModal.VersionCombobox'); + const container = utils.getByTestId('agentUpgradeModal.VersionCombobox'); + const input = within(container).getByRole('combobox'); + await waitFor(() => { - expect(el.textContent).toEqual('8.10.2'); + expect(input?.value).toEqual('8.10.2'); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx index 511af850cab46d..daebac615d6eb5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/index.tsx @@ -542,7 +542,6 @@ export const EditOutputFlyout: React.FunctionComponent = }} /> } - disabled={isRemoteESOutput} /> diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx index 0e85390a4b3274..214ce24463e547 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/components/package_list_grid/grid.tsx @@ -125,8 +125,7 @@ export const GridColumn = ({ // Ensure that cards wrapped in EuiTours/EuiPopovers correctly inherit the full grid row height css={css` & > .euiPopover, - & > .euiPopover > .euiPopover__anchor, - & > .euiPopover > .euiPopover__anchor > .euiCard { + & > .euiPopover > .euiCard { height: 100%; } `} diff --git a/x-pack/plugins/fleet/server/routes/uninstall_token/handlers.ts b/x-pack/plugins/fleet/server/routes/uninstall_token/handlers.ts index 804b90ab1aa2f1..50dc1263ddf07c 100644 --- a/x-pack/plugins/fleet/server/routes/uninstall_token/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/uninstall_token/handlers.ts @@ -34,7 +34,12 @@ export const getUninstallTokensMetadataHandler: FleetRequestHandler< try { const { page = 1, perPage = 20, policyId } = request.query; - const body = await uninstallTokenService.getTokenMetadata(policyId?.trim(), page, perPage); + const body = await uninstallTokenService.getTokenMetadata( + policyId?.trim(), + page, + perPage, + 'policy-elastic-agent-on-cloud' + ); return response.ok({ body }); } catch (error) { diff --git a/x-pack/plugins/fleet/server/services/output.test.ts b/x-pack/plugins/fleet/server/services/output.test.ts index c17cf9d3af210f..8c2fee196d8d81 100644 --- a/x-pack/plugins/fleet/server/services/output.test.ts +++ b/x-pack/plugins/fleet/server/services/output.test.ts @@ -705,12 +705,12 @@ describe('Output Service', () => { ); }); - it('should throw when a remote es output is attempted to be created as default data output', async () => { + it('should not throw when a remote es output is attempted to be created as default data output', async () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - await expect( + expect( outputService.create( soClient, esClientMock, @@ -722,9 +722,7 @@ describe('Output Service', () => { }, { id: 'output-1' } ) - ).rejects.toThrow( - `Remote elasticsearch output cannot be set as default output for integration data. Please set "is_default" to false.` - ); + ).resolves.not.toThrow(); }); it('should set preset: balanced by default when creating a new ES output', async () => { @@ -1644,21 +1642,19 @@ describe('Output Service', () => { ); }); - it('should throw when a remote es output is attempted to be updated as default data output', async () => { + it('should not throw when a remote es output is attempted to be updated as default data output', async () => { const soClient = getMockedSoClient({ defaultOutputId: 'output-test', }); - await expect( + expect( outputService.update(soClient, esClientMock, 'output-test', { is_default: true, is_default_monitoring: false, name: 'Test', type: 'remote_elasticsearch', }) - ).rejects.toThrow( - `Remote elasticsearch output cannot be set as default output for integration data. Please set "is_default" to false.` - ); + ).resolves.not.toThrow(); }); }); diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index 7b838d9b9b0a53..e73a070a54965f 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -441,13 +441,6 @@ class OutputService { logger.debug(`Creating new output`); const data: OutputSOAttributes = { ...omit(output, ['ssl', 'secrets']) }; - if (output.type === outputType.RemoteElasticsearch) { - if (data.is_default) { - throw new OutputInvalidError( - 'Remote elasticsearch output cannot be set as default output for integration data. Please set "is_default" to false.' - ); - } - } if (outputTypeSupportPresets(data.type)) { if ( @@ -767,14 +760,6 @@ class OutputService { const logger = appContextService.getLogger(); logger.debug(`Updating output ${id}`); - if (data.type === outputType.RemoteElasticsearch) { - if (data.is_default) { - throw new OutputInvalidError( - 'Remote elasticsearch output cannot be set as default output for integration data. Please set "is_default" to false.' - ); - } - } - let secretsToDelete: PolicySecretReference[] = []; const originalOutput = await this.get(soClient, id); diff --git a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts index 7a2bdedffcdc8c..330007e23963d1 100644 --- a/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts +++ b/x-pack/plugins/fleet/server/services/security/uninstall_token_service/index.ts @@ -25,7 +25,10 @@ import type { KibanaRequest } from '@kbn/core-http-server'; import { SECURITY_EXTENSION_ID } from '@kbn/core-saved-objects-server'; import { asyncForEach } from '@kbn/std'; -import type { AggregationsTermsInclude } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import type { + AggregationsTermsInclude, + AggregationsTermsExclude, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { UninstallTokenError } from '../../../../common/errors'; @@ -74,12 +77,14 @@ export interface UninstallTokenServiceInterface { * @param policyIdFilter a string for partial matching the policyId * @param page * @param perPage + * @param policyIdExcludeFilter * @returns Uninstall Tokens Metadata Response */ getTokenMetadata( policyIdFilter?: string, page?: number, - perPage?: number + perPage?: number, + policyIdExcludeFilter?: string ): Promise; /** @@ -170,11 +175,15 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { public async getTokenMetadata( policyIdFilter?: string, page = 1, - perPage = 20 + perPage = 20, + policyIdExcludeFilter?: string ): Promise { const includeFilter = policyIdFilter ? `.*${policyIdFilter}.*` : undefined; - const tokenObjects = await this.getTokenObjectsByIncludeFilter(includeFilter); + const tokenObjects = await this.getTokenObjectsByIncludeFilter( + includeFilter, + policyIdExcludeFilter + ); const items: UninstallTokenMetadata[] = tokenObjects .slice((page - 1) * perPage, page * perPage) @@ -250,7 +259,8 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { }; private async getTokenObjectsByIncludeFilter( - include?: AggregationsTermsInclude + include?: AggregationsTermsInclude, + exclude?: AggregationsTermsExclude ): Promise>> { const bucketSize = 10000; @@ -263,7 +273,7 @@ export class UninstallTokenService implements UninstallTokenServiceInterface { field: `${UNINSTALL_TOKENS_SAVED_OBJECT_TYPE}.attributes.policy_id`, size: bucketSize, include, - exclude: 'policy-elastic-agent-on-cloud', // todo: find a better way to not return or even generate token for managed policies + exclude, }, aggs: { latest: { diff --git a/x-pack/plugins/index_lifecycle_management/integration_tests/helpers/actions/toggle_phase_action.ts b/x-pack/plugins/index_lifecycle_management/integration_tests/helpers/actions/toggle_phase_action.ts index fc89332e47a67c..7af36c2fb4f1d5 100644 --- a/x-pack/plugins/index_lifecycle_management/integration_tests/helpers/actions/toggle_phase_action.ts +++ b/x-pack/plugins/index_lifecycle_management/integration_tests/helpers/actions/toggle_phase_action.ts @@ -27,7 +27,7 @@ const toggleDeletePhase = async (testBed: TestBed) => { if (action === 'disable') { button.simulate('click'); } else { - button.find('input').simulate('change'); + button.find('button').simulate('click'); } }); component.update(); 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 fd373efb6d17da..367437e5c5346e 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 @@ -100,14 +100,10 @@ describe('', () => { httpRequestsMockHelpers.setLoadComponentTemplatesResponse(componentTemplates); httpRequestsMockHelpers.setLoadNodesPluginsResponse([]); - - // disable all react-beautiful-dnd development warnings - (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = true; }); afterAll(() => { jest.useRealTimers(); - (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = false; }); describe('composable index template', () => { @@ -533,11 +529,6 @@ describe('', () => { name: TEMPLATE_NAME, indexPatterns: DEFAULT_INDEX_PATTERNS, dataStream: {}, - lifecycle: { - enabled: true, - value: 1, - unit: 'd', - }, allowAutoCreate: true, }); // Component templates @@ -551,13 +542,14 @@ describe('', () => { }); it('should send the correct payload', async () => { - const { actions, find } = testBed; + const { component, actions, find } = testBed; expect(find('stepTitle').text()).toEqual(`Review details for '${TEMPLATE_NAME}'`); await act(async () => { actions.clickNextButton(); }); + component.update(); expect(httpSetup.post).toHaveBeenLastCalledWith( `${API_BASE_PATH}/index_templates`, @@ -589,10 +581,6 @@ describe('', () => { }, }, aliases: ALIASES, - lifecycle: { - enabled: true, - data_retention: '1d', - }, }, }), }) @@ -620,44 +608,59 @@ describe('', () => { }); }); - test('preview data stream', async () => { - await act(async () => { - testBed = await setup(httpSetup); - }); - testBed.component.update(); - - const { actions } = testBed; - // Logistics - await actions.completeStepOne({ - name: TEMPLATE_NAME, - indexPatterns: DEFAULT_INDEX_PATTERNS, - dataStream: {}, - lifecycle: { - enabled: true, - value: 1, - unit: 'd', - }, + describe('DSL', () => { + beforeEach(async () => { + await act(async () => { + testBed = await setup(httpSetup); + }); + testBed.component.update(); + + await testBed.actions.completeStepOne({ + name: TEMPLATE_NAME, + indexPatterns: DEFAULT_INDEX_PATTERNS, + dataStream: {}, + lifecycle: { + enabled: true, + value: 1, + unit: 'd', + }, + }); }); - await act(async () => { - await actions.previewTemplate(); + test('should include DSL in summary when set in step 1', async () => { + const { find, component } = testBed; + + await act(async () => { + testBed.find('formWizardStep-5').simulate('click'); + }); + component.update(); + + expect(find('lifecycleValue').text()).toContain('1 day'); }); - expect(httpSetup.post).toHaveBeenLastCalledWith( - `${API_BASE_PATH}/index_templates/simulate`, - expect.objectContaining({ - body: JSON.stringify({ - template: { - lifecycle: { - enabled: true, - data_retention: '1d', + test('preview data stream', async () => { + const { actions } = testBed; + + await act(async () => { + await actions.previewTemplate(); + }); + + expect(httpSetup.post).toHaveBeenLastCalledWith( + `${API_BASE_PATH}/index_templates/simulate`, + expect.objectContaining({ + body: JSON.stringify({ + template: { + lifecycle: { + enabled: true, + data_retention: '1d', + }, }, - }, - index_patterns: DEFAULT_INDEX_PATTERNS, - data_stream: {}, - allow_auto_create: false, - }), - }) - ); + index_patterns: DEFAULT_INDEX_PATTERNS, + data_stream: {}, + allow_auto_create: false, + }), + }) + ); + }); }); }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts index 8b98fb769959f6..88cee63b0e693c 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_form.helpers.ts @@ -185,27 +185,24 @@ export const formSetup = async (initTestBed: SetupFunc) => { if (version) { form.setInputValue('versionField.input', JSON.stringify(version)); } + + if (allowAutoCreate) { + form.toggleEuiSwitch('allowAutoCreateField.input'); + } }); component.update(); if (lifecycle && lifecycle.enabled) { - act(() => { + await act(async () => { form.toggleEuiSwitch('dataRetentionToggle.input'); }); component.update(); - act(() => { - form.setInputValue('valueDataRetentionField', String(lifecycle.value)); - }); + form.setInputValue('valueDataRetentionField', String(lifecycle.value)); } await act(async () => { - if (allowAutoCreate) { - form.toggleEuiSwitch('allowAutoCreateField.input'); - } - clickNextButton(); - jest.advanceTimersByTime(0); }); component.update(); @@ -378,6 +375,8 @@ export type TestSubjects = | 'settingsEditor' | 'versionField.input' | 'valueDataRetentionField' + | 'formWizardStep-5' + | 'lifecycleValue' | 'mappingsEditor.formTab' | 'mappingsEditor.advancedConfiguration.sizeEnabledToggle' | 'previewIndexTemplate'; diff --git a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx index 04a5a4a20f491f..fa4efa61bf548b 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/data_stream_list/data_stream_list.tsx @@ -128,7 +128,7 @@ export const DataStreamList: React.FunctionComponent { searchCriteria.dateRange.from, searchCriteria.dateRange.to, ]), - parseResponses: normalizeDataSearchResponse, + parseResponses: useMemo( + () => + normalizeDataSearchResponse({ + telemetry, + telemetryData: { + withQuery: !!searchCriteria.query.query, + withFilters: + searchCriteria.filters.length > 0 || searchCriteria.panelFilters.length > 0, + }, + }), + [ + searchCriteria.filters.length, + searchCriteria.panelFilters.length, + searchCriteria.query.query, + telemetry, + ] + ), }); const { isRequestRunning, isResponsePartial, latestResponseData, latestResponseErrors } = @@ -89,14 +106,6 @@ export const useHostCount = () => { fetchHostCount(); }, [fetchHostCount]); - useEffect(() => { - if (latestResponseData) { - telemetry.reportHostsViewTotalHostCountRetrieved({ - total: latestResponseData.count.value, - }); - } - }, [latestResponseData, telemetry]); - return { errors: latestResponseErrors, isRequestRunning, @@ -116,27 +125,42 @@ const INITIAL_STATE = { loaded: 0, total: undefined, }; -const normalizeDataSearchResponse = ( - response$: Observable>>> -) => - response$.pipe( - map((response) => ({ - data: decodeOrThrow(HostCountResponseRT)(response.rawResponse.aggregations), - errors: [], - isPartial: response.isPartial ?? false, - isRunning: response.isRunning ?? false, - loaded: response.loaded, - total: response.total, - })), - startWith(INITIAL_STATE), - catchError((error) => - of({ - ...INITIAL_STATE, - errors: [error.message ?? error], - isRunning: false, - }) - ) - ); + +const normalizeDataSearchResponse = + ({ + telemetry, + telemetryData, + }: { + telemetry: ITelemetryClient; + telemetryData: { withQuery: boolean; withFilters: boolean }; + }) => + (response$: Observable>>>) => { + return response$.pipe( + map((response) => ({ + data: decodeOrThrow(HostCountResponseRT)(response.rawResponse.aggregations), + errors: [], + isPartial: response.isPartial ?? false, + isRunning: response.isRunning ?? false, + loaded: response.loaded, + total: response.total, + })), + tap(({ data }) => { + telemetry.reportHostsViewTotalHostCountRetrieved({ + total: data.count.value, + with_query: telemetryData.withQuery, + with_filters: telemetryData.withFilters, + }); + }), + startWith(INITIAL_STATE), + catchError((error) => + of({ + ...INITIAL_STATE, + errors: [error.message ?? error], + isRunning: false, + }) + ) + ); + }; const HostCountResponseRT = rt.type({ count: rt.type({ diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts index 6ce2d2b8276234..b83cbfe262e637 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_events.ts @@ -109,6 +109,20 @@ const hostViewTotalHostCountRetrieved: InfraTelemetryEvent = { optional: false, }, }, + with_query: { + type: 'boolean', + _meta: { + description: 'Has KQL query', + optional: false, + }, + }, + with_filters: { + type: 'boolean', + _meta: { + description: 'Has filters', + optional: false, + }, + }, }, }; diff --git a/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts index ac450df7dd1628..3fa8a9b447111e 100644 --- a/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/infra/public/services/telemetry/telemetry_service.test.ts @@ -172,6 +172,8 @@ describe('TelemetryService', () => { telemetry.reportHostsViewTotalHostCountRetrieved({ total: 300, + with_filters: true, + with_query: false, }); expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); @@ -179,6 +181,8 @@ describe('TelemetryService', () => { InfraTelemetryEventTypes.HOST_VIEW_TOTAL_HOST_COUNT_RETRIEVED, { total: 300, + with_filters: true, + with_query: false, } ); }); diff --git a/x-pack/plugins/infra/public/services/telemetry/types.ts b/x-pack/plugins/infra/public/services/telemetry/types.ts index 3b1665078ee3a4..769cc303def50e 100644 --- a/x-pack/plugins/infra/public/services/telemetry/types.ts +++ b/x-pack/plugins/infra/public/services/telemetry/types.ts @@ -41,6 +41,8 @@ export interface HostFlyoutFilterActionParams { export interface HostsViewQueryHostsCountRetrievedParams { total: number; + with_query: boolean; + with_filters: boolean; } export interface AssetDetailsFlyoutViewedParams { diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx index 9102d2b5e307f0..3698d07018c712 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/test_pipeline.test.tsx @@ -377,7 +377,9 @@ describe('Test pipeline', () => { // Click the "Configuration" tab await actions.clickProcessorConfigurationTab(); // Verify type selector has not changed - expect(find('processorTypeSelector.input').text()).toBe('Set'); + expect(find('processorTypeSelector.input').find('[role="combobox"]').props().value).toBe( + 'Set' + ); }); }); diff --git a/x-pack/plugins/kubernetes_security/public/components/tree_view_container/tree_nav/index.test.tsx b/x-pack/plugins/kubernetes_security/public/components/tree_view_container/tree_nav/index.test.tsx index 554f34325016f0..155f4236f81072 100644 --- a/x-pack/plugins/kubernetes_security/public/components/tree_view_container/tree_nav/index.test.tsx +++ b/x-pack/plugins/kubernetes_security/public/components/tree_view_container/tree_nav/index.test.tsx @@ -40,24 +40,26 @@ describe('TreeNav component', () => { it('mount with Logical View selected by default', async () => { renderResult = mockedContext.render(); - const elemLabel = await renderResult.getByDisplayValue(/logical/i); - expect(elemLabel).toBeChecked(); + const elemLabel = await renderResult.getByTestId('treeNavType_generated-idlogical'); + expect(elemLabel).toHaveAttribute('aria-pressed', 'true'); }); it('shows the tree path according with the selected view type', async () => { renderResult = mockedContext.render(); const logicalViewPath = 'cluster / namespace / pod / container image'; - const logicViewRadio = await renderResult.getByDisplayValue(/logical/i); - expect(logicViewRadio).toBeChecked(); + const logicViewButton = renderResult.getByTestId('treeNavType_generated-idlogical'); + expect(logicViewButton).toHaveAttribute('aria-pressed', 'true'); expect(renderResult.getByText(logicalViewPath)).toBeInTheDocument(); - const infraStructureViewRadio = await renderResult.getByDisplayValue(/infrastructure/i); + const infraStructureViewRadio = renderResult.getByTestId( + 'treeNavType_generated-idinfrastructure' + ); infraStructureViewRadio.click(); expect(renderResult.getByText('cluster / node / pod / container image')).toBeInTheDocument(); - logicViewRadio.click(); + logicViewButton.click(); expect(renderResult.getByText(logicalViewPath)).toBeInTheDocument(); }); 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 a5de3e7ef8052a..4c361f37029c66 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 @@ -72,11 +72,13 @@ export function LensEditConfigurationFlyout({ const [isLayerAccordionOpen, setIsLayerAccordionOpen] = useState(true); const [isSuggestionsAccordionOpen, setIsSuggestionsAccordionOpen] = useState(false); const datasourceState = attributes.state.datasourceStates[datasourceId]; - const activeVisualization = visualizationMap[attributes.visualizationType]; const activeDatasource = datasourceMap[datasourceId]; const { datasourceStates, visualization, isLoading, annotationGroups } = useLensSelector( (state) => state.lens ); + // use the latest activeId, but fallback to attributes + const activeVisualization = + visualizationMap[visualization.activeId ?? attributes.visualizationType]; const framePublicAPI = useLensSelector((state) => selectFramePublicAPI(state, datasourceMap)); const suggestsLimitedColumns = activeDatasource?.suggestsLimitedColumns?.(datasourceState); diff --git a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filter_popover.tsx b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filter_popover.tsx index 4e3fe6336be9e0..35327fb91b6781 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filter_popover.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filter_popover.tsx @@ -53,7 +53,6 @@ export const FilterPopover = ({ return ( selectFramePublicAPI(state, datasourceMap)); const changesApplied = useLensSelector(selectChangesApplied); // get user's selection from localStorage, this key defines if the suggestions panel will be hidden or not - const initialAccordionStatusValue = - typeof isAccordionOpen !== 'undefined' ? !Boolean(isAccordionOpen) : false; + const initialAccordionStatusValue = isAccordionOpen != null ? !Boolean(isAccordionOpen) : false; const [hideSuggestions, setHideSuggestions] = useLocalStorage( LOCAL_STORAGE_SUGGESTIONS_PANEL, initialAccordionStatusValue ); useEffect(() => { - if (typeof isAccordionOpen !== 'undefined') { + if (isAccordionOpen != null) { setHideSuggestions(!Boolean(isAccordionOpen)); } }, [isAccordionOpen, setHideSuggestions]); diff --git a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx index 9fc42f01a93027..429a681027e634 100644 --- a/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx +++ b/x-pack/plugins/lens/public/visualizations/metric/dimension_editor.test.tsx @@ -245,9 +245,9 @@ describe('dimension editor', () => { userEvent.type(customPrefixTextbox, prefix); }; return { - settingNone: screen.getByLabelText(/none/i), - settingAuto: screen.getByLabelText(/auto/i), - settingCustom: screen.getByLabelText(/custom/i), + settingNone: screen.getByTitle(/none/i), + settingAuto: screen.getByTitle(/auto/i), + settingCustom: screen.getByTitle(/custom/i), customPrefixTextbox, typePrefix, ...rtlRender, @@ -276,9 +276,9 @@ describe('dimension editor', () => { state: localState, }); - expect(settingAuto).toBeChecked(); - expect(settingNone).not.toBeChecked(); - expect(settingCustom).not.toBeChecked(); + expect(settingAuto).toHaveAttribute('aria-pressed', 'true'); + expect(settingNone).toHaveAttribute('aria-pressed', 'false'); + expect(settingCustom).toHaveAttribute('aria-pressed', 'false'); expect(customPrefixTextbox).not.toBeInTheDocument(); }); @@ -286,9 +286,9 @@ describe('dimension editor', () => { const { settingAuto, settingCustom, settingNone, customPrefixTextbox } = renderSecondaryMetricEditor({ state: { ...localState, secondaryPrefix: NONE_PREFIX } }); - expect(settingNone).toBeChecked(); - expect(settingAuto).not.toBeChecked(); - expect(settingCustom).not.toBeChecked(); + expect(settingNone).toHaveAttribute('aria-pressed', 'true'); + expect(settingAuto).toHaveAttribute('aria-pressed', 'false'); + expect(settingCustom).toHaveAttribute('aria-pressed', 'false'); expect(customPrefixTextbox).not.toBeInTheDocument(); }); @@ -297,9 +297,9 @@ describe('dimension editor', () => { const { settingAuto, settingCustom, settingNone, customPrefixTextbox } = renderSecondaryMetricEditor({ state: customPrefixState }); - expect(settingAuto).not.toBeChecked(); - expect(settingNone).not.toBeChecked(); - expect(settingCustom).toBeChecked(); + expect(settingAuto).toHaveAttribute('aria-pressed', 'false'); + expect(settingNone).toHaveAttribute('aria-pressed', 'false'); + expect(settingCustom).toHaveAttribute('aria-pressed', 'true'); expect(customPrefixTextbox).toHaveValue(customPrefixState.secondaryPrefix); }); @@ -454,11 +454,10 @@ describe('dimension editor', () => { ); const supportingVisOptions = { - none: screen.queryByLabelText(/none/i), + none: screen.queryByTitle(/none/i), // in eui when bar or line become disabled they change from input to button so we have to do this weird check - bar: screen.queryByLabelText(/bar/i) || screen.queryByRole('button', { name: /bar/i }), - trendline: - screen.queryByLabelText(/line/i) || screen.queryByRole('button', { name: /line/i }), + bar: screen.queryByTitle(/bar/i) || screen.queryByRole('button', { name: /bar/i }), + trendline: screen.queryByTitle(/line/i) || screen.queryByRole('button', { name: /line/i }), }; const clickOnSupportingVis = (type: SupportingVisType) => { @@ -472,8 +471,8 @@ describe('dimension editor', () => { return { progressDirectionShowing: screen.queryByTestId('lnsMetric_progress_direction_buttons'), progressOptions: { - vertical: screen.queryByLabelText(/vertical/i), - horizontal: screen.queryByLabelText(/horizontal/i), + vertical: screen.queryByTitle(/vertical/i), + horizontal: screen.queryByTitle(/horizontal/i), }, supportingVisOptions, clickOnSupportingVis, @@ -501,21 +500,21 @@ describe('dimension editor', () => { const { supportingVisOptions } = renderAdditionalSectionEditor({ state: { ...stateWOTrend, showBar: false, maxAccessor: undefined }, }); - expect(supportingVisOptions.none).toBeChecked(); + expect(supportingVisOptions.none).toHaveAttribute('aria-pressed', 'true'); }); it('when `showBar` is true and maximum value is not defined, bar should be selected', () => { const { supportingVisOptions } = renderAdditionalSectionEditor({ state: { ...stateWOTrend, showBar: true }, }); - expect(supportingVisOptions.bar).toBeChecked(); + expect(supportingVisOptions.bar).toHaveAttribute('aria-pressed', 'true'); }); it('when `showBar` is true and trendline is defined, line should be selected', () => { const { supportingVisOptions } = renderAdditionalSectionEditor({ state: metricAccessorState, }); - expect(supportingVisOptions.trendline).toBeChecked(); + expect(supportingVisOptions.trendline).toHaveAttribute('aria-pressed', 'true'); }); it('should enable bar when max dimension exists', () => { @@ -633,10 +632,10 @@ describe('dimension editor', () => { state: metricAccessorState, }); - expect(progressOptions.vertical).toBeChecked(); - expect(progressOptions.horizontal).not.toBeChecked(); + expect(progressOptions.vertical).toHaveAttribute('aria-pressed', 'true'); + expect(progressOptions.horizontal).toHaveAttribute('aria-pressed', 'false'); if (progressOptions.horizontal === null) { - throw new Error('horizontal radio button not found'); + throw new Error('horizontal button not found'); } userEvent.click(progressOptions.horizontal); diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx index 5c2bfb90456889..f6b8bff8c09ab7 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/entry_renderer.test.tsx @@ -264,11 +264,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual('is'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldMatch"]').text()).toEqual( - '1234' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatchLabel"] input').props().value + ).toEqual('1234'); }); test('it renders field values correctly when operator is "isNotOperator"', () => { @@ -299,13 +303,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'is not' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldMatch"]').text()).toEqual( - '1234' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is not'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatchLabel"] input').props().value + ).toEqual('1234'); }); test('it renders field values correctly when operator is "isOneOfOperator"', () => { @@ -336,11 +342,13 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'is one of' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldMatchAny"]').text()).toEqual( + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is one of'); + expect(wrapper.find('[data-test-subj="valuesAutocompleteMatchAny"]').first().text()).toEqual( '1234' ); }); @@ -373,10 +381,12 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'is not one of' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is not one of'); expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldMatchAny"]').text()).toEqual( '1234' ); @@ -411,12 +421,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'is in list' - ); expect( - wrapper.find('[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]').at(1).text() + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is in list'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input').props() + .value ).toEqual('some name'); }); @@ -449,12 +462,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'is not in list' - ); expect( - wrapper.find('[data-test-subj="valuesAutocompleteComboBox listsComboxBox"]').at(1).text() + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is not in list'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteComboBox listsComboxBox"] input').props() + .value ).toEqual('some name'); }); @@ -486,11 +502,16 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'exists' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldExists"]').text()).toEqual('—'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"] input').props().value + ).toEqual('exists'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteComboBox existsComboxBox"] input').props() + .placeholder + ).toEqual('—'); expect( wrapper.find('[data-test-subj="exceptionBuilderEntryFieldExists"] input').props().disabled ).toBeTruthy(); @@ -524,11 +545,16 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('ip'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'does not exist' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldExists"]').text()).toEqual('—'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"] input').props().value + ).toEqual('does not exist'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteComboBox existsComboxBox"] input').props() + .placeholder + ).toEqual('—'); expect( wrapper.find('[data-test-subj="exceptionBuilderEntryFieldExists"] input').props().disabled ).toBeTruthy(); @@ -562,13 +588,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('@tags'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'matches' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldWildcard"]').text()).toEqual( - '1234*' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('@tags'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"] input').props().value + ).toEqual('matches'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').props().value + ).toEqual('1234*'); // doesnt show warning label for non endpoint exception items expect( wrapper.find('[data-test-subj="valuesAutocompleteWildcardLabel"] .euiFormHelpText') @@ -637,13 +665,15 @@ describe('BuilderEntryItem', () => { /> ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').text()).toEqual('@tags'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"]').text()).toEqual( - 'does not match' - ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryFieldWildcard"]').text()).toEqual( - '1234*' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('@tags'); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryOperator"] input').props().value + ).toEqual('does not match'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteWildcard"] input').props().value + ).toEqual('1234*'); }); test('it uses "correspondingKeywordField" if it exists', () => { diff --git a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx index 37262749ce55af..2bb1ebc275b084 100644 --- a/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx +++ b/x-pack/plugins/lists/public/exceptions/components/builder/exception_items_renderer.test.tsx @@ -58,18 +58,20 @@ describe('ExceptionBuilderComponent', () => { ); + // console.log(wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').html()); + expect(wrapper.find('EuiFlexGroup[data-test-subj="exceptionItemEntryContainer"]')).toHaveLength( 1 ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); - expect(wrapper.find('[data-test-subj="valuesAutocompleteMatch"]').at(0).text()).toEqual( - 'Please select a field first...' - ); + expect( + wrapper.find('[data-test-subj="fieldAutocompleteComboBox"] input').props().placeholder + ).toEqual('Search'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').props().placeholder + ).toEqual('Please select a field first...'); }); test('it displays "exceptionListItems" that are passed in', async () => { @@ -103,15 +105,16 @@ describe('ExceptionBuilderComponent', () => { /> ); + expect(wrapper.find('EuiFlexGroup[data-test-subj="exceptionItemEntryContainer"]')).toHaveLength( 1 ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'ip' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is one of' - ); + expect( + wrapper.find('[data-test-subj="fieldAutocompleteComboBox"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').props().value + ).toEqual('is one of'); expect(wrapper.find('[data-test-subj="valuesAutocompleteMatchAny"]').at(0).text()).toEqual( 'some ip' ); @@ -263,25 +266,27 @@ describe('ExceptionBuilderComponent', () => { expect( wrapper.find('EuiFlexGroup[data-test-subj="exceptionItemEntryContainer"]') ).toHaveLength(2); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); - expect(wrapper.find('[data-test-subj="valuesAutocompleteMatch"]').at(0).text()).toEqual( - 'Please select a field first...' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').at(0).props() + .placeholder + ).toEqual('Search'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().placeholder + ).toEqual('Please select a field first...'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(1).text()).toEqual( - 'Search' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(1).text()).toEqual( - 'is' - ); - expect(wrapper.find('[data-test-subj="valuesAutocompleteMatch"]').at(1).text()).toEqual( - 'Please select a field first...' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').at(1).props() + .placeholder + ).toEqual('Search'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(1).props().value + ).toEqual('is'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(1).props().placeholder + ).toEqual('Please select a field first...'); }); }); @@ -324,25 +329,25 @@ describe('ExceptionBuilderComponent', () => { const item1 = wrapper.find('EuiFlexGroup[data-test-subj="exceptionEntriesContainer"]').at(0); const item2 = wrapper.find('EuiFlexGroup[data-test-subj="exceptionEntriesContainer"]').at(1); - expect(item1.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search' - ); - expect(item1.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); - expect(item1.find('[data-test-subj="valuesAutocompleteMatch"]').at(0).text()).toEqual( - 'Please select a field first...' - ); + expect( + item1.find('[data-test-subj="exceptionBuilderEntryField"] input').at(0).props().placeholder + ).toEqual('Search'); + expect( + item1.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); + expect( + item1.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().placeholder + ).toEqual('Please select a field first...'); - expect(item2.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search' - ); - expect(item2.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); - expect(item2.find('[data-test-subj="valuesAutocompleteMatch"]').at(0).text()).toEqual( - 'Please select a field first...' - ); + expect( + item2.find('[data-test-subj="exceptionBuilderEntryField"] input').at(0).props().placeholder + ).toEqual('Search'); + expect( + item2.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); + expect( + item2.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().placeholder + ).toEqual('Please select a field first...'); }); }); @@ -378,27 +383,27 @@ describe('ExceptionBuilderComponent', () => { ); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'ip' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is one of' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').props().value + ).toEqual('ip'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is one of'); expect(wrapper.find('[data-test-subj="valuesAutocompleteMatchAny"]').at(0).text()).toEqual( 'some ip' ); wrapper.find('[data-test-subj="firstRowBuilderDeleteButton"] button').simulate('click'); - expect(wrapper.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search' - ); - expect(wrapper.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); - expect(wrapper.find('[data-test-subj="valuesAutocompleteMatch"]').at(0).text()).toEqual( - 'Please select a field first...' - ); + expect( + wrapper.find('[data-test-subj="exceptionBuilderEntryField"] input').at(0).props().placeholder + ).toEqual('Search'); + expect( + wrapper.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); + expect( + wrapper.find('[data-test-subj="valuesAutocompleteMatch"] input').at(0).props().placeholder + ).toEqual('Please select a field first...'); }); test('it displays "and" badge if at least one exception item includes more than one entry', () => { @@ -507,14 +512,17 @@ describe('ExceptionBuilderComponent', () => { const entry2 = wrapper .find('EuiFlexGroup[data-test-subj="exceptionItemEntryContainer"]') .at(1); - expect(entry2.find('[data-test-subj="exceptionBuilderEntryField"]').at(0).text()).toEqual( - 'Search nested field' - ); - expect(entry2.find('[data-test-subj="operatorAutocompleteComboBox"]').at(0).text()).toEqual( - 'is' - ); + + expect( + entry2.find('[data-test-subj="exceptionBuilderEntryField"] input').at(0).props() + .placeholder + ).toEqual('Search nested field'); + expect( + entry2.find('[data-test-subj="operatorAutocompleteComboBox"] input').at(0).props().value + ).toEqual('is'); expect( - entry2.find('[data-test-subj="exceptionBuilderEntryFieldExists"]').at(0).text() + entry2.find('[data-test-subj="exceptionBuilderEntryFieldExists"] input').at(0).props() + .placeholder ).toEqual(getEmptyValue()); }); }); diff --git a/x-pack/plugins/log_explorer/public/components/dataset_selector/sub_components/esql_selector.tsx b/x-pack/plugins/log_explorer/public/components/dataset_selector/sub_components/esql_selector.tsx index fec07114d939d5..65ca1f1fd22e83 100644 --- a/x-pack/plugins/log_explorer/public/components/dataset_selector/sub_components/esql_selector.tsx +++ b/x-pack/plugins/log_explorer/public/components/dataset_selector/sub_components/esql_selector.tsx @@ -7,7 +7,7 @@ import { EuiBadge, EuiButton, EuiHorizontalRule } from '@elastic/eui'; import React from 'react'; -import { getRouterLinkProps } from '../../../utils/get_router_link_props'; +import { getRouterLinkProps } from '@kbn/router-utils'; import { DiscoverEsqlUrlProps } from '../../../hooks/use_esql'; import { technicalPreview, tryEsql } from '../constants'; diff --git a/x-pack/plugins/log_explorer/public/controller/public_state.ts b/x-pack/plugins/log_explorer/public/controller/public_state.ts index 04c12160a88091..5f4aad892bcb96 100644 --- a/x-pack/plugins/log_explorer/public/controller/public_state.ts +++ b/x-pack/plugins/log_explorer/public/controller/public_state.ts @@ -15,11 +15,7 @@ import { DEFAULT_CONTEXT, LogExplorerControllerContext, } from '../state_machines/log_explorer_controller'; -import { - LogExplorerPublicState, - LogExplorerPublicStateUpdate, - OptionsListControlOption, -} from './types'; +import { LogExplorerPublicState, LogExplorerPublicStateUpdate, OptionsListControl } from './types'; export const getPublicStateFromContext = ( context: LogExplorerControllerContext @@ -80,7 +76,7 @@ const getPublicControlsStateFromControlPanels = ( const getOptionsListPublicControlStateFromControlPanel = ( optionsListControlPanel: ControlPanels[string] -): OptionsListControlOption => ({ +): OptionsListControl => ({ mode: optionsListControlPanel.explicitInput.exclude ? 'exclude' : 'include', selection: optionsListControlPanel.explicitInput.existsSelected ? { type: 'exists' } @@ -113,7 +109,7 @@ const getControlPanelsFromPublicControlsState = ( const getControlPanelFromOptionsListPublicControlState = ( controlId: string, - publicControlState: OptionsListControlOption + publicControlState: OptionsListControl ): ControlPanels[string] => { const defaultControlPanelConfig = controlPanelConfigs[controlId]; diff --git a/x-pack/plugins/log_explorer/public/controller/types.ts b/x-pack/plugins/log_explorer/public/controller/types.ts index 50eb259d38cb30..5947051ad25189 100644 --- a/x-pack/plugins/log_explorer/public/controller/types.ts +++ b/x-pack/plugins/log_explorer/public/controller/types.ts @@ -41,19 +41,21 @@ export type LogExplorerDiscoverServices = Pick< }; export interface OptionsListControlOption { + type: 'options'; + selectedOptions: string[]; +} + +export interface OptionsListControlExists { + type: 'exists'; +} + +export interface OptionsListControl { mode: 'include' | 'exclude'; - selection: - | { - type: 'options'; - selectedOptions: string[]; - } - | { - type: 'exists'; - }; + selection: OptionsListControlOption | OptionsListControlExists; } export interface ControlOptions { - [availableControlsPanels.NAMESPACE]?: OptionsListControlOption; + [availableControlsPanels.NAMESPACE]?: OptionsListControl; } // we might want to wrap this into an object that has a "state value" laster diff --git a/x-pack/plugins/log_explorer/public/index.ts b/x-pack/plugins/log_explorer/public/index.ts index 005b5cca07a146..efd337234ffc6f 100644 --- a/x-pack/plugins/log_explorer/public/index.ts +++ b/x-pack/plugins/log_explorer/public/index.ts @@ -21,6 +21,7 @@ export type { LogExplorerPluginSetup, LogExplorerPluginStart } from './types'; export { getDiscoverColumnsFromDisplayOptions, getDiscoverGridFromDisplayOptions, + getDiscoverFiltersFromState, } from './utils/convert_discover_app_state'; export function plugin(context: PluginInitializerContext) { diff --git a/x-pack/plugins/log_explorer/public/utils/convert_discover_app_state.ts b/x-pack/plugins/log_explorer/public/utils/convert_discover_app_state.ts index dea02a0bec0028..90d51f75e8c7c7 100644 --- a/x-pack/plugins/log_explorer/public/utils/convert_discover_app_state.ts +++ b/x-pack/plugins/log_explorer/public/utils/convert_discover_app_state.ts @@ -7,6 +7,8 @@ import { QueryState } from '@kbn/data-plugin/public'; import { DiscoverAppState } from '@kbn/discover-plugin/public'; +import { ExistsFilter, Filter, FILTERS, PhrasesFilter } from '@kbn/es-query'; +import { PhraseFilterValue } from '@kbn/es-query/src/filters/build_filters'; import { cloneDeep } from 'lodash'; import { ChartDisplayOptions, @@ -14,6 +16,7 @@ import { GridColumnDisplayOptions, GridRowsDisplayOptions, } from '../../common'; +import { ControlOptions, OptionsListControlOption } from '../controller'; export const getGridColumnDisplayOptionsFromDiscoverAppState = ( discoverAppState: DiscoverAppState @@ -71,3 +74,60 @@ export const getDiscoverGridFromDisplayOptions = ( return gridColumns; }, {}), }); + +const createDiscoverPhrasesFilter = ({ + key, + values, + negate, +}: { + values: PhraseFilterValue[]; + key: string; + negate?: boolean; +}): PhrasesFilter => + ({ + meta: { + key, + negate, + type: FILTERS.PHRASES, + params: values, + }, + query: { + bool: { + should: values.map((value) => ({ match_phrase: { [key]: value.toString() } })), + minimum_should_match: 1, + }, + }, + } as PhrasesFilter); + +const createDiscoverExistsFilter = ({ + key, + negate, +}: { + key: string; + negate?: boolean; +}): ExistsFilter => ({ + meta: { + key, + negate, + type: FILTERS.EXISTS, + }, + query: { exists: { field: key } }, +}); + +export const getDiscoverFiltersFromState = (filters: Filter[] = [], controls?: ControlOptions) => [ + ...filters, + ...(controls + ? (Object.keys(controls) as Array).map((key) => + controls[key as keyof ControlOptions]?.selection.type === 'exists' + ? createDiscoverExistsFilter({ + key, + negate: controls[key]?.mode === 'exclude', + }) + : createDiscoverPhrasesFilter({ + key, + values: (controls[key]?.selection as OptionsListControlOption).selectedOptions, + negate: controls[key]?.mode === 'exclude', + }) + ) + : []), +]; diff --git a/x-pack/plugins/log_explorer/tsconfig.json b/x-pack/plugins/log_explorer/tsconfig.json index 15f3a940651976..05cdd888eba1f7 100644 --- a/x-pack/plugins/log_explorer/tsconfig.json +++ b/x-pack/plugins/log_explorer/tsconfig.json @@ -35,12 +35,13 @@ "@kbn/kibana-utils-plugin", "@kbn/navigation-plugin", "@kbn/react-field", + "@kbn/router-utils", "@kbn/share-plugin", "@kbn/unified-data-table", "@kbn/unified-doc-viewer", "@kbn/unified-field-list", "@kbn/unified-search-plugin", - "@kbn/xstate-utils" + "@kbn/xstate-utils", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss index 959176547dfb25..c88f343f7dbfa1 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/_toc_entry.scss @@ -81,7 +81,6 @@ flex-grow: 1; } -.mapLayTocActions__popoverAnchor, .mapLayTocActions__tooltipAnchor { max-width: 100%; } diff --git a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap index dfa4200c8508e4..47171e8bbe871b 100644 --- a/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap +++ b/x-pack/plugins/maps/public/connected_components/right_side_controls/layer_control/layer_toc/toc_entry/toc_entry_actions_popover/__snapshots__/toc_entry_actions_popover.test.tsx.snap @@ -3,7 +3,6 @@ exports[`TOCEntryActionsPopover is rendered 1`] = ` { closePopover={this._closePopover} panelPaddingSize="none" anchorPosition="leftUp" - anchorClassName="mapLayTocActions__popoverAnchor" > { // Check the Single Metric Viewer element exists in the selector, and that it is checked. expect(getByTestId('mlAnomalyResultsViewSelectorSingleMetricViewer')).toBeInTheDocument(); - expect( - getByTestId('mlAnomalyResultsViewSelectorSingleMetricViewer') - .querySelector('input')! - .hasAttribute('checked') - ).toBe(true); + expect(getByTestId('mlAnomalyResultsViewSelectorSingleMetricViewer')).toHaveAttribute( + 'aria-pressed', + 'true' + ); }); }); diff --git a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__snapshots__/cells.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__snapshots__/cells.test.js.snap index b5cc6f0e7ecc09..aadc12d246169e 100644 --- a/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__snapshots__/cells.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__snapshots__/cells.test.js.snap @@ -26,26 +26,22 @@ exports[`Node Listing Metric Cell should format a non-percentage metric 1`] = ` class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+
-
- -
+
- + ; export function useCloneSlo() { const { - http, - notifications: { toasts }, + http: { basePath }, + application: { navigateToUrl }, } = useKibana().services; - const queryClient = useQueryClient(); - return useMutation< - CreateSLOResponse, - ServerError, - { slo: CreateSLOInput; originalSloId?: string }, - { previousData?: FindSLOResponse; queryKey?: QueryKey } - >( - ['cloneSlo'], - ({ slo }: { slo: CreateSLOInput; originalSloId?: string }) => { - const body = JSON.stringify(slo); - return http.post(`/api/observability/slos`, { body }); + return useCallback( + (slo: SLOWithSummaryResponse) => { + navigateToUrl( + basePath.prepend( + paths.observability.sloCreateWithEncodedForm( + encode({ ...slo, name: `[Copy] ${slo.name}`, id: undefined }) + ) + ) + ); }, - { - onMutate: async ({ slo, originalSloId }) => { - await queryClient.cancelQueries({ queryKey: sloKeys.lists(), exact: false }); - - const queriesData = queryClient.getQueriesData({ - queryKey: sloKeys.lists(), - exact: false, - }); - const [queryKey, previousData] = queriesData?.at(0) ?? []; - - const originalSlo = previousData?.results?.find((el) => el.id === originalSloId); - const optimisticUpdate = { - page: previousData?.page ?? 1, - perPage: previousData?.perPage ?? 25, - total: previousData?.total ? previousData.total + 1 : 1, - results: [ - ...(previousData?.results ?? []), - { ...originalSlo, name: slo.name, id: uuidv4(), summary: undefined }, - ], - }; - - if (queryKey) { - queryClient.setQueryData(queryKey, optimisticUpdate); - } - - return { queryKey, previousData }; - }, - // If the mutation fails, use the context returned from onMutate to roll back - onError: (error, { slo }, context) => { - if (context?.previousData && context?.queryKey) { - queryClient.setQueryData(context.queryKey, context.previousData); - } - - toasts.addError(new Error(error.body?.message ?? error.message), { - title: i18n.translate('xpack.observability.slo.clone.errorNotification', { - defaultMessage: 'Failed to clone {name}', - values: { name: slo.name }, - }), - }); - }, - onSuccess: (_data, { slo }) => { - toasts.addSuccess( - i18n.translate('xpack.observability.slo.clone.successNotification', { - defaultMessage: 'Successfully created {name}', - values: { name: slo.name }, - }) - ); - queryClient.invalidateQueries({ queryKey: sloKeys.lists(), exact: false }); - }, - } + [navigateToUrl, basePath] ); } diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_group_by_cardinality.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_group_by_cardinality.ts new file mode 100644 index 00000000000000..928eb7e92482da --- /dev/null +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_group_by_cardinality.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 { ALL_VALUE } from '@kbn/slo-schema'; +import { useQuery } from '@tanstack/react-query'; +import { lastValueFrom } from 'rxjs'; +import { useKibana } from '../../utils/kibana_react'; + +export interface UseFetchIndexPatternFieldsResponse { + isLoading: boolean; + isSuccess: boolean; + isError: boolean; + data?: { cardinality: number; isHighCardinality: boolean }; +} + +const HIGH_CARDINALITY_THRESHOLD = 1000; + +export function useFetchGroupByCardinality( + indexPattern: string, + timestampField: string, + groupBy: string +): UseFetchIndexPatternFieldsResponse { + const { data: dataService } = useKibana().services; + + const { isLoading, isError, isSuccess, data } = useQuery({ + queryKey: ['fetchGroupByCardinality', indexPattern, timestampField, groupBy], + queryFn: async ({ signal }) => { + try { + const result = await lastValueFrom( + dataService.search.search({ + params: { + index: indexPattern, + body: { + query: { + bool: { + filter: [{ range: { [timestampField]: { gte: 'now-24h' } } }], + }, + }, + aggs: { + groupByCardinality: { + cardinality: { + field: groupBy, + }, + }, + }, + }, + }, + }) + ); + + // @ts-expect-error Property 'value' does not exist on type 'AggregationsAggregate' + const cardinality = result.rawResponse?.aggregations?.groupByCardinality?.value ?? 0; + return { cardinality, isHighCardinality: cardinality > HIGH_CARDINALITY_THRESHOLD }; + } catch (error) { + throw new Error(`Something went wrong. Error: ${error}`); + } + }, + retry: false, + refetchOnWindowFocus: false, + enabled: + Boolean(indexPattern) && Boolean(timestampField) && Boolean(groupBy) && groupBy !== ALL_VALUE, + }); + + return { isLoading, isError, isSuccess, data }; +} diff --git a/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts b/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts index 3363d501fae22c..5aedb92219da62 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_fetch_index_pattern_fields.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { FieldSpec } from '@kbn/data-views-plugin/common'; import { useQuery } from '@tanstack/react-query'; import { useKibana } from '../../utils/kibana_react'; @@ -12,14 +13,7 @@ export interface UseFetchIndexPatternFieldsResponse { isLoading: boolean; isSuccess: boolean; isError: boolean; - data: Field[] | undefined; -} - -export interface Field { - name: string; - type: string; - aggregatable: boolean; - searchable: boolean; + data: FieldSpec[] | undefined; } export function useFetchIndexPatternFields( diff --git a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx index 615edf3ef65f38..34eb1f278e7a3c 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/components/header_control.tsx @@ -10,20 +10,16 @@ import { i18n } from '@kbn/i18n'; import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { SLOWithSummaryResponse } from '@kbn/slo-schema'; +import { useCloneSlo } from '../../../hooks/slo/use_clone_slo'; import { SloDeleteConfirmationModal } from '../../../components/slo/delete_confirmation_modal/slo_delete_confirmation_modal'; import { useCapabilities } from '../../../hooks/slo/use_capabilities'; import { useKibana } from '../../../utils/kibana_react'; -import { useCloneSlo } from '../../../hooks/slo/use_clone_slo'; import { useDeleteSlo } from '../../../hooks/slo/use_delete_slo'; import { isApmIndicatorType } from '../../../utils/slo/indicator'; import { convertSliApmParamsToApmAppDeeplinkUrl } from '../../../utils/slo/convert_sli_apm_params_to_apm_app_deeplink_url'; import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../common/constants'; import { rulesLocatorID, sloFeatureId } from '../../../../common'; import { paths } from '../../../../common/locators/paths'; -import { - transformSloResponseToCreateSloForm, - transformCreateSLOFormToCreateSLOInput, -} from '../../slo_edit/helpers/process_slo_form_values'; import type { RulesParams } from '../../../locators/rules'; export interface Props { @@ -47,7 +43,6 @@ export function HeaderControl({ isLoading, slo }: Props) { const [isRuleFlyoutVisible, setRuleFlyoutVisibility] = useState(false); const [isDeleteConfirmationModalOpen, setDeleteConfirmationModalOpen] = useState(false); - const { mutate: cloneSlo } = useCloneSlo(); const { mutate: deleteSlo } = useDeleteSlo(); const handleActionsClick = () => setIsPopoverOpen((value) => !value); @@ -101,17 +96,12 @@ export function HeaderControl({ isLoading, slo }: Props) { } }; + const navigateToClone = useCloneSlo(); + const handleClone = async () => { if (slo) { setIsPopoverOpen(false); - - const newSlo = transformCreateSLOFormToCreateSLOInput( - transformSloResponseToCreateSloForm({ ...slo, name: `[Copy] ${slo.name}` })! - ); - - cloneSlo({ slo: newSlo, originalSloId: slo.id }); - - navigate(basePath.prepend(paths.observability.slos)); + navigateToClone(slo); } }; diff --git a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx index c9b04fee85eb25..5a06bbd9bf2db5 100644 --- a/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx +++ b/x-pack/plugins/observability/public/pages/slo_details/slo_details.test.tsx @@ -17,7 +17,6 @@ import { useFetchSloDetails } from '../../hooks/slo/use_fetch_slo_details'; import { useFetchHistoricalSummary } from '../../hooks/slo/use_fetch_historical_summary'; import { useFetchActiveAlerts } from '../../hooks/slo/use_fetch_active_alerts'; import { ActiveAlerts } from '../../hooks/slo/active_alerts'; -import { useCloneSlo } from '../../hooks/slo/use_clone_slo'; import { useDeleteSlo } from '../../hooks/slo/use_delete_slo'; import { render } from '../../utils/test_helper'; import { SloDetailsPage } from './slo_details'; @@ -30,6 +29,7 @@ import { import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { buildApmAvailabilityIndicator } from '../../data/slo/indicator'; import { ALL_VALUE } from '@kbn/slo-schema'; +import { encode } from '@kbn/rison'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -44,7 +44,6 @@ jest.mock('../../hooks/slo/use_capabilities'); jest.mock('../../hooks/slo/use_fetch_active_alerts'); jest.mock('../../hooks/slo/use_fetch_slo_details'); jest.mock('../../hooks/slo/use_fetch_historical_summary'); -jest.mock('../../hooks/slo/use_clone_slo'); jest.mock('../../hooks/slo/use_delete_slo'); const useKibanaMock = useKibana as jest.Mock; @@ -55,12 +54,10 @@ const useCapabilitiesMock = useCapabilities as jest.Mock; const useFetchActiveAlertsMock = useFetchActiveAlerts as jest.Mock; const useFetchSloDetailsMock = useFetchSloDetails as jest.Mock; const useFetchHistoricalSummaryMock = useFetchHistoricalSummary as jest.Mock; -const useCloneSloMock = useCloneSlo as jest.Mock; const useDeleteSloMock = useDeleteSlo as jest.Mock; const mockNavigate = jest.fn(); const mockLocator = jest.fn(); -const mockClone = jest.fn(); const mockDelete = jest.fn(); const mockCapabilities = { apm: { show: true }, @@ -120,7 +117,6 @@ describe('SLO Details Page', () => { data: historicalSummaryData, }); useFetchActiveAlertsMock.mockReturnValue({ isLoading: false, data: new ActiveAlerts() }); - useCloneSloMock.mockReturnValue({ mutate: mockClone }); useDeleteSloMock.mockReturnValue({ mutate: mockDelete }); useLocationMock.mockReturnValue({ search: '' }); }); @@ -248,29 +244,12 @@ describe('SLO Details Page', () => { fireEvent.click(button!); - const { - id, - createdAt, - enabled, - revision, - summary, - settings, - updatedAt, - instanceId, - version, - ...newSlo - } = slo; - - expect(mockClone).toBeCalledWith({ - originalSloId: slo.id, - slo: { - ...newSlo, - name: `[Copy] ${newSlo.name}`, - }, - }); - await waitFor(() => { - expect(mockNavigate).toBeCalledWith(paths.observability.slos); + expect(mockNavigate).toBeCalledWith( + paths.observability.sloCreateWithEncodedForm( + encode({ ...slo, name: `[Copy] ${slo.name}`, id: undefined }) + ) + ); }); }); diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx index c877d1de173c1f..78afcc71cae583 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; @@ -27,9 +28,14 @@ export function ApmAvailabilityIndicatorTypeForm() { setValue('indicator.params.index', apmIndex); } }, [setValue, apmIndex]); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(apmIndex); + + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(apmIndex, timestampField, groupByField); const groupByFields = indexFields.filter((field) => field.aggregatable); return ( @@ -158,6 +164,19 @@ export function ApmAvailabilityIndicatorTypeForm() { isDisabled={!apmIndex} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + ); diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx index b75c9fd8d110cd..dcb4be69d272d1 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx @@ -5,11 +5,19 @@ * 2.0. */ -import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip } from '@elastic/eui'; +import { + EuiCallOut, + EuiFieldNumber, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIconTip, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React, { useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchApmIndex } from '../../../../hooks/slo/use_fetch_apm_indices'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; @@ -28,8 +36,14 @@ export function ApmLatencyIndicatorTypeForm() { } }, [setValue, apmIndex]); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); + const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(apmIndex); + + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(apmIndex, timestampField, groupByField); const groupByFields = indexFields.filter((field) => field.aggregatable); return ( @@ -201,6 +215,19 @@ export function ApmLatencyIndicatorTypeForm() { isDisabled={!apmIndex} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + ); diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx index 367ff255edde0f..0a07515a8915f1 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/common/index_field_selector.tsx @@ -6,14 +6,14 @@ */ import { EuiComboBox, EuiComboBoxOptionOption, EuiFlexItem, EuiFormRow } from '@elastic/eui'; +import { FieldSpec } from '@kbn/data-views-plugin/common'; import React, { useEffect, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { createOptionsFromFields, Option } from '../../helpers/create_options'; import { CreateSLOForm } from '../../types'; interface Props { - indexFields: Field[]; + indexFields: FieldSpec[]; name: 'groupBy' | 'indicator.params.timestampField'; label: React.ReactNode | string; placeholder: string; diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx index 33b8a2eb6def32..42130cf204df66 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx @@ -5,11 +5,12 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; @@ -20,11 +21,17 @@ import { IndexSelection } from '../custom_common/index_selection'; export function CustomKqlIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); + const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(index); const timestampFields = indexFields.filter((field) => field.type === 'date'); const groupByFields = indexFields.filter((field) => field.aggregatable); + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(index, timestampField, groupByField); + return ( @@ -158,6 +165,19 @@ export function CustomKqlIndicatorTypeForm() { isDisabled={!index} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + ); diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx index c7a180d59cfbe4..2db17479ffd2d5 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx @@ -6,6 +6,7 @@ */ import { + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -18,6 +19,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; @@ -33,8 +35,14 @@ const SUPPORTED_METRIC_FIELD_TYPES = ['number', 'histogram']; export function CustomMetricIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); + const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(index); + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(index, timestampField, groupByField); + const timestampFields = indexFields.filter((field) => field.type === 'date'); const groupByFields = indexFields.filter((field) => field.aggregatable); const metricFields = indexFields.filter((field) => @@ -175,6 +183,19 @@ export function CustomMetricIndicatorTypeForm() { isDisabled={!index} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx index 262e6e6d2249a0..3e077ab2280a66 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx @@ -16,12 +16,12 @@ import { EuiIconTip, EuiSpacer, } from '@elastic/eui'; +import { FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { first, range, xor } from 'lodash'; import React, { useEffect, useState } from 'react'; import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; -import { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { aggValueToLabel, CUSTOM_METRIC_AGGREGATION_OPTIONS, @@ -32,7 +32,7 @@ import { QueryBuilder } from '../common/query_builder'; interface MetricIndicatorProps { type: 'good' | 'total'; - metricFields: Field[]; + metricFields: FieldSpec[]; isLoadingIndex: boolean; } diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator.tsx index 1362674828d74f..4efcc1bfb5b8ba 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator.tsx @@ -15,17 +15,17 @@ import { EuiIconTip, EuiSpacer, } from '@elastic/eui'; +import { 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 { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { createOptionsFromFields, Option } from '../../helpers/create_options'; import { CreateSLOForm } from '../../types'; import { QueryBuilder } from '../common/query_builder'; interface HistogramIndicatorProps { type: 'good' | 'total'; - histogramFields: Field[]; + histogramFields: FieldSpec[]; isLoadingIndex: boolean; } diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx index 9f8831fa9dfab7..992547dc2802fd 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx @@ -6,6 +6,7 @@ */ import { + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -18,6 +19,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; @@ -29,9 +31,14 @@ import { HistogramIndicator } from './histogram_indicator'; export function HistogramIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(index); + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(index, timestampField, groupByField); + const histogramFields = indexFields.filter((field) => field.type === 'histogram'); const timestampFields = indexFields.filter((field) => field.type === 'date'); const groupByFields = indexFields.filter((field) => field.aggregatable); @@ -162,6 +169,19 @@ export function HistogramIndicatorTypeForm() { isDisabled={!index} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form.tsx index 6627f910a7c276..e5f8e9b02ce2a0 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/slo_edit_form.tsx @@ -18,8 +18,7 @@ import { i18n } from '@kbn/i18n'; import type { GetSLOResponse } from '@kbn/slo-schema'; import React, { useCallback, useEffect, useState } from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { sloFeatureId } from '../../../../common'; -import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../common/constants'; +import { BurnRateRuleFlyout } from '../../slos/components/common/burn_rate_rule_flyout'; import { paths } from '../../../../common/locators/paths'; import { useCreateSlo } from '../../../hooks/slo/use_create_slo'; import { useFetchRulesForSlo } from '../../../hooks/slo/use_fetch_rules_for_slo'; @@ -54,7 +53,6 @@ export function SloEditForm({ slo }: Props) { const { application: { navigateToUrl }, http: { basePath }, - triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout }, } = useKibana().services; const isEditMode = slo !== undefined; @@ -146,10 +144,6 @@ export function SloEditForm({ slo }: Props) { setIsCreateRuleCheckboxChecked(!isCreateRuleCheckboxChecked); }; - const handleCloseRuleFlyout = async () => { - navigateToUrl(basePath.prepend(paths.observability.slos)); - }; - return ( <> @@ -256,17 +250,11 @@ export function SloEditForm({ slo }: Props) { - {isAddRuleFlyoutOpen && slo ? ( - - ) : null} + ); } diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx index 14cce99bb5d86c..b8105814b852e4 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx @@ -17,18 +17,18 @@ import { EuiSpacer, EuiText, } from '@elastic/eui'; +import { FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; 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 { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { COMPARATOR_OPTIONS } from '../../constants'; import { CreateSLOForm } from '../../types'; import { MetricInput } from './metric_input'; interface MetricIndicatorProps { - indexFields: Field[]; + indexFields: FieldSpec[]; isLoadingIndex: boolean; } diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx index 95cc2775560209..22cbc42366baa8 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx @@ -12,10 +12,10 @@ import { EuiFormRow, EuiIconTip, } from '@elastic/eui'; +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 { Field } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { AGGREGATION_OPTIONS, aggValueToLabel } from '../../helpers/aggregation_options'; import { createOptionsFromFields, Option } from '../../helpers/create_options'; import { CreateSLOForm } from '../../types'; @@ -55,7 +55,7 @@ interface MetricInputProps { metricIndex: number; indexPattern: string; isLoadingIndex: boolean; - indexFields: Field[]; + indexFields: FieldSpec[]; } export function MetricInput({ diff --git a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx index 2fde2468d78ec4..1c01219ffe1a24 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx @@ -6,6 +6,7 @@ */ import { + EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -19,6 +20,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { ALL_VALUE } from '@kbn/slo-schema/src/schema/common'; +import { useFetchGroupByCardinality } from '../../../../hooks/slo/use_fetch_group_by_cardinality'; import { useFetchIndexPatternFields } from '../../../../hooks/slo/use_fetch_index_pattern_fields'; import { CreateSLOForm } from '../../types'; import { DataPreviewChart } from '../common/data_preview_chart'; @@ -34,8 +36,14 @@ export { NEW_TIMESLICE_METRIC } from './metric_indicator'; export function TimesliceMetricIndicatorTypeForm() { const { watch } = useFormContext(); const index = watch('indicator.params.index'); + const timestampField = watch('indicator.params.timestampField'); + const groupByField = watch('groupBy'); + const { isLoading: isIndexFieldsLoading, data: indexFields = [] } = useFetchIndexPatternFields(index); + const { isLoading: isGroupByCardinalityLoading, data: groupByCardinality } = + useFetchGroupByCardinality(index, timestampField, groupByField); + const timestampFields = indexFields.filter((field) => field.type === 'date'); const groupByFields = indexFields.filter((field) => field.aggregatable); const { uiSettings } = useKibana().services; @@ -152,6 +160,19 @@ export function TimesliceMetricIndicatorTypeForm() { isDisabled={!index} /> + {!isGroupByCardinalityLoading && !!groupByCardinality && ( + + )} + boolean ): Option[] { const options = fields diff --git a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx index 27fda5cfc61fa1..485ee068fc6f75 100644 --- a/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx +++ b/x-pack/plugins/observability/public/pages/slo_edit/slo_edit.tsx @@ -33,7 +33,7 @@ export function SloEditPage() { const { sloId } = useParams<{ sloId: string | undefined }>(); const { hasAtLeast } = useLicense(); const hasRightLicense = hasAtLeast('platinum'); - const { data: slo, isInitialLoading } = useFetchSloDetails({ sloId }); + const { data: slo } = useFetchSloDetails({ sloId }); useBreadcrumbs([ { @@ -66,10 +66,6 @@ export function SloEditPage() { navigateToUrl(basePath.prepend(paths.observability.slos)); } - if (sloId && isInitialLoading) { - return null; - } - return ( { +const getSubTitle = (slo: SLOWithSummaryResponse) => { return slo.groupBy && slo.groupBy !== ALL_VALUE ? `${slo.groupBy}: ${slo.instanceId}` : ''; }; @@ -88,14 +89,14 @@ export function SloCardItem({ slo, rules, activeAlerts, historicalSummary, cards } }} paddingSize="none" - style={{ - height: '182px', - overflow: 'hidden', - position: 'relative', - }} + css={css` + height: 182px; + overflow: hidden; + position: relative; + `} title={slo.summary.status} > - + {(isMouseOver || isActionsPopoverOpen) && ( ; }) { const { @@ -147,7 +146,7 @@ export function SloCardChart({ } = useKibana().services; const cardColor = useSloCardColor(slo.summary.status); - const subTitle = getSubTitle(slo, cardsPerRow); + const subTitle = getSubTitle(slo); const { sliValue, sloTarget, sloDetailsUrl } = useSloFormattedSummary(slo); return ( diff --git a/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx index a8d43c35217d17..3e1a80f147f2e4 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/card_view/slos_card_view.tsx @@ -68,27 +68,29 @@ export function SloListCardView({ } return ( - - {sloList.map((slo) => ( - - - historicalSummary.sloId === slo.id && - historicalSummary.instanceId === (slo.instanceId ?? ALL_VALUE) - )?.data - } - historicalSummaryLoading={historicalSummaryLoading} - cardsPerRow={Number(cardsPerRow)} - /> - - ))} + + {sloList + .filter((slo) => slo.summary) + .map((slo) => ( + + + historicalSummary.sloId === slo.id && + historicalSummary.instanceId === (slo.instanceId ?? ALL_VALUE) + )?.data + } + historicalSummaryLoading={historicalSummaryLoading} + cardsPerRow={Number(cardsPerRow)} + /> + + ))} ); } diff --git a/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx b/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx index a02730231ae5f3..871c11d39bdde2 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/common/burn_rate_rule_flyout.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { SLOWithSummaryResponse } from '@kbn/slo-schema'; import { useQueryClient } from '@tanstack/react-query'; +import { paths } from '../../../../../common/locators/paths'; import { useGetFilteredRuleTypes } from '../../../../hooks/use_get_filtered_rule_types'; import { sloKeys } from '../../../../hooks/slo/query_key_factory'; import { useKibana } from '../../../../utils/kibana_react'; @@ -17,13 +18,17 @@ import { sloFeatureId } from '../../../../../common'; export function BurnRateRuleFlyout({ slo, isAddRuleFlyoutOpen, + canChangeTrigger, setIsAddRuleFlyoutOpen, }: { - slo: SLOWithSummaryResponse; + slo?: SLOWithSummaryResponse; isAddRuleFlyoutOpen: boolean; - setIsAddRuleFlyoutOpen: (value: boolean) => void; + canChangeTrigger?: boolean; + setIsAddRuleFlyoutOpen?: (value: boolean) => void; }) { const { + application: { navigateToUrl }, + http: { basePath }, triggersActionsUi: { getAddRuleFlyout: AddRuleFlyout }, } = useKibana().services; @@ -32,19 +37,30 @@ export function BurnRateRuleFlyout({ const queryClient = useQueryClient(); const handleSavedRule = async () => { - queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); + if (setIsAddRuleFlyoutOpen) { + queryClient.invalidateQueries({ queryKey: sloKeys.rules(), exact: false }); + } else { + navigateToUrl(basePath.prepend(paths.observability.slos)); + } }; - return isAddRuleFlyoutOpen ? ( + const handleCloseRuleFlyout = async () => { + if (setIsAddRuleFlyoutOpen) { + setIsAddRuleFlyoutOpen(false); + } else { + navigateToUrl(basePath.prepend(paths.observability.slos)); + } + }; + + return isAddRuleFlyoutOpen && slo ? ( { - setIsAddRuleFlyoutOpen(false); - }} + onClose={handleCloseRuleFlyout} useRuleProducer /> ) : null; diff --git a/x-pack/plugins/observability/public/pages/slos/components/compact_view/slo_list_compact_view.tsx b/x-pack/plugins/observability/public/pages/slos/components/compact_view/slo_list_compact_view.tsx index d7e1c78d117e6b..d884de55aed547 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/compact_view/slo_list_compact_view.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/compact_view/slo_list_compact_view.tsx @@ -19,6 +19,7 @@ import { i18n } from '@kbn/i18n'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { useQueryClient } from '@tanstack/react-query'; import React, { useState } from 'react'; +import { useCloneSlo } from '../../../../hooks/slo/use_clone_slo'; import { rulesLocatorID, sloFeatureId } from '../../../../../common'; import { SLO_BURN_RATE_RULE_TYPE_ID } from '../../../../../common/constants'; import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; @@ -28,7 +29,6 @@ import { SloStatusBadge } from '../../../../components/slo/slo_status_badge'; import { SloActiveAlertsBadge } from '../../../../components/slo/slo_status_badge/slo_active_alerts_badge'; import { sloKeys } from '../../../../hooks/slo/query_key_factory'; import { useCapabilities } from '../../../../hooks/slo/use_capabilities'; -import { useCloneSlo } from '../../../../hooks/slo/use_clone_slo'; import { useDeleteSlo } from '../../../../hooks/slo/use_delete_slo'; import { useFetchActiveAlerts } from '../../../../hooks/slo/use_fetch_active_alerts'; import { useFetchHistoricalSummary } from '../../../../hooks/slo/use_fetch_historical_summary'; @@ -37,10 +37,6 @@ import { useGetFilteredRuleTypes } from '../../../../hooks/use_get_filtered_rule import { RulesParams } from '../../../../locators/rules'; import { useKibana } from '../../../../utils/kibana_react'; import { formatHistoricalData } from '../../../../utils/slo/chart_data_formatter'; -import { - transformCreateSLOFormToCreateSLOInput, - transformSloResponseToCreateSloForm, -} from '../../../slo_edit/helpers/process_slo_form_values'; import { SloRulesBadge } from '../badges/slo_rules_badge'; import { SloListEmpty } from '../slo_list_empty'; import { SloListError } from '../slo_list_error'; @@ -72,7 +68,6 @@ export function SloListCompactView({ sloList, loading, error }: Props) { const filteredRuleTypes = useGetFilteredRuleTypes(); const queryClient = useQueryClient(); - const { mutate: cloneSlo } = useCloneSlo(); const { mutate: deleteSlo } = useDeleteSlo(); const [sloToAddRule, setSloToAddRule] = useState(undefined); @@ -102,6 +97,8 @@ export function SloListCompactView({ sloList, loading, error }: Props) { list: sloList.map((slo) => ({ sloId: slo.id, instanceId: slo.instanceId ?? ALL_VALUE })), }); + const navigateToClone = useCloneSlo(); + const actions: Array> = [ { type: 'icon', @@ -180,11 +177,7 @@ export function SloListCompactView({ sloList, loading, error }: Props) { 'data-test-subj': 'sloActionsClone', enabled: (_) => hasWriteCapabilities, onClick: (slo: SLOWithSummaryResponse) => { - const newSlo = transformCreateSLOFormToCreateSLOInput( - transformSloResponseToCreateSloForm({ ...slo, name: `[Copy] ${slo.name}` })! - ); - - cloneSlo({ slo: newSlo, originalSloId: slo.id }); + navigateToClone(slo); }, }, { diff --git a/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx index 4fb03968d40a01..51652abe135428 100644 --- a/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx +++ b/x-pack/plugins/observability/public/pages/slos/components/slo_item_actions.tsx @@ -17,16 +17,12 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import styled from 'styled-components'; -import { useCapabilities } from '../../../hooks/slo/use_capabilities'; import { useCloneSlo } from '../../../hooks/slo/use_clone_slo'; +import { useCapabilities } from '../../../hooks/slo/use_capabilities'; import { useKibana } from '../../../utils/kibana_react'; import { paths } from '../../../../common/locators/paths'; import { RulesParams } from '../../../locators/rules'; import { rulesLocatorID } from '../../../../common'; -import { - transformCreateSLOFormToCreateSLOInput, - transformSloResponseToCreateSloForm, -} from '../../slo_edit/helpers/process_slo_form_values'; interface Props { slo: SLOWithSummaryResponse; @@ -73,7 +69,6 @@ export function SloItemActions({ }, } = useKibana().services; const { hasWriteCapabilities } = useCapabilities(); - const { mutate: cloneSlo } = useCloneSlo(); const sloDetailsUrl = basePath.prepend( paths.observability.sloDetails( @@ -94,18 +89,15 @@ export function SloItemActions({ navigateToUrl(basePath.prepend(paths.observability.sloEdit(slo.id))); }; - const handleNavigateToRules = async () => { - const locator = locators.get(rulesLocatorID); - locator?.navigate({ params: { sloId: slo.id } }, { replace: false }); - }; + const navigateToClone = useCloneSlo(); const handleClone = () => { - const newSlo = transformCreateSLOFormToCreateSLOInput( - transformSloResponseToCreateSloForm({ ...slo, name: `[Copy] ${slo.name}` })! - ); + navigateToClone(slo); + }; - cloneSlo({ slo: newSlo, originalSloId: slo.id }); - setIsActionsPopoverOpen(false); + const handleNavigateToRules = async () => { + const locator = locators.get(rulesLocatorID); + locator?.navigate({ params: { sloId: slo.id } }, { replace: false }); }; const handleDelete = () => { diff --git a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx index 40fd12d4b003e4..1f28e822b96f90 100644 --- a/x-pack/plugins/observability/public/pages/slos/slos.test.tsx +++ b/x-pack/plugins/observability/public/pages/slos/slos.test.tsx @@ -15,7 +15,6 @@ import { paths } from '../../../common/locators/paths'; import { historicalSummaryData } from '../../data/slo/historical_summary_data'; import { emptySloList, sloList } from '../../data/slo/slo'; import { useCapabilities } from '../../hooks/slo/use_capabilities'; -import { useCloneSlo } from '../../hooks/slo/use_clone_slo'; import { useCreateSlo } from '../../hooks/slo/use_create_slo'; import { useDeleteSlo } from '../../hooks/slo/use_delete_slo'; import { useFetchHistoricalSummary } from '../../hooks/slo/use_fetch_historical_summary'; @@ -24,6 +23,7 @@ import { useLicense } from '../../hooks/use_license'; import { useKibana } from '../../utils/kibana_react'; import { render } from '../../utils/test_helper'; import { SlosPage } from './slos'; +import { encode } from '@kbn/rison'; jest.mock('react-router-dom', () => ({ ...jest.requireActual('react-router-dom'), @@ -35,7 +35,6 @@ jest.mock('../../utils/kibana_react'); jest.mock('../../hooks/use_license'); jest.mock('../../hooks/slo/use_fetch_slo_list'); jest.mock('../../hooks/slo/use_create_slo'); -jest.mock('../../hooks/slo/use_clone_slo'); jest.mock('../../hooks/slo/use_delete_slo'); jest.mock('../../hooks/slo/use_fetch_historical_summary'); jest.mock('../../hooks/slo/use_capabilities'); @@ -44,17 +43,14 @@ const useKibanaMock = useKibana as jest.Mock; const useLicenseMock = useLicense as jest.Mock; const useFetchSloListMock = useFetchSloList as jest.Mock; const useCreateSloMock = useCreateSlo as jest.Mock; -const useCloneSloMock = useCloneSlo as jest.Mock; const useDeleteSloMock = useDeleteSlo as jest.Mock; const useFetchHistoricalSummaryMock = useFetchHistoricalSummary as jest.Mock; const useCapabilitiesMock = useCapabilities as jest.Mock; const mockCreateSlo = jest.fn(); -const mockCloneSlo = jest.fn(); const mockDeleteSlo = jest.fn(); useCreateSloMock.mockReturnValue({ mutate: mockCreateSlo }); -useCloneSloMock.mockReturnValue({ mutate: mockCloneSlo }); useDeleteSloMock.mockReturnValue({ mutate: mockDeleteSlo }); const mockNavigate = jest.fn(); @@ -358,7 +354,14 @@ describe('SLOs Page', () => { button.click(); - expect(mockCloneSlo).toBeCalled(); + await waitFor(() => { + const slo = sloList.results.at(0); + expect(mockNavigate).toBeCalledWith( + paths.observability.sloCreateWithEncodedForm( + encode({ ...slo, name: `[Copy] ${slo!.name}`, id: undefined }) + ) + ); + }); }); }); }); diff --git a/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts b/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts index ddcd3b244dbb61..e1891e68af58b1 100644 --- a/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts +++ b/x-pack/plugins/observability/server/lib/rules/slo_burn_rate/executor.ts @@ -98,7 +98,6 @@ export const getRuleExecutor = ({ const alertLimit = alertFactory.alertLimit.getValue(); let hasReachedLimit = false; let scheduledActionsCount = 0; - for (const result of results) { const { instanceId, @@ -172,40 +171,40 @@ export const getRuleExecutor = ({ scheduledActionsCount++; } } + alertFactory.alertLimit.setLimitReached(hasReachedLimit); + } - const { getRecoveredAlerts } = alertFactory.done(); - const recoveredAlerts = getRecoveredAlerts(); - for (const recoveredAlert of recoveredAlerts) { - const alertId = recoveredAlert.getId(); - const indexedStartedAt = getAlertStartedDate(alertId) ?? startedAt.toISOString(); - const alertUuid = recoveredAlert.getUuid(); - const alertDetailsUrl = await getAlertUrl( - alertUuid, - spaceId, - indexedStartedAt, - alertsLocator, - basePath.publicBaseUrl - ); + const { getRecoveredAlerts } = alertFactory.done(); + const recoveredAlerts = getRecoveredAlerts(); + for (const recoveredAlert of recoveredAlerts) { + const alertId = recoveredAlert.getId(); + const indexedStartedAt = getAlertStartedDate(alertId) ?? startedAt.toISOString(); + const alertUuid = recoveredAlert.getUuid(); + const alertDetailsUrl = await getAlertUrl( + alertUuid, + spaceId, + indexedStartedAt, + alertsLocator, + basePath.publicBaseUrl + ); - const urlQuery = alertId === ALL_VALUE ? '' : `?instanceId=${alertId}`; - const viewInAppUrl = addSpaceIdToPath( - basePath.publicBaseUrl, - spaceId, - `/app/observability/slos/${slo.id}${urlQuery}` - ); + const urlQuery = alertId === ALL_VALUE ? '' : `?instanceId=${alertId}`; + const viewInAppUrl = addSpaceIdToPath( + basePath.publicBaseUrl, + spaceId, + `/app/observability/slos/${slo.id}${urlQuery}` + ); - const context = { - timestamp: startedAt.toISOString(), - viewInAppUrl, - alertDetailsUrl, - sloId: slo.id, - sloName: slo.name, - sloInstanceId: alertId, - }; + const context = { + timestamp: startedAt.toISOString(), + viewInAppUrl, + alertDetailsUrl, + sloId: slo.id, + sloName: slo.name, + sloInstanceId: alertId, + }; - recoveredAlert.setContext(context); - } - alertFactory.alertLimit.setLimitReached(hasReachedLimit); + recoveredAlert.setContext(context); } return { state: {} }; diff --git a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx index 60aa56c15dda8d..c38d328a87bcb8 100644 --- a/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx +++ b/x-pack/plugins/observability_ai_assistant/public/components/chat/chat_body.tsx @@ -14,6 +14,8 @@ import { EuiHorizontalRule, EuiPanel, EuiSpacer, + useEuiTheme, + euiScrollBarStyles, } from '@elastic/eui'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; import { euiThemeVars } from '@kbn/ui-theme'; @@ -40,8 +42,9 @@ const fullHeightClassName = css` height: 100%; `; -const timelineClassName = css` +const timelineClassName = (scrollBarStyles: string) => css` overflow-y: auto; + ${scrollBarStyles} `; const promptEditorClassname = css` @@ -104,6 +107,8 @@ export function ChatBody({ }) { const license = useLicense(); const hasCorrectLicense = license?.hasAtLeast('enterprise'); + const euiTheme = useEuiTheme(); + const scrollBarStyles = euiScrollBarStyles(euiTheme); const chatService = useObservabilityAIAssistantChatService(); @@ -217,7 +222,7 @@ export function ChatBody({ } else { footer = ( <> - +
css` overflow-y: auto; + ${scrollBarStyles} `; const newChatButtonWrapperClassName = css` @@ -56,10 +59,12 @@ export function ConversationList({ onClickNewChat: () => void; onClickDeleteConversation: (id: string) => void; }) { + const euiTheme = useEuiTheme(); + const scrollBarStyles = euiScrollBarStyles(euiTheme); return ( - + diff --git a/x-pack/plugins/observability_log_explorer/public/components/discover_link.tsx b/x-pack/plugins/observability_log_explorer/public/components/discover_link.tsx index 2d12de11731c06..d2195124bc292b 100644 --- a/x-pack/plugins/observability_log_explorer/public/components/discover_link.tsx +++ b/x-pack/plugins/observability_log_explorer/public/components/discover_link.tsx @@ -9,7 +9,11 @@ import { EuiHeaderLink } from '@elastic/eui'; import { DiscoverAppLocatorParams } from '@kbn/discover-plugin/common'; import { DiscoverStart } from '@kbn/discover-plugin/public'; import { hydrateDatasetSelection } from '@kbn/log-explorer-plugin/common'; -import { getDiscoverColumnsFromDisplayOptions } from '@kbn/log-explorer-plugin/public'; +import { + getDiscoverColumnsFromDisplayOptions, + getDiscoverFiltersFromState, +} from '@kbn/log-explorer-plugin/public'; +import { getRouterLinkProps } from '@kbn/router-utils'; import { MatchedStateFromActor } from '@kbn/xstate-utils'; import { useActor } from '@xstate/react'; import React, { useMemo } from 'react'; @@ -18,7 +22,6 @@ import { ObservabilityLogExplorerService, useObservabilityLogExplorerPageStateContext, } from '../state_machines/observability_log_explorer/src'; -import { getRouterLinkProps } from '../utils/get_router_link_props'; import { useKibanaContextForPlugin } from '../utils/use_kibana'; export const ConnectedDiscoverLink = React.memo(() => { @@ -54,7 +57,7 @@ export const DiscoverLinkForValidState = React.memo( () => ({ breakdownField: logExplorerState.chart.breakdownField ?? undefined, columns: getDiscoverColumnsFromDisplayOptions(logExplorerState), - filters: logExplorerState.filters, + filters: getDiscoverFiltersFromState(logExplorerState.filters, logExplorerState.controls), query: logExplorerState.query, refreshInterval: logExplorerState.refreshInterval, timeRange: logExplorerState.time, diff --git a/x-pack/plugins/observability_log_explorer/public/components/onboarding_link.tsx b/x-pack/plugins/observability_log_explorer/public/components/onboarding_link.tsx index abdc585c227687..261405c7660246 100644 --- a/x-pack/plugins/observability_log_explorer/public/components/onboarding_link.tsx +++ b/x-pack/plugins/observability_log_explorer/public/components/onboarding_link.tsx @@ -10,10 +10,10 @@ import { ObservabilityOnboardingLocatorParams, OBSERVABILITY_ONBOARDING_LOCATOR, } from '@kbn/deeplinks-observability/locators'; +import { getRouterLinkProps } from '@kbn/router-utils'; import { BrowserUrlService } from '@kbn/share-plugin/public'; import React from 'react'; import { onboardingLinkTitle } from '../../common/translations'; -import { getRouterLinkProps } from '../utils/get_router_link_props'; import { useKibanaContextForPlugin } from '../utils/use_kibana'; export const ConnectedOnboardingLink = React.memo(() => { diff --git a/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts b/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts deleted file mode 100644 index a325df1a7e86ff..00000000000000 --- a/x-pack/plugins/observability_log_explorer/public/utils/get_router_link_props.ts +++ /dev/null @@ -1,35 +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. - */ - -interface GetRouterLinkPropsDeps { - href?: string; - onClick(): void; -} - -const isModifiedEvent = (event: React.MouseEvent) => - !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); - -const isLeftClickEvent = (event: React.MouseEvent) => event.button === 0; - -export const getRouterLinkProps = ({ href, onClick }: GetRouterLinkPropsDeps) => { - const guardedClickHandler = (event: React.MouseEvent) => { - if (event.defaultPrevented) { - return; - } - - if (isModifiedEvent(event) || !isLeftClickEvent(event)) { - return; - } - - // Prevent regular link behavior, which causes a browser refresh. - event.preventDefault(); - - onClick(); - }; - - return { href, onClick: guardedClickHandler }; -}; diff --git a/x-pack/plugins/observability_log_explorer/tsconfig.json b/x-pack/plugins/observability_log_explorer/tsconfig.json index be61fb9926a8c7..0c03040b4203b7 100644 --- a/x-pack/plugins/observability_log_explorer/tsconfig.json +++ b/x-pack/plugins/observability_log_explorer/tsconfig.json @@ -35,7 +35,8 @@ "@kbn/shared-ux-router", "@kbn/shared-ux-utility", "@kbn/ui-theme", - "@kbn/xstate-utils" + "@kbn/xstate-utils", + "@kbn/router-utils", ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_shared/common/utils/get_inspect_response.ts b/x-pack/plugins/observability_shared/common/utils/get_inspect_response.ts index 85f6624225e5a6..fbcb053acdc528 100644 --- a/x-pack/plugins/observability_shared/common/utils/get_inspect_response.ts +++ b/x-pack/plugins/observability_shared/common/utils/get_inspect_response.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { v4 as uuidv4 } from 'uuid'; import type { KibanaRequest } from '@kbn/core/server'; import type { RequestStatistics, RequestStatus } from '@kbn/inspector-plugin/common'; import { Request } from '@kbn/inspector-plugin/common'; @@ -157,12 +158,13 @@ export function getInspectResponse({ operationName: string; startTime: number; }): InspectResponse[0] { - const id = `${operationName} (${kibanaRequest.route.path})`; + const name = `${operationName} (${kibanaRequest.route.path})`; + const id = `${name} ${uuidv4()}`; return { id, json: esRequestParams.body ?? esRequestParams, - name: id, + name, response: { json: esError ? esError.originalError : esResponse, }, diff --git a/x-pack/plugins/observability_shared/public/contexts/inspector/inspector_context.tsx b/x-pack/plugins/observability_shared/public/contexts/inspector/inspector_context.tsx index a595c6bd67a8eb..0b87f0e4a5476c 100644 --- a/x-pack/plugins/observability_shared/public/contexts/inspector/inspector_context.tsx +++ b/x-pack/plugins/observability_shared/public/contexts/inspector/inspector_context.tsx @@ -49,7 +49,7 @@ export function InspectorContextProvider({ children }: { children: ReactNode }) const requestParams = { id, name }; const requestResponder = inspectorAdapters.requests.start( - id, + name, requestParams, operation.startTime ); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts index 1c932435d81736..97dedb2ca6a2b9 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_linked_apps.cy.ts @@ -54,7 +54,7 @@ describe( cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { cy.contains("SELECT * FROM os_version where name='{{host.os.name}}';"); - cy.contains('host.os.platform'); + cy.get('input[value="host.os.platform"]').should('exist'); cy.contains('platform'); }); cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts index afea9bb8c0adf7..ca10dc80fe6b6c 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_multiple_agents.cy.ts @@ -49,7 +49,7 @@ describe( // This is probably due to the tokenization of the fields when it's inactive cy.get(OSQUERY_FLYOUT_BODY_EDITOR).click(); cy.getBySel('flyout-body-osquery').contains("SELECT * FROM os_version where name='Ubuntu';"); - cy.getBySel('flyout-body-osquery').contains('host.os.platform'); + cy.getBySel('flyout-body-osquery').find('input[value="host.os.platform"]').should('exist'); cy.getBySel('flyout-body-osquery').contains('platform'); }); diff --git a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts index f0d3c3468f16c9..0591e650cc560f 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/alerts_response_actions_form.cy.ts @@ -157,8 +157,8 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve cy.contains('Days of uptime'); }); cy.getBySel(RESPONSE_ACTIONS_ITEM_1).within(() => { - cy.contains(packName); - cy.getBySel('comboBoxInput').type('{backspace}{enter}'); + cy.getBySel('comboBoxSearchInput').should('have.value', packName); + cy.getBySel('comboBoxInput').type('{selectall}{backspace}{enter}'); }); cy.getBySel(RESPONSE_ACTIONS_ITEM_0).within(() => { cy.contains('select * from uptime1'); @@ -166,6 +166,7 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve }); cy.getBySel(RESPONSE_ACTIONS_ITEM_0) .within(() => { + cy.getBySel('comboBoxSearchInput').click(); cy.contains('Search for a pack to run'); cy.contains('Pack is a required field'); cy.getBySel('comboBoxInput').type(`${packName}{downArrow}{enter}`); @@ -201,8 +202,10 @@ describe('Alert Event Details - Response Actions Form', { tags: ['@ess', '@serve cy.getBySel('edit-rule-actions-tab').click(); cy.getBySel(RESPONSE_ACTIONS_ITEM_0) .within(() => { - cy.contains(packName); - cy.getBySel('comboBoxInput').type(`${multiQueryPackName}{downArrow}{enter}`); + cy.getBySel('comboBoxSearchInput').should('have.value', packName); + cy.getBySel('comboBoxInput').type( + `{selectall}{backspace}${multiQueryPackName}{downArrow}{enter}` + ); cy.contains('SELECT * FROM memory_info;'); cy.contains('SELECT * FROM system_info;'); }) diff --git a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts index 9e10e1eb0d889e..8a972405015c99 100644 --- a/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/all/packs_integration.cy.ts @@ -86,7 +86,7 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => { cy.visit(FLEET_AGENT_POLICIES); cy.contains(AGENT_POLICY_NAME).click(); cy.get('.euiTableCellContent') - .get('.euiPopover__anchor') + .get('.euiPopover') .get(`[aria-label="Open"]`) .first() .click(); @@ -308,14 +308,12 @@ describe('ALL - Packs', { tags: ['@ess', '@serverless'] }, () => { cy.getBySel(EDIT_PACK_HEADER_BUTTON).click(); cy.get('#shardsPercentage0').should('have.value', '15'); cy.getBySel('packShardsForm-1').within(() => { - cy.getBySel('shards-field-policy').contains(OSQUERY_POLICY); + cy.getBySel('shards-field-policy').find('input').should('value', OSQUERY_POLICY); cy.get('#shardsPercentage1').should('have.value', '0'); }); - cy.getBySel(POLICY_SELECT_COMBOBOX).within(() => { - cy.contains(OSQUERY_POLICY).should('not.exist'); - }); + cy.getBySel(POLICY_SELECT_COMBOBOX).find('input').should('not.have.value', OSQUERY_POLICY); - cy.getBySel('comboBoxInput').contains(OSQUERY_POLICY).should('exist'); + cy.getBySel('shards-field-policy').find(`input[value="${OSQUERY_POLICY}"]`).should('exist'); cy.getBySel(POLICY_SELECT_COMBOBOX).click(); cy.get('[data-test-subj="packShardsForm-1"]').within(() => { cy.get(`[aria-label="Delete shards row"]`).click(); diff --git a/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts b/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts index d512f5d5df5bb8..afa0482c90a26f 100644 --- a/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts +++ b/x-pack/plugins/osquery/cypress/e2e/roles/t1_and_t2_analyst.cy.ts @@ -79,7 +79,9 @@ describe(`T1 and T2 analysts`, { tags: ['@ess', '@serverless'] }, () => { cy.contains(liveQueryQuery); cy.get(`[aria-label="Run query"]`).first().should('not.be.disabled'); cy.get(`[aria-label="Run query"]`).first().click(); - cy.contains(savedQueryName); + cy.get('[data-test-subj="savedQuerySelect"]') + .find('input') + .should('have.value', savedQueryName); submitQuery(); checkResults(); }); diff --git a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap index 06ae63fee31288..16b666d519c467 100644 --- a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap +++ b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap @@ -134,7 +134,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "canvas" layout class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isClosed" id="advanced-options" inert="" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -331,7 +331,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "print" layout o class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isClosed" id="advanced-options" inert="" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > @@ -469,7 +469,7 @@ exports[`ScreenCapturePanelContent renders the default view properly 1`] = ` class="euiAccordion__childWrapper emotion-euiAccordion__childWrapper-isClosed" id="advanced-options" inert="" - role="region" + role="group" style="block-size: 0;" tabindex="-1" > diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx index e336d75969246f..e0b0156db75686 100644 --- a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx +++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx @@ -197,7 +197,7 @@ describe('', () => { const featurePrivilegeToggles = wrapper.find(EuiButtonGroup); expect(featurePrivilegeToggles).toHaveLength(1); - expect(featurePrivilegeToggles.find('input')).toHaveLength(3); + expect(featurePrivilegeToggles.find('button')).toHaveLength(3); (featurePrivilegeToggles.props() as EuiButtonGroupProps).onChange('feature1_all', null); diff --git a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts index 6350641bf5da30..d2fa41f6d1c1f5 100644 --- a/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts +++ b/x-pack/plugins/security/public/nav_control/nav_control_service.test.ts @@ -80,41 +80,37 @@ describe('SecurityNavControlService', () => { data-test-subj="kbnRedirectAppLink" >
- + +
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap index c676809c3c2a56..d22fb49ab6627b 100644 --- a/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/common/components/event_details/overview/__snapshots__/index.test.tsx.snap @@ -82,33 +82,29 @@ exports[`Event Details Overview Cards renders rows and spacers correctly 1`] = ` class="c2" >
-
- -
+ + +
{ ); expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(1); - expect(wrapper.find('[data-test-subj="entryField"]').text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="threatEntryField"]').text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').props().placeholder).toEqual( + 'Search' + ); + expect(wrapper.find('[data-test-subj="threatEntryField"] input').props().placeholder).toEqual( + 'Search' + ); }); test('it displays "Search" for "listItems" that are passed in', async () => { @@ -108,7 +112,9 @@ describe('ThreatMatchComponent', () => { ); expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(1); - expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').at(0).props().placeholder).toEqual( + 'Search' + ); wrapper.unmount(); }); @@ -171,10 +177,18 @@ describe('ThreatMatchComponent', () => { await waitFor(() => { expect(wrapper.find('EuiFlexGroup[data-test-subj="itemEntryContainer"]')).toHaveLength(2); - expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="threatEntryField"]').at(0).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="entryField"]').at(1).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="threatEntryField"]').at(1).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').at(0).props().placeholder).toEqual( + 'Search' + ); + expect( + wrapper.find('[data-test-subj="threatEntryField"] input').at(0).props().placeholder + ).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').at(1).props().placeholder).toEqual( + 'Search' + ); + expect( + wrapper.find('[data-test-subj="threatEntryField"] input').at(1).props().placeholder + ).toEqual('Search'); }); }); @@ -208,10 +222,18 @@ describe('ThreatMatchComponent', () => { await waitFor(() => { expect(wrapper.find('EuiFlexGroup[data-test-subj="entriesContainer"]')).toHaveLength(2); - expect(wrapper.find('[data-test-subj="entryField"]').at(0).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="threatEntryField"]').at(0).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="entryField"]').at(1).text()).toEqual('Search'); - expect(wrapper.find('[data-test-subj="threatEntryField"]').at(1).text()).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').at(0).props().placeholder).toEqual( + 'Search' + ); + expect( + wrapper.find('[data-test-subj="threatEntryField"] input').at(0).props().placeholder + ).toEqual('Search'); + expect(wrapper.find('[data-test-subj="entryField"] input').at(1).props().placeholder).toEqual( + 'Search' + ); + expect( + wrapper.find('[data-test-subj="threatEntryField"] input').at(1).props().placeholder + ).toEqual('Search'); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/use_combo_box_reset/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/use_combo_box_reset/index.test.tsx index e9082e2ca72a9d..24f813cf81a5cb 100644 --- a/x-pack/plugins/security_solution/public/common/components/use_combo_box_reset/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/use_combo_box_reset/index.test.tsx @@ -65,21 +65,21 @@ describe('useEuiComboBoxReset', () => { render(); - const initialValue = screen.getByTestId('comboBoxInput'); // EuiComboBox does NOT render the current selection via it's input; it uses this div - expect(initialValue).toHaveTextContent(options[0].label); + const initialValue = screen.getByRole('combobox'); + expect(initialValue).toHaveValue(options[0].label); // update the EuiComboBox input to an invalid value: - const searchInput = screen.getByTestId('comboBoxSearchInput'); // the actual controlled by EuiComboBox + const searchInput = screen.getByRole('combobox'); // the actual controlled by EuiComboBox fireEvent.change(searchInput, { target: { value: invalidValue } }); - const afterInvalidInput = screen.getByTestId('comboBoxInput'); + const afterInvalidInput = screen.getByRole('combobox'); expect(searchInput).toHaveValue(invalidValue); // the EuiComboBox is now in the "error state" expect(afterInvalidInput).not.toHaveTextContent(invalidValue); // Value should not have been applied const resetButton = screen.getByRole('button', { name: 'Reset' }); fireEvent.click(resetButton); // clicking invokes onReset() - const afterReset = screen.getByTestId('comboBoxInput'); - expect(afterReset).toHaveTextContent(options[0].label); // back to the default + const afterReset = screen.getByRole('combobox'); + expect(afterReset).toHaveValue(options[0].label); // back to the default }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/with_hover_actions/index.tsx b/x-pack/plugins/security_solution/public/common/components/with_hover_actions/index.tsx index 85b1def4c41018..509d7610cb0fb2 100644 --- a/x-pack/plugins/security_solution/public/common/components/with_hover_actions/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/with_hover_actions/index.tsx @@ -11,20 +11,12 @@ import { IS_DRAGGING_CLASS_NAME, } from '@kbn/securitysolution-t-grid'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import styled from 'styled-components'; /** * To avoid expensive changes to the DOM, delay showing the popover menu */ const HOVER_INTENT_DELAY = 100; // ms -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const WithHoverActionsPopover = styled(EuiPopover as any)` - .euiPopover__anchor { - width: 100%; - } -` as unknown as typeof EuiPopover; - interface Props { /** * Always show the hover menu contents (default: false) @@ -157,7 +149,7 @@ export const WithHoverActions = React.memo( className={alwaysShow ? HOVER_ACTIONS_ALWAYS_SHOW_CLASS_NAME : ''} onMouseLeave={onMouseLeave} > - ( repositionOnScroll={true} > {isOpen ?
{hoverContent}
: null} -
+
); } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx index 75d132b7616543..b23786f07f379f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field.tsx @@ -14,8 +14,7 @@ import * as i18n from '../../../../../detections/pages/detection_engine/rules/tr const SearchBarWrapper = styled(EuiFlexItem)` min-width: 200px; - & .euiPopover, - & .euiPopover__anchor { + & .euiPopover { // This is needed to "cancel" styles passed down from EuiTourStep that // interfere with EuiFieldSearch and don't allow it to take the full width display: block; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx index 8ec9c52e0b773a..e1a6440edd0d00 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.test.tsx @@ -148,11 +148,7 @@ describe('StepAboutRuleToggleDetails', () => { expect(wrapper.find('[idSelected="details"]').exists()).toBeTruthy(); expect(wrapper.find('[idSelected="notes"]').exists()).toBeFalsy(); - wrapper - .find('[title="Investigation guide"]') - .at(0) - .find('input') - .simulate('change', { target: { value: 'notes' } }); + wrapper.find('button[title="Investigation guide"]').simulate('click'); expect(wrapper.find('[idSelected="details"]').exists()).toBeFalsy(); expect(wrapper.find('[idSelected="notes"]').exists()).toBeTruthy(); @@ -174,11 +170,7 @@ describe('StepAboutRuleToggleDetails', () => { ); - wrapper - .find('[title="Investigation guide"]') - .at(0) - .find('input') - .simulate('change', { target: { value: 'notes' } }); + wrapper.find('button[title="Investigation guide"]').simulate('click'); expect(wrapper.find('EuiButtonGroup[idSelected="notes"]').exists()).toBeTruthy(); expect(wrapper.find('div.euiMarkdownFormat').text()).toEqual( @@ -254,11 +246,7 @@ describe('StepAboutRuleToggleDetails', () => { expect(wrapper.find('[idSelected="notes"]').exists()).toBeFalsy(); expect(wrapper.find('[idSelected="setup"]').exists()).toBeFalsy(); - wrapper - .find('[title="Setup guide"]') - .at(0) - .find('input') - .simulate('change', { target: { value: 'setup' } }); + wrapper.find('button[title="Setup guide"]').simulate('click'); expect(wrapper.find('[idSelected="details"]').exists()).toBeFalsy(); expect(wrapper.find('[idSelected="notes"]').exists()).toBeFalsy(); @@ -281,11 +269,7 @@ describe('StepAboutRuleToggleDetails', () => { ); - wrapper - .find('[title="Setup guide"]') - .at(0) - .find('input') - .simulate('change', { target: { value: 'setup' } }); + wrapper.find('button[title="Setup guide"]').simulate('click'); expect(wrapper.find('EuiButtonGroup[idSelected="setup"]').exists()).toBeTruthy(); expect(wrapper.find('div.euiMarkdownFormat').text()).toEqual( diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.test.tsx index b38f10994eb131..c8707897d18a88 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.test.tsx @@ -393,16 +393,15 @@ describe('StepDefineRule', () => { ); expect(getByTestId(`eqlQueryBarTextInput`).textContent).toEqual(eqlQuery.queryBar.query.query); fireEvent.click(getByTestId(`eql-settings-trigger`)); - expect( - within(getByTestId(`eql-event-category-field`)).queryByText( - eqlQuery.eqlOptions.eventCategoryField - ) - ).toBeInTheDocument(); - expect( - within(getByTestId(`eql-tiebreaker-field`)).queryByText(eqlQuery.eqlOptions.tiebreakerField) - ).toBeInTheDocument(); - expect( - within(getByTestId(`eql-timestamp-field`)).queryByText(eqlQuery.eqlOptions.timestampField) - ).toBeInTheDocument(); + + expect(within(getByTestId(`eql-event-category-field`)).queryByRole('combobox')).toHaveValue( + eqlQuery.eqlOptions.eventCategoryField + ); + expect(within(getByTestId(`eql-tiebreaker-field`)).queryByRole('combobox')).toHaveValue( + eqlQuery.eqlOptions.tiebreakerField + ); + expect(within(getByTestId(`eql-timestamp-field`)).queryByRole('combobox')).toHaveValue( + eqlQuery.eqlOptions.timestampField + ); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/chart_select/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/chart_select/index.test.tsx index d5e956da14c0ee..4d7798a4fcbe67 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/chart_select/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/chart_select/index.test.tsx @@ -62,23 +62,33 @@ describe('ChartSelect', () => { ); expect(screen.getByTestId('chart-select-tabs')).toBeInTheDocument(); - expect(screen.getByTestId('trend')).toBeChecked(); + expect(screen.getByTitle('Trend')).toHaveAttribute('aria-pressed', 'true'); }); - test('changing selection render correctly when alertsPageChartsEnabled is true', async () => { + test('changing selection render correctly when alertsPageChartsEnabled is true', () => { mockUseIsExperimentalFeatureEnabled.mockReturnValue(true); const setAlertViewSelection = jest.fn(); - const { container } = render( + const { rerender } = render( ); - const button = container.querySelector('input[value="treemap"]'); - if (button) { - fireEvent.change(button, { target: { checked: true, type: 'radio' } }); - } - expect(screen.getByTestId('treemap')).toBeChecked(); - expect(screen.getByTestId('trend')).not.toBeChecked(); + expect(screen.getByTitle('Trend')).toHaveAttribute('aria-pressed', 'true'); + + const treemapButton = screen.getByTitle('Treemap'); + expect(treemapButton).toHaveAttribute('aria-pressed', 'false'); + + fireEvent.click(treemapButton); + expect(setAlertViewSelection).toHaveBeenCalledWith('treemap'); + + rerender( + + + + ); + + expect(screen.getByTitle('Treemap')).toHaveAttribute('aria-pressed', 'true'); + expect(screen.getByTitle('Trend')).toHaveAttribute('aria-pressed', 'false'); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/index.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/index.test.tsx index 07f07df47d8884..feb8b0ead2be48 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/chart_panels/index.test.tsx @@ -245,22 +245,21 @@ describe('ChartPanels', () => { ); - const initialValue = screen.getAllByTestId('comboBoxInput')[0]; // EuiComboBox does NOT render the current selection via it's input; it uses this div - expect(initialValue).toHaveTextContent(defaultValue); + const initialInput = screen.getAllByTestId('comboBoxSearchInput')[0]; + expect(initialInput).toHaveValue(defaultValue); // update the EuiComboBox input to an invalid value: - const searchInput = screen.getAllByTestId('comboBoxSearchInput')[0]; // the actual controlled by EuiComboBox - fireEvent.change(searchInput, { target: { value: invalidValue } }); + fireEvent.change(initialInput, { target: { value: invalidValue } }); - const afterInvalidInput = screen.getAllByTestId('comboBoxInput')[0]; - expect(searchInput).toHaveValue(invalidValue); // the 'Group by' EuiComboBox is now in the "error state" - expect(afterInvalidInput).not.toHaveTextContent(invalidValue); // Value should not have been applied + const afterInvalidInput = screen.getAllByTestId('comboBoxSearchInput')[0]; + expect(afterInvalidInput).toHaveValue(invalidValue); // the 'Group by' EuiComboBox is now in the "error state" + expect(afterInvalidInput).toBeInvalid(); resetGroupByFields(); // invoke the `Reset group by fields` context menu action await waitFor(() => { - const afterReset = screen.getAllByTestId('comboBoxInput')[0]; - expect(afterReset).toHaveTextContent(defaultValue); // back to the default + const afterReset = screen.getAllByTestId('comboBoxSearchInput')[0]; + expect(afterReset).toHaveValue(defaultValue); // back to the default }); }); }); @@ -285,22 +284,21 @@ describe('ChartPanels', () => { ); - const initialValue = screen.getAllByTestId('comboBoxInput')[1]; // EuiComboBox does NOT render the current selection via it's input; it uses this div - expect(initialValue).toHaveTextContent(defaultValue); + const initialInput = screen.getAllByTestId('comboBoxSearchInput')[1]; + expect(initialInput).toHaveValue(defaultValue); // update the EuiComboBox input to an invalid value: - const searchInput = screen.getAllByTestId('comboBoxSearchInput')[1]; // the actual controlled by EuiComboBox - fireEvent.change(searchInput, { target: { value: invalidValue } }); + fireEvent.change(initialInput, { target: { value: invalidValue } }); - const afterInvalidInput = screen.getAllByTestId('comboBoxInput')[1]; - expect(searchInput).toHaveValue(invalidValue); // the 'Group by top' EuiComboBox is now in the "error state" - expect(afterInvalidInput).not.toHaveTextContent(invalidValue); // Value should not have been applied + const afterInvalidInput = screen.getAllByTestId('comboBoxSearchInput')[1]; + expect(afterInvalidInput).toHaveValue(invalidValue); // the 'Group by top' EuiComboBox is now in the "error state" + expect(afterInvalidInput).toBeInvalid(); resetGroupByFields(); // invoke the `Reset group by fields` context menu action await waitFor(() => { - const afterReset = screen.getAllByTestId('comboBoxInput')[1]; - expect(afterReset).toHaveTextContent(defaultValue); // back to the default + const afterReset = screen.getAllByTestId('comboBoxSearchInput')[1]; + expect(afterReset).toHaveValue(defaultValue); // back to the default }); }); }); diff --git a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap index cebd8a483aafba..b0b2754c24d3bc 100644 --- a/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/explore/components/authentication/__snapshots__/authentications_host_table.test.tsx.snap @@ -374,32 +374,28 @@ exports[`Authentication Host Table Component rendering it renders the host authe class="euiFlexItem emotion-euiFlexItem-grow-1" >
-
- -
+ + +
-
- -
+ + +
diff --git a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx index 174496f1f3d211..f3fdb0b8009be2 100644 --- a/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/effected_policy_select/effected_policy_select.test.tsx @@ -74,13 +74,13 @@ describe('when using EffectedPolicySelect component', () => { const selectGlobalPolicy = () => { act(() => { - fireEvent.click(renderResult.getByTestId('globalPolicy')); + fireEvent.click(renderResult.getByTestId('test-global')); }); }; const selectPerPolicy = () => { act(() => { - fireEvent.click(renderResult.getByTestId('perPolicy')); + fireEvent.click(renderResult.getByTestId('test-perPolicy')); }); }; @@ -142,7 +142,8 @@ describe('when using EffectedPolicySelect component', () => { }); it('should maintain policies selection even if global was checked, and user switched back to per policy', () => { - render(); + const { debug } = render(); + debug(undefined, 999999); selectPerPolicy(); clickOnPolicy(); diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts index a736e05c331451..6bbb565d7546f8 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts @@ -26,7 +26,7 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +describe.skip('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts index 3d92528c2eee72..1fa34d232a7423 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts @@ -22,7 +22,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +describe.skip( 'Unenroll agent from fleet when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts index a9508a13f719b3..d744abcb5b431c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts @@ -22,7 +22,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +describe.skip( 'Unenroll agent from fleet changing when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts index bbb675cf56d5ed..069f4eb7c727b4 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts @@ -24,7 +24,7 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx index e07dc6f2d081bd..c7d1c3a46d442d 100644 --- a/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/blocklist/view/components/blocklist_form.test.tsx @@ -368,7 +368,7 @@ describe('blocklist form', () => { it('should default to global policy', () => { render(); - expect(screen.getByTestId('globalPolicy')).toBeEnabled(); + expect(screen.getByTestId('blocklist-form-effectedPolicies-global')).toBeEnabled(); }); it('should correctly edit policies', () => { @@ -383,7 +383,7 @@ describe('blocklist form', () => { }, ] as PolicyData[]; render(createProps({ policies })); - const byPolicyButton = screen.getByTestId('perPolicy'); + const byPolicyButton = screen.getByTestId('blocklist-form-effectedPolicies-perPolicy'); userEvent.click(byPolicyButton); expect(byPolicyButton).toBeEnabled(); @@ -408,9 +408,9 @@ describe('blocklist form', () => { }, ] as PolicyData[]; render(createProps({ policies, item: createItem({ tags: [`policy:${policies[1].id}`] }) })); - expect(screen.getByTestId('globalPolicy')).toBeEnabled(); + expect(screen.getByTestId('blocklist-form-effectedPolicies-global')).toBeEnabled(); - const byPolicyButton = screen.getByTestId('perPolicy'); + const byPolicyButton = screen.getByTestId('blocklist-form-effectedPolicies-perPolicy'); userEvent.click(byPolicyButton); expect(byPolicyButton).toBeEnabled(); userEvent.click(screen.getByText(policies[0].name)); diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx index 2870a67e7042cb..168ecc6b84a72c 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/form.test.tsx @@ -281,7 +281,7 @@ describe('Event filter form', () => { it('should display the policy list when "per policy" is selected', async () => { render(); - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click(renderResult.getByTestId('eventFilters-form-effectedPolicies-perPolicy')); rerenderWithLatestProps(); // policy selector should show up expect( @@ -308,17 +308,21 @@ describe('Event filter form', () => { it('should have global policy by default', async () => { render(); - expect(renderResult.getByTestId('globalPolicy')).toBeChecked(); - expect(renderResult.getByTestId('perPolicy')).not.toBeChecked(); + expect(renderResult.getByTestId('eventFilters-form-effectedPolicies-global')).toHaveAttribute( + 'aria-pressed', + 'true' + ); + expect( + renderResult.getByTestId('eventFilters-form-effectedPolicies-perPolicy') + ).toHaveAttribute('aria-pressed', 'false'); }); it('should retain the previous policy selection when switching from per-policy to global', async () => { formProps.item.tags = [formProps.policies.map((p) => `policy:${p.id}`)[0]]; render(); const policyId = formProps.policies[0].id; - // move to per-policy and select the first - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click(renderResult.getByTestId('eventFilters-form-effectedPolicies-perPolicy')); userEvent.click(renderResult.getByTestId(`policy-${policyId}`)); formProps.item.tags = formProps.onChange.mock.calls[0][0].item.tags; rerender(); @@ -328,7 +332,7 @@ describe('Event filter form', () => { expect(formProps.item.tags).toEqual([`policy:${policyId}`]); // move back to global - userEvent.click(renderResult.getByTestId('globalPolicy')); + userEvent.click(renderResult.getByTestId('eventFilters-form-effectedPolicies-global')); formProps.item.tags = ['policy:all']; rerenderWithLatestProps(); expect(formProps.item.tags).toEqual(['policy:all']); @@ -337,7 +341,7 @@ describe('Event filter form', () => { ).toBeFalsy(); // move back to per-policy - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click(renderResult.getByTestId('eventFilters-form-effectedPolicies-perPolicy')); formProps.item.tags = [`policy:${policyId}`]; rerender(); // on change called with the previous policy @@ -379,13 +383,17 @@ describe('Event filter form', () => { formProps.item.tags = ['policy:id-0']; rerender(); - expect(renderResult.queryByTestId('perPolicy')).not.toBeNull(); + expect( + renderResult.queryByTestId('eventFilters-form-effectedPolicies-perPolicy') + ).not.toBeNull(); expect(renderResult.getByTestId('policy-id-0').getAttribute('aria-disabled')).toBe('true'); }); it("allows the user to set the event filter entry to 'Global' in the edit option", () => { render(); - const globalButtonInput = renderResult.getByTestId('globalPolicy') as HTMLButtonElement; + const globalButtonInput = renderResult.getByTestId( + 'eventFilters-form-effectedPolicies-global' + ) as HTMLButtonElement; userEvent.click(globalButtonInput); formProps.item.tags = ['policy:all']; rerender(); diff --git a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/integration_tests/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/integration_tests/form.test.tsx index 268fa8ac3c47a9..04b94c0262fea5 100644 --- a/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/integration_tests/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/host_isolation_exceptions/view/components/integration_tests/form.test.tsx @@ -146,7 +146,9 @@ describe('When on the host isolation exceptions entry form', () => { }); it('should show policy as selected when user clicks on it', async () => { - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click( + renderResult.getByTestId('hostIsolationExceptions-form-effectedPolicies-perPolicy') + ); await clickOnEffectedPolicy(renderResult, testIdPrefix); await expect(isEffectedPolicySelected(renderResult, testIdPrefix)).resolves.toBe(true); @@ -154,20 +156,26 @@ describe('When on the host isolation exceptions entry form', () => { it('should retain the previous policy selection when switching from per-policy to global', async () => { // move to per-policy and select the first - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click( + renderResult.getByTestId('hostIsolationExceptions-form-effectedPolicies-perPolicy') + ); await clickOnEffectedPolicy(renderResult, testIdPrefix); await expect(isEffectedPolicySelected(renderResult, testIdPrefix)).resolves.toBe(true); // move back to global - userEvent.click(renderResult.getByTestId('globalPolicy')); + userEvent.click( + renderResult.getByTestId('hostIsolationExceptions-form-effectedPolicies-global') + ); expect( renderResult.queryByTestId(`${testIdPrefix}-effectedPolicies-policiesSelectable`) ).toBeFalsy(); // move back to per-policy - userEvent.click(renderResult.getByTestId('perPolicy')); + userEvent.click( + renderResult.getByTestId('hostIsolationExceptions-form-effectedPolicies-perPolicy') + ); await expect(isEffectedPolicySelected(renderResult, testIdPrefix)).resolves.toBe(true); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/form.test.tsx b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/form.test.tsx index cc0111f23c4169..df4b06ecc2b9c8 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/form.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/form.test.tsx @@ -430,7 +430,9 @@ describe('Trusted apps form', () => { expect(renderResult.getByTestId('policy-id-0-checkbox')).toBeChecked(); }); it("allows the user to set the trusted app entry to 'Global' in the edit option", () => { - const globalButtonInput = renderResult.getByTestId('globalPolicy') as HTMLButtonElement; + const globalButtonInput = renderResult.getByTestId( + 'trustedApps-form-effectedPolicies-global' + ) as HTMLButtonElement; act(() => { fireEvent.click(globalButtonInput); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.test.tsx index 8fd5dce2da0d2a..edcadfb2d391ab 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/edit_data_provider/index.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { render, screen } from '@testing-library/react'; +import { render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -42,7 +42,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText(field)).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('field'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue(field); }); test('it renders the expected placeholder for the current field when field is empty', () => { @@ -82,7 +83,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('is')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('is'); }); test('it renders the negated "is" operator in a humanized format when isExcluded is true', () => { @@ -102,7 +104,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('is not')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('is not'); }); test('it renders the "exists" operator in human-readable format', () => { @@ -122,7 +125,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('exists')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('exists'); }); test('it renders the negated "exists" operator in a humanized format when isExcluded is true', () => { @@ -142,7 +146,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('does not exist')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('does not exist'); }); test('it renders the "is one of" operator in human-readable format', () => { @@ -162,7 +167,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('is one of')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('is one of'); }); test('it renders the negated "is one of" operator in a humanized format when isExcluded is true', () => { @@ -182,7 +188,8 @@ describe('StatefulEditDataProvider', () => { ); - expect(screen.getByText('is not one of')).toBeInTheDocument(); + const fieldWrapper = screen.getByTestId('operator'); + expect(within(fieldWrapper).getByTestId('comboBoxSearchInput')).toHaveValue('is not one of'); }); test('it renders the current value when the operator is "is"', () => { @@ -244,7 +251,9 @@ describe('StatefulEditDataProvider', () => { /> ); - expect(screen.getByText('enter one or more values')).toBeInTheDocument(); + + const wrapper = screen.getByTestId('is-one-of-combobox-input'); + expect(within(wrapper).getByPlaceholderText('enter one or more values')).toBeInTheDocument(); }); test('it renders selected values when the type of value is an array and the operator is "is one of"', () => { @@ -326,8 +335,8 @@ describe('StatefulEditDataProvider', () => { ); - // EuiCombobox does not render placeholder text with placeholder tag - expect(screen.getByText('enter one or more values')).toBeInTheDocument(); + const wrapper = screen.getByTestId('is-one-of-combobox-input'); + expect(within(wrapper).getByPlaceholderText('enter one or more values')).toBeInTheDocument(); }); test('it does NOT render value when the operator is "exists"', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap index bf7c1251f52027..2f11cdf57c3a6e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/field_renderers/__snapshots__/field_renderers.test.tsx.snap @@ -2,15 +2,11 @@ exports[`Field Renderers #autonomousSystemRenderer it renders correctly against snapshot 1`] = ` - .c0 .euiPopover__anchor { - width: 100%; -} - -.c1 > span.euiToolTipAnchor { + .c0 > span.euiToolTipAnchor { display: block; } -.c1 > span.euiToolTipAnchor.eui-textTruncate { +.c0 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } @@ -24,29 +20,25 @@ exports[`Field Renderers #autonomousSystemRenderer it renders correctly against class="" >
-
- - Test Org - + Test Org -
+
@@ -64,29 +56,25 @@ exports[`Field Renderers #autonomousSystemRenderer it renders correctly against class="" >
-
- - 12345 - + 12345 -
+
@@ -108,15 +96,11 @@ exports[`Field Renderers #dateRenderer it renders correctly against snapshot 1`] exports[`Field Renderers #hostIdRenderer it renders correctly against snapshot 1`] = ` - .c0 .euiPopover__anchor { - width: 100%; -} - -.c1 > span.euiToolTipAnchor { + .c0 > span.euiToolTipAnchor { display: block; } -.c1 > span.euiToolTipAnchor.eui-textTruncate { +.c0 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } @@ -124,36 +108,32 @@ exports[`Field Renderers #hostIdRenderer it renders correctly against snapshot 1 class="" >
-
- - - raspberrypi - - + raspberrypi + -
+
@@ -163,15 +143,11 @@ exports[`Field Renderers #hostIdRenderer it renders correctly against snapshot 1 exports[`Field Renderers #hostNameRenderer it renders correctly against snapshot 1`] = ` - .c0 .euiPopover__anchor { - width: 100%; -} - -.c1 > span.euiToolTipAnchor { + .c0 > span.euiToolTipAnchor { display: block; } -.c1 > span.euiToolTipAnchor.eui-textTruncate { +.c0 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } @@ -179,36 +155,32 @@ exports[`Field Renderers #hostNameRenderer it renders correctly against snapshot class="" >
-
- - - raspberrypi - - + raspberrypi + -
+
@@ -218,15 +190,11 @@ exports[`Field Renderers #hostNameRenderer it renders correctly against snapshot exports[`Field Renderers #locationRenderer it renders correctly against snapshot 1`] = ` - .c0 .euiPopover__anchor { - width: 100%; -} - -.c1 > span.euiToolTipAnchor { + .c0 > span.euiToolTipAnchor { display: block; } -.c1 > span.euiToolTipAnchor.eui-textTruncate { +.c0 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } @@ -240,29 +208,25 @@ exports[`Field Renderers #locationRenderer it renders correctly against snapshot class="" >
-
- - New York - + New York -
+
@@ -276,29 +240,25 @@ exports[`Field Renderers #locationRenderer it renders correctly against snapshot class="" >
-
- - New York - + New York -
+
diff --git a/x-pack/plugins/security_solution/public/timelines/components/flyout/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/flyout/__snapshots__/index.test.tsx.snap index 5ef25f98932c0f..76ff4c26321beb 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/flyout/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/flyout/__snapshots__/index.test.tsx.snap @@ -69,26 +69,22 @@ exports[`Flyout rendering it renders correctly against snapshot 1`] = ` class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- -
+
diff --git a/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap index 8ad225711b7732..919d237027815b 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/netflow/__snapshots__/index.test.tsx.snap @@ -2,13 +2,13 @@ exports[`Netflow renders correctly against snapshot 1`] = ` - .c13 svg { + .c12 svg { position: relative; top: -1px; } -.c11, -.c11 * { +.c10, +.c10 * { display: inline-block; max-width: 100%; overflow: hidden; @@ -17,18 +17,14 @@ exports[`Netflow renders correctly against snapshot 1`] = ` white-space: nowrap; } -.c1 .euiPopover__anchor { - width: 100%; -} - -.c3 { +.c2 { border-radius: 2px; padding: 0 4px 0 8px; position: relative; z-index: 0 !important; } -.c3::before { +.c2::before { background-image: linear-gradient( 135deg, #535966 25%, transparent 25% ), linear-gradient( -135deg, #535966 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #535966 75% ), linear-gradient( -135deg, transparent 75%, #535966 75% ); background-position: 0 0,1px 0,1px -1px,0px 1px; background-size: 2px 2px; @@ -41,147 +37,147 @@ exports[`Netflow renders correctly against snapshot 1`] = ` width: 4px; } -.c3:hover, -.c3:hover .euiBadge, -.c3:hover .euiBadge__text { +.c2:hover, +.c2:hover .euiBadge, +.c2:hover .euiBadge__text { cursor: move; cursor: -webkit-grab; cursor: -moz-grab; cursor: grab; } -.event-column-view:hover .c3::before, -tr:hover .c3::before { +.event-column-view:hover .c2::before, +tr:hover .c2::before { background-image: linear-gradient( 135deg, #98a2b3 25%, transparent 25% ), linear-gradient( -135deg, #98a2b3 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #98a2b3 75% ), linear-gradient( -135deg, transparent 75%, #98a2b3 75% ); } -.c3:hover, -.c3:focus, -.event-column-view:hover .c3:hover, -.event-column-view:focus .c3:focus, -tr:hover .c3:hover, -tr:hover .c3:focus { +.c2:hover, +.c2:focus, +.event-column-view:hover .c2:hover, +.event-column-view:focus .c2:focus, +tr:hover .c2:hover, +tr:hover .c2:focus { background-color: #36a2ef; } -.c3:hover, -.c3:focus, -.event-column-view:hover .c3:hover, -.event-column-view:focus .c3:focus, -tr:hover .c3:hover, -tr:hover .c3:focus, -.c3:hover a, -.c3:focus a, -.event-column-view:hover .c3:hover a, -.event-column-view:focus .c3:focus a, -tr:hover .c3:hover a, -tr:hover .c3:focus a, -.c3:hover a:hover, -.c3:focus a:hover, -.event-column-view:hover .c3:hover a:hover, -.event-column-view:focus .c3:focus a:hover, -tr:hover .c3:hover a:hover, -tr:hover .c3:focus a:hover { +.c2:hover, +.c2:focus, +.event-column-view:hover .c2:hover, +.event-column-view:focus .c2:focus, +tr:hover .c2:hover, +tr:hover .c2:focus, +.c2:hover a, +.c2:focus a, +.event-column-view:hover .c2:hover a, +.event-column-view:focus .c2:focus a, +tr:hover .c2:hover a, +tr:hover .c2:focus a, +.c2:hover a:hover, +.c2:focus a:hover, +.event-column-view:hover .c2:hover a:hover, +.event-column-view:focus .c2:focus a:hover, +tr:hover .c2:hover a:hover, +tr:hover .c2:focus a:hover { color: #1d1e24; } -.c3:hover::before, -.c3:focus::before, -.event-column-view:hover .c3:hover::before, -.event-column-view:focus .c3:focus::before, -tr:hover .c3:hover::before, -tr:hover .c3:focus::before { +.c2:hover::before, +.c2:focus::before, +.event-column-view:hover .c2:hover::before, +.event-column-view:focus .c2:focus::before, +tr:hover .c2:hover::before, +tr:hover .c2:focus::before { background-image: linear-gradient( 135deg, #1d1e24 25%, transparent 25% ), linear-gradient( -135deg, #1d1e24 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #1d1e24 75% ), linear-gradient( -135deg, transparent 75%, #1d1e24 75% ); } -.c2 { +.c1 { display: inline-block; max-width: 100%; } -.c2 [data-rbd-placeholder-context-id] { +.c1 [data-rbd-placeholder-context-id] { display: none !important; } -.c4 > span.euiToolTipAnchor { +.c3 > span.euiToolTipAnchor { display: block; } -.c4 > span.euiToolTipAnchor.eui-textTruncate { +.c3 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } -.c5 { +.c4 { vertical-align: top; } -.c22 { +.c21 { margin-right: 5px; } -.c21 { +.c20 { margin-right: 5px; } -.c15 { +.c14 { position: relative; top: 1px; } -.c14 { +.c13 { margin-right: 5px; } -.c17 { +.c16 { background-color: #343741; height: 2.8px; width: 25px; } -.c20 { +.c19 { background-color: #343741; height: 2.2px; width: 25px; } -.c19 { +.c18 { margin-right: 5px; } -.c16 { +.c15 { margin: 0 2px; } -.c16 .euiToolTipAnchor { +.c15 .euiToolTipAnchor { white-space: nowrap; } -.c18 { +.c17 { margin: 0 5px; } -.c7 { +.c6 { margin-right: 3px; } -.c8 { +.c7 { margin: 0 5px; } -.c12 { +.c11 { margin: 0 3px; } -.c10 { +.c9 { font-weight: bold; margin-top: 2px; } -.c9 { +.c8 { margin-top: 3px; } -.c6 { +.c5 { margin-right: 3px; position: relative; top: -1px; @@ -216,69 +212,65 @@ tr:hover .c3:focus::before { class="" >
-
+ - - - first.last - + first.last -
+
@@ -294,69 +286,65 @@ tr:hover .c3:focus::before { class="" >
-
+ - - - rat - + rat -
+
@@ -381,63 +369,59 @@ tr:hover .c3:focus::before { class="" >
-
- -
+ - - -
- 1ms -
-
-
-
-
+ 1ms +
+ +
+
@@ -453,59 +437,55 @@ tr:hover .c3:focus::before { class="" >
-
- -
+ - - - Nov 12, 2018 @ 19:03:25.836 - -
-
-
+ Nov 12, 2018 @ 19:03:25.836 + +
+
@@ -521,59 +501,55 @@ tr:hover .c3:focus::before { class="" >
-
- -
+ - - - Nov 12, 2018 @ 19:03:25.936 - -
-
-
+ Nov 12, 2018 @ 19:03:25.936 + +
+
@@ -597,75 +573,71 @@ tr:hover .c3:focus::before { class="euiFlexGroup emotion-euiFlexGroup-responsive-none-center-center-row" >
-
+ - - - outgoing - + outgoing -
+
@@ -675,70 +647,66 @@ tr:hover .c3:focus::before {
-
- - http - + http -
+
@@ -748,63 +716,59 @@ tr:hover .c3:focus::before {
-
- -
- - 100B - -
-
+ + 100B + +
-
+
@@ -814,63 +778,59 @@ tr:hover .c3:focus::before {
-
- -
- - 3 pkts - -
-
+ + 3 pkts + +
-
+
@@ -880,70 +840,66 @@ tr:hover .c3:focus::before {
-
- - tcp - + tcp -
+
@@ -959,64 +915,60 @@ tr:hover .c3:focus::before { class="" >
-
- - we.live.in.a - + we.live.in.a -
+
@@ -1028,7 +980,7 @@ tr:hover .c3:focus::before {
Source
@@ -1079,58 +1031,54 @@ tr:hover .c3:focus::before { class="" >
-
- - - 192.168.1.2 - - + 192.168.1.2 + -
+
@@ -1149,7 +1097,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" > : @@ -1159,7 +1107,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- - North America - + North America -
+
@@ -1264,7 +1208,7 @@ tr:hover .c3:focus::before {
-
- - United States - + United States -
+
@@ -1332,7 +1272,7 @@ tr:hover .c3:focus::before {
🇺🇸 @@ -1354,51 +1294,47 @@ tr:hover .c3:focus::before { class="" >
-
- - US - + US -
+
@@ -1410,7 +1346,7 @@ tr:hover .c3:focus::before {
-
- - Georgia - + Georgia -
+
@@ -1478,7 +1410,7 @@ tr:hover .c3:focus::before {
-
- - Atlanta - + Atlanta -
+
@@ -1553,7 +1481,7 @@ tr:hover .c3:focus::before {
@@ -1576,62 +1504,58 @@ tr:hover .c3:focus::before { class="" >
-
- -
- - (60.00%) - - - 60B - -
-
+ (60.00%) +
+ + 60B + +
-
+
@@ -1644,7 +1568,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1655,57 +1579,53 @@ tr:hover .c3:focus::before { class="" >
-
- -
- - 2 pkts - -
-
+ + 2 pkts + +
-
+
@@ -1718,7 +1638,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1752,7 +1672,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1763,62 +1683,58 @@ tr:hover .c3:focus::before { class="" >
-
- -
- - (40.00%) - - - 40B - -
-
+ (40.00%) +
+ + 40B + +
-
+
@@ -1831,7 +1747,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1842,57 +1758,53 @@ tr:hover .c3:focus::before { class="" >
-
- -
- - 1 pkts - -
-
+ + 1 pkts + +
-
+
@@ -1905,7 +1817,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1934,7 +1846,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
Destination
@@ -1958,58 +1870,54 @@ tr:hover .c3:focus::before { class="" >
-
- - - 10.1.2.3 - - + 10.1.2.3 + -
+
@@ -2028,7 +1936,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" > : @@ -2038,7 +1946,7 @@ tr:hover .c3:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- - North America - + North America -
+
@@ -2143,7 +2047,7 @@ tr:hover .c3:focus::before {
-
- - United States - + United States -
+
@@ -2211,7 +2111,7 @@ tr:hover .c3:focus::before {
🇺🇸 @@ -2233,51 +2133,47 @@ tr:hover .c3:focus::before { class="" >
-
- - US - + US -
+
@@ -2289,7 +2185,7 @@ tr:hover .c3:focus::before {
-
- - New York - + New York -
+
@@ -2357,7 +2249,7 @@ tr:hover .c3:focus::before {
-
- - New York - + New York -
+
@@ -2451,93 +2339,89 @@ tr:hover .c3:focus::before { class="" >
@@ -2553,93 +2437,89 @@ tr:hover .c3:focus::before { class="" >
@@ -2655,93 +2535,89 @@ tr:hover .c3:focus::before { class="" >
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx index c10a7fd829f9f6..945c999dbe6398 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/column_headers/column_header.tsx @@ -42,7 +42,7 @@ const ContextMenu = styled(EuiContextMenu)` `; const PopoverContainer = styled.div<{ $width: number }>` - & .euiPopover__anchor { + & .euiPopover { padding-right: 8px; width: ${({ $width }) => $width}px; } diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/netflow/__snapshots__/netflow_row_renderer.test.tsx.snap b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/netflow/__snapshots__/netflow_row_renderer.test.tsx.snap index e9f09d689f0cdd..803a4f84552f29 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/netflow/__snapshots__/netflow_row_renderer.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/netflow/__snapshots__/netflow_row_renderer.test.tsx.snap @@ -16,13 +16,13 @@ exports[`netflowRowRenderer renders correctly against snapshot 1`] = ` border-radius: 4px; } -.c15 svg { +.c14 svg { position: relative; top: -1px; } -.c13, -.c13 * { +.c12, +.c12 * { display: inline-block; max-width: 100%; overflow: hidden; @@ -31,18 +31,14 @@ exports[`netflowRowRenderer renders correctly against snapshot 1`] = ` white-space: nowrap; } -.c3 .euiPopover__anchor { - width: 100%; -} - -.c5 { +.c4 { border-radius: 2px; padding: 0 4px 0 8px; position: relative; z-index: 0 !important; } -.c5::before { +.c4::before { background-image: linear-gradient( 135deg, #535966 25%, transparent 25% ), linear-gradient( -135deg, #535966 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #535966 75% ), linear-gradient( -135deg, transparent 75%, #535966 75% ); background-position: 0 0,1px 0,1px -1px,0px 1px; background-size: 2px 2px; @@ -55,147 +51,147 @@ exports[`netflowRowRenderer renders correctly against snapshot 1`] = ` width: 4px; } -.c5:hover, -.c5:hover .euiBadge, -.c5:hover .euiBadge__text { +.c4:hover, +.c4:hover .euiBadge, +.c4:hover .euiBadge__text { cursor: move; cursor: -webkit-grab; cursor: -moz-grab; cursor: grab; } -.event-column-view:hover .c5::before, -tr:hover .c5::before { +.event-column-view:hover .c4::before, +tr:hover .c4::before { background-image: linear-gradient( 135deg, #98a2b3 25%, transparent 25% ), linear-gradient( -135deg, #98a2b3 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #98a2b3 75% ), linear-gradient( -135deg, transparent 75%, #98a2b3 75% ); } -.c5:hover, -.c5:focus, -.event-column-view:hover .c5:hover, -.event-column-view:focus .c5:focus, -tr:hover .c5:hover, -tr:hover .c5:focus { +.c4:hover, +.c4:focus, +.event-column-view:hover .c4:hover, +.event-column-view:focus .c4:focus, +tr:hover .c4:hover, +tr:hover .c4:focus { background-color: #36a2ef; } -.c5:hover, -.c5:focus, -.event-column-view:hover .c5:hover, -.event-column-view:focus .c5:focus, -tr:hover .c5:hover, -tr:hover .c5:focus, -.c5:hover a, -.c5:focus a, -.event-column-view:hover .c5:hover a, -.event-column-view:focus .c5:focus a, -tr:hover .c5:hover a, -tr:hover .c5:focus a, -.c5:hover a:hover, -.c5:focus a:hover, -.event-column-view:hover .c5:hover a:hover, -.event-column-view:focus .c5:focus a:hover, -tr:hover .c5:hover a:hover, -tr:hover .c5:focus a:hover { +.c4:hover, +.c4:focus, +.event-column-view:hover .c4:hover, +.event-column-view:focus .c4:focus, +tr:hover .c4:hover, +tr:hover .c4:focus, +.c4:hover a, +.c4:focus a, +.event-column-view:hover .c4:hover a, +.event-column-view:focus .c4:focus a, +tr:hover .c4:hover a, +tr:hover .c4:focus a, +.c4:hover a:hover, +.c4:focus a:hover, +.event-column-view:hover .c4:hover a:hover, +.event-column-view:focus .c4:focus a:hover, +tr:hover .c4:hover a:hover, +tr:hover .c4:focus a:hover { color: #1d1e24; } -.c5:hover::before, -.c5:focus::before, -.event-column-view:hover .c5:hover::before, -.event-column-view:focus .c5:focus::before, -tr:hover .c5:hover::before, -tr:hover .c5:focus::before { +.c4:hover::before, +.c4:focus::before, +.event-column-view:hover .c4:hover::before, +.event-column-view:focus .c4:focus::before, +tr:hover .c4:hover::before, +tr:hover .c4:focus::before { background-image: linear-gradient( 135deg, #1d1e24 25%, transparent 25% ), linear-gradient( -135deg, #1d1e24 25%, transparent 25% ), linear-gradient( 135deg, transparent 75%, #1d1e24 75% ), linear-gradient( -135deg, transparent 75%, #1d1e24 75% ); } -.c4 { +.c3 { display: inline-block; max-width: 100%; } -.c4 [data-rbd-placeholder-context-id] { +.c3 [data-rbd-placeholder-context-id] { display: none !important; } -.c6 > span.euiToolTipAnchor { +.c5 > span.euiToolTipAnchor { display: block; } -.c6 > span.euiToolTipAnchor.eui-textTruncate { +.c5 > span.euiToolTipAnchor.eui-textTruncate { display: inline-block; } -.c7 { +.c6 { vertical-align: top; } -.c24 { +.c23 { margin-right: 5px; } -.c23 { +.c22 { margin-right: 5px; } -.c9 { +.c8 { margin-right: 3px; } -.c10 { +.c9 { margin: 0 5px; } -.c19 { +.c18 { background-color: #343741; height: 2.8px; width: 25px; } -.c22 { +.c21 { background-color: #343741; height: 2.2px; width: 25px; } -.c21 { +.c20 { margin-right: 5px; } -.c18 { +.c17 { margin: 0 2px; } -.c18 .euiToolTipAnchor { +.c17 .euiToolTipAnchor { white-space: nowrap; } -.c20 { +.c19 { margin: 0 5px; } -.c17 { +.c16 { position: relative; top: 1px; } -.c16 { +.c15 { margin-right: 5px; } -.c14 { +.c13 { margin: 0 3px; } -.c12 { +.c11 { font-weight: bold; margin-top: 2px; } -.c11 { +.c10 { margin-top: 3px; } -.c8 { +.c7 { margin-right: 3px; position: relative; top: -1px; @@ -240,79 +236,75 @@ tr:hover .c5:focus::before { class="" >
-
+ user.name +

+ -

- user.name -

+ - - - first.last - + first.last -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -328,79 +320,75 @@ tr:hover .c5:focus::before { class="" >
-
+ process.name +

+ -

- process.name -

+ - - - rat - + rat -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -425,73 +413,69 @@ tr:hover .c5:focus::before { class="" >
-
+ event.duration +

+ -

- event.duration -

- -
+ - - -
- 1ms -
-
-
-
-

- Press enter for options, or press space to begin dragging. -

-
+ 1ms +
+ +
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -507,69 +491,65 @@ tr:hover .c5:focus::before { class="" >
-
+ event.start +

+ -

- event.start -

- -
+ - - - Nov 12, 2018 @ 19:03:25.836 - -
-
-

- Press enter for options, or press space to begin dragging. -

-
+ Nov 12, 2018 @ 19:03:25.836 + +
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -585,69 +565,65 @@ tr:hover .c5:focus::before { class="" >
-
+ event.end +

+ -

- event.end -

- -
+ - - - Nov 12, 2018 @ 19:03:25.936 - -
-
-

- Press enter for options, or press space to begin dragging. -

-
+ Nov 12, 2018 @ 19:03:25.936 + +
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -671,85 +647,81 @@ tr:hover .c5:focus::before { class="euiFlexGroup emotion-euiFlexGroup-responsive-none-center-center-row" >
-
+ network.direction +

+ -

- network.direction -

+ - - - outgoing - + outgoing -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -759,80 +731,76 @@ tr:hover .c5:focus::before {
-
+ network.protocol +

+ -

- network.protocol -

- - http - + http -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -842,73 +810,69 @@ tr:hover .c5:focus::before {
-
+ network.bytes +

+ -

- network.bytes -

- -
- - 100B - -
-
+ + 100B + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -918,73 +882,69 @@ tr:hover .c5:focus::before {
-
+ network.packets +

+ -

- network.packets -

- -
- - 3 pkts - -
-
+ + 3 pkts + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -994,80 +954,76 @@ tr:hover .c5:focus::before {
-
+ network.transport +

+ -

- network.transport -

- - tcp - + tcp -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1083,74 +1039,70 @@ tr:hover .c5:focus::before { class="" >
-
+ network.community_id +

+ -

- network.community_id -

- - we.live.in.a - + we.live.in.a -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1162,7 +1114,7 @@ tr:hover .c5:focus::before {
Source
@@ -1213,68 +1165,64 @@ tr:hover .c5:focus::before { class="" >
-
+ source.ip +

+ -

- source.ip -

- - - 192.168.1.2 - - + 192.168.1.2 + -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1293,7 +1241,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" > : @@ -1306,84 +1254,80 @@ tr:hover .c5:focus::before { class="" >
-
+ source.port +

+ -

- source.port -

- - - + External link + + + (opens in a new tab or window) + + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1405,7 +1349,7 @@ tr:hover .c5:focus::before { class="euiFlexGroup emotion-euiFlexGroup-responsive-none-flexStart-center-row" >
-
+ source.geo.continent_name +

+ -

- source.geo.continent_name -

- - North America - + North America -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1483,7 +1423,7 @@ tr:hover .c5:focus::before {
-
+ source.geo.country_name +

+ -

- source.geo.country_name -

- - United States - + United States -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1561,7 +1497,7 @@ tr:hover .c5:focus::before {
🇺🇸 @@ -1583,61 +1519,57 @@ tr:hover .c5:focus::before { class="" >
-
+ source.geo.country_iso_code +

+ -

- source.geo.country_iso_code -

- - US - + US -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1649,7 +1581,7 @@ tr:hover .c5:focus::before {
-
+ source.geo.region_name +

+ -

- source.geo.region_name -

- - Georgia - + Georgia -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1727,7 +1655,7 @@ tr:hover .c5:focus::before {
-
+ source.geo.city_name +

+ -

- source.geo.city_name -

- - Atlanta - + Atlanta -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1812,7 +1736,7 @@ tr:hover .c5:focus::before {
@@ -1835,72 +1759,68 @@ tr:hover .c5:focus::before { class="" >
-
+ source.bytes +

+ -

- source.bytes -

- -
- - (60.00%) - - - 60B - -
-
+ (60.00%) +
+ + 60B + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1913,7 +1833,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -1924,67 +1844,63 @@ tr:hover .c5:focus::before { class="" >
-
+ source.packets +

+ -

- source.packets -

- -
- - 2 pkts - -
-
+ + 2 pkts + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -1997,7 +1913,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -2031,7 +1947,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -2042,72 +1958,68 @@ tr:hover .c5:focus::before { class="" >
-
+ destination.bytes +

+ -

- destination.bytes -

- -
- - (40.00%) - - - 40B - -
-
+ (40.00%) +
+ + 40B + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2120,7 +2032,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -2131,67 +2043,63 @@ tr:hover .c5:focus::before { class="" >
-
+ destination.packets +

+ -

- destination.packets -

- -
- - 1 pkts - -
-
+ + 1 pkts + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2204,7 +2112,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
@@ -2233,7 +2141,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" >
Destination
@@ -2257,68 +2165,64 @@ tr:hover .c5:focus::before { class="" >
-
+ destination.ip +

+ -

- destination.ip -

- - - 10.1.2.3 - - + 10.1.2.3 + -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2337,7 +2241,7 @@ tr:hover .c5:focus::before { class="euiFlexItem emotion-euiFlexItem-growZero" > : @@ -2350,84 +2254,80 @@ tr:hover .c5:focus::before { class="" >
-
+ destination.port +

+ -

- destination.port -

- - - + External link + + + (opens in a new tab or window) + + +
-

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2449,7 +2349,7 @@ tr:hover .c5:focus::before { class="euiFlexGroup emotion-euiFlexGroup-responsive-none-flexStart-center-row" >
-
+ destination.geo.continent_name +

+ -

- destination.geo.continent_name -

- - North America - + North America -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2527,7 +2423,7 @@ tr:hover .c5:focus::before {
-
+ destination.geo.country_name +

+ -

- destination.geo.country_name -

- - United States - + United States -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2605,7 +2497,7 @@ tr:hover .c5:focus::before {
🇺🇸 @@ -2627,61 +2519,57 @@ tr:hover .c5:focus::before { class="" >
-
+ destination.geo.country_iso_code +

+ -

- destination.geo.country_iso_code -

- - US - + US -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2693,7 +2581,7 @@ tr:hover .c5:focus::before {
-
+ destination.geo.region_name +

+ -

- destination.geo.region_name -

- - New York - + New York -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2771,7 +2655,7 @@ tr:hover .c5:focus::before {
-
+ destination.geo.city_name +

+ -

- destination.geo.city_name -

- - New York - + New York -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2875,103 +2755,99 @@ tr:hover .c5:focus::before { class="" >
-
+ tls.fingerprints.ja3.hash +

+ -

- tls.fingerprints.ja3.hash -

+ - + ja3 + + + tls.fingerprints.ja3.hash-value - ja3 + External link - - tls.fingerprints.ja3.hash-value - - External link - - - (opens in a new tab or window) - - - + (opens in a new tab or window) + + -

- Press enter for options, or press space to begin dragging. -

-
+ +

+ Press enter for options, or press space to begin dragging. +

@@ -2987,103 +2863,99 @@ tr:hover .c5:focus::before { class="" >
@@ -3099,103 +2971,99 @@ tr:hover .c5:focus::before { class="" >
diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx index a18176e523f1b9..d7e8ae909c75f6 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/search_super_select/index.tsx @@ -133,7 +133,7 @@ const SearchTimelineSuperSelectComponent: React.FC { } href={docLinks.gettingStartedSearch} + target="_blank" /> diff --git a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap index 77801c3f8daddd..af2221e460a32e 100644 --- a/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap +++ b/x-pack/plugins/spaces/public/nav_control/__snapshots__/nav_control_popover.test.tsx.snap @@ -4,48 +4,44 @@ exports[`NavControlPopover renders without crashing 1`] = `
- + +
diff --git a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx index 12fa612ac97949..22a33248aea55a 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/tines/tines_params.test.tsx @@ -91,13 +91,15 @@ describe('TinesParamsFields renders', () => { expect(wrapper.find('[data-test-subj="tines-bodyJsonEditor"]').exists()).toBe(false); expect(wrapper.find('[data-test-subj="tines-storySelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-storySelector"]').first().text()).toBe( - 'Select a Tines story' - ); + expect( + wrapper.find('[data-test-subj="tines-storySelector"]').first().find('input').props() + .placeholder + ).toBe('Select a Tines story'); expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').first().text()).toBe( - 'Select a story first' - ); + expect( + wrapper.find('[data-test-subj="tines-webhookSelector"]').first().find('input').props() + .placeholder + ).toBe('Select a story first'); expect(wrapper.find('[data-test-subj="tines-fallbackCallout"]').exists()).toBe(false); expect(wrapper.find('[data-test-subj="tines-webhookUrlInput"]').exists()).toBe(false); @@ -119,13 +121,13 @@ describe('TinesParamsFields renders', () => { expect(wrapper.find('[data-test-subj="bodyAddVariableButton"]').exists()).toBe(false); expect(wrapper.find('[data-test-subj="tines-storySelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-storySelector"]').first().text()).toBe( - 'Select a Tines story' - ); + expect( + wrapper.find('[data-test-subj="tines-storySelector"] input').first().props().placeholder + ).toBe('Select a Tines story'); expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').first().text()).toBe( - 'Select a story first' - ); + expect( + wrapper.find('[data-test-subj="tines-webhookSelector"] input').first().props().placeholder + ).toBe('Select a story first'); expect(mockEditAction).toHaveBeenCalledWith('subAction', 'test', index); }); @@ -223,9 +225,9 @@ describe('TinesParamsFields renders', () => { expect( wrapper.find('[data-test-subj="tines-webhookSelector"]').first().prop('disabled') ).toBe(false); - expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').first().text()).toBe( - 'Select a webhook action' - ); + expect( + wrapper.find('[data-test-subj="tines-webhookSelector"] input').first().props().placeholder + ).toBe('Select a webhook action'); wrapper .find( '[data-test-subj="tines-webhookSelector"] [data-test-subj="comboBoxToggleListButton"]' @@ -312,13 +314,13 @@ describe('TinesParamsFields renders', () => { expect(wrapper.find('[data-test-subj="tines-bodyJsonEditor"]').exists()).toBe(false); expect(wrapper.find('[data-test-subj="tines-storySelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-storySelector"]').first().text()).toBe( - story.name - ); + expect( + wrapper.find('[data-test-subj="tines-storySelector"] input').first().props().value + ).toBe(story.name); expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="tines-webhookSelector"]').first().text()).toBe( - webhook.name - ); + expect( + wrapper.find('[data-test-subj="tines-webhookSelector"] input').first().props().value + ).toBe(webhook.name); expect(wrapper.find('[data-test-subj="tines-fallbackCallout"]').exists()).toBe(false); expect(wrapper.find('[data-test-subj="tines-webhookUrlInput"]').exists()).toBe(false); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 549c459b4944f4..1c0f90d9ad92ec 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28790,8 +28790,6 @@ "xpack.observability.slo.alerting.burnRate.reasonForInstanceId": "{actionGroupName} : Le taux d'avancement pour le (les) dernier(s) {longWindowDuration} est de {longWindowBurnRate} et pour le (les) dernier(s) {shortWindowDuration} est de {shortWindowBurnRate} pour {instanceId}. Alerter si supérieur à {burnRateThreshold} pour les deux fenêtres", "xpack.observability.slo.burnRate.breachedStatustSubtitle": "Au rythme actuel, le budget d'erreur sera épuisé en {hour} heures.", "xpack.observability.slo.burnRate.threshold": "Le seuil est {threshold}x", - "xpack.observability.slo.clone.errorNotification": "Échec du clonage de {name}", - "xpack.observability.slo.clone.successNotification": "{name} créé avec succès", "xpack.observability.slo.create.errorNotification": "Un problème est survenu lors de la création de {name}", "xpack.observability.slo.create.successNotification": "{name} créé avec succès", "xpack.observability.slo.deleteConfirmationModal.title": "Supprimer {name} ?", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8ab33bb6186bb2..cc52a3743aca85 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28790,8 +28790,6 @@ "xpack.observability.slo.alerting.burnRate.reasonForInstanceId": "{actionGroupName}:過去{longWindowDuration}のバーンレートは{longWindowBurnRate}、{instanceId}の過去{shortWindowDuration}のバーンレートは{shortWindowBurnRate}です。両期間とも{burnRateThreshold}を超えたらアラート", "xpack.observability.slo.burnRate.breachedStatustSubtitle": "現在のレートでは、エラー予算は{hour}時間後に使い果たされます。", "xpack.observability.slo.burnRate.threshold": "しきい値は{threshold}xです", - "xpack.observability.slo.clone.errorNotification": "{name}を複製できませんでした", - "xpack.observability.slo.clone.successNotification": "{name}の作成が正常に完了しました", "xpack.observability.slo.create.errorNotification": "{name}の作成中に問題が発生しました", "xpack.observability.slo.create.successNotification": "{name}の作成が正常に完了しました", "xpack.observability.slo.deleteConfirmationModal.title": "{name}を削除しますか?", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d12e878252732f..4a724bbb7c4a67 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28787,8 +28787,6 @@ "xpack.observability.slo.alerting.burnRate.reasonForInstanceId": "{actionGroupName}:过去 {longWindowDuration} 的消耗速度为 {longWindowBurnRate},且对于 {instanceId},过去 {shortWindowDuration} 为 {shortWindowBurnRate}。两个窗口超出 {burnRateThreshold} 时告警", "xpack.observability.slo.burnRate.breachedStatustSubtitle": "按照当前的速率,错误预算将在 {hour} 小时后耗尽。", "xpack.observability.slo.burnRate.threshold": "阈值为 {threshold}x", - "xpack.observability.slo.clone.errorNotification": "无法克隆 {name}", - "xpack.observability.slo.clone.successNotification": "已成功创建 {name}", "xpack.observability.slo.create.errorNotification": "创建 {name} 时出现问题", "xpack.observability.slo.create.successNotification": "已成功创建 {name}", "xpack.observability.slo.deleteConfirmationModal.title": "删除 {name}?", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx index 4f961f8a7bf6c1..e3bf983d7bd096 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connectors_selection.test.tsx @@ -123,6 +123,6 @@ describe('connectors_selection', () => { ); - expect(screen.queryAllByText('test pagerduty')).toHaveLength(1); + expect(screen.getByRole('combobox')).toHaveValue('test pagerduty'); }); }); 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 52a2ac09140886..324e9a290e8316 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 @@ -30,7 +30,11 @@ describe('RuleFormConsumerSelectionModal', () => { ); expect(screen.getByTestId('ruleFormConsumerSelect')).toBeInTheDocument(); - expect(screen.getByText('Select a scope')).toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveAttribute( + 'placeholder', + 'Select a scope' + ); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue(''); fireEvent.click(screen.getByTestId('comboBoxToggleListButton')); expect(screen.getByText('Logs')).toBeInTheDocument(); expect(screen.getByText('Metrics')).toBeInTheDocument(); @@ -116,8 +120,7 @@ describe('RuleFormConsumerSelectionModal', () => { /> ); - expect(screen.getByText('Logs')).toBeInTheDocument(); - expect(() => screen.getByText('Select a scope')).toThrow(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('Logs'); }); it('should not display the initial selected consumer if it is not a selectable option', () => { @@ -129,7 +132,6 @@ describe('RuleFormConsumerSelectionModal', () => { errors={{}} /> ); - expect(() => screen.getByText('Logs')).toThrow(); - expect(screen.getByText('Select a scope')).toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue(''); }); }); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/ml/__snapshots__/ml_integerations.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/ml/__snapshots__/ml_integerations.test.tsx.snap index b85193cb80f05f..5b8d20ae63ba02 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/ml/__snapshots__/ml_integerations.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/ml/__snapshots__/ml_integerations.test.tsx.snap @@ -2,33 +2,29 @@ exports[`ML Integrations renders without errors 1`] = `
-
- -
+ aria-label="Loading" + class="euiLoadingSpinner emotion-euiLoadingSpinner-m" + role="progressbar" + style="border-color:#07C currentcolor currentcolor currentcolor" + /> + + +
`; diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap index 77345c95164a6d..8a4e0915d4fa3c 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/monitor/status_details/__snapshots__/monitor_status.bar.test.tsx.snap @@ -83,42 +83,38 @@ Array [ Enable status alerts
-
- -
+ class="euiSwitch__thumb" + /> + + +
diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/down_number_select.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/down_number_select.test.tsx.snap index 527247ec9f0727..8e559f70cd5fb9 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/down_number_select.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/down_number_select.test.tsx.snap @@ -2,30 +2,26 @@ exports[`DownNoExpressionSelect component should renders against props 1`] = `
-
- - matching monitors are down >= - - - - 5 times - + matching monitors are down >= -
+ + + 5 times + +
`; diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/time_expression_select.test.tsx.snap b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/time_expression_select.test.tsx.snap index 8bdfe9e9b28eb5..49aabf62728c14 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/time_expression_select.test.tsx.snap +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/overview/alerts/monitor_expressions/__snapshots__/time_expression_select.test.tsx.snap @@ -8,58 +8,50 @@ exports[`TimeExpressionSelect component should renders against props 1`] = ` class="euiFlexItem emotion-euiFlexItem-growZero" >
-
- - within - - - - last 15 - + within -
+ + + last 15 + +
-
+ + - - - - minutes - + minutes -
+
diff --git a/x-pack/test/alerting_api_integration/common/plugins/aad/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/aad/server/plugin.ts index 75b66396c269ca..a55417d6685952 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/aad/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/aad/server/plugin.ts @@ -16,6 +16,7 @@ import { import { schema } from '@kbn/config-schema'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; interface FixtureSetupDeps { spaces?: SpacesPluginSetup; @@ -49,7 +50,7 @@ export class FixturePlugin implements Plugin { return await savedObjectsWithAlerts.update( - 'alert', + RULE_SAVED_OBJECT_TYPE, id, { ...( await encryptedSavedObjectsWithAlerts.getDecryptedAsInternalUser( - 'alert', + RULE_SAVED_OBJECT_TYPE, id, { namespace, @@ -182,7 +183,7 @@ export function defineRoutes( const [{ savedObjects }] = await core.getStartServices(); const savedObjectsWithAlerts = await savedObjects.getScopedClient(req, { - includedHiddenTypes: ['alert'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE], }); const savedAlert = await savedObjectsWithAlerts.get(type, id); const result = await retryIfConflicts( @@ -223,7 +224,7 @@ export function defineRoutes( const [{ savedObjects }] = await core.getStartServices(); const savedObjectsWithTasksAndAlerts = await savedObjects.getScopedClient(req, { - includedHiddenTypes: ['task', 'alert'], + includedHiddenTypes: ['task', RULE_SAVED_OBJECT_TYPE], }); const result = await retryIfConflicts( logger, @@ -260,9 +261,9 @@ export function defineRoutes( const [{ savedObjects }] = await core.getStartServices(); const savedObjectsWithTasksAndAlerts = await savedObjects.getScopedClient(req, { - includedHiddenTypes: ['task', 'alert'], + includedHiddenTypes: ['task', RULE_SAVED_OBJECT_TYPE], }); - const alert = await savedObjectsWithTasksAndAlerts.get('alert', id); + const alert = await savedObjectsWithTasksAndAlerts.get(RULE_SAVED_OBJECT_TYPE, id); const result = await retryIfConflicts( logger, `/api/alerts_fixture/{id}/reset_task_status`, @@ -422,9 +423,9 @@ export function defineRoutes( attributes: { apiKey, apiKeyOwner }, }: SavedObject = await encryptedSavedObjects .getClient({ - includedHiddenTypes: ['alert'], + includedHiddenTypes: [RULE_SAVED_OBJECT_TYPE], }) - .getDecryptedAsInternalUser('alert', id, { + .getDecryptedAsInternalUser(RULE_SAVED_OBJECT_TYPE, id, { namespace, }); diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts index 66a85b32e6be61..9e78728d1f7a8b 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts_restricted/server/plugin.ts @@ -10,6 +10,7 @@ import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/s import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server/plugin'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { defineAlertTypes } from './alert_types'; export interface FixtureSetupDeps { @@ -34,7 +35,7 @@ export class FixturePlugin implements Plugin = { space_1_all_alerts_none_actions: SavedObjectsUtils.getConvertedObjectId( 'space1', - 'alert', + RULE_SAVED_OBJECT_TYPE, '6ee9630a-a20e-44af-9465-217a3717d2ab' ), space_1_all_with_restricted_fixture: SavedObjectsUtils.getConvertedObjectId( 'space1', - 'alert', + RULE_SAVED_OBJECT_TYPE, '5cc59319-74ee-4edc-8646-a79ea91067cd' ), space_1_all: SavedObjectsUtils.getConvertedObjectId( 'space1', - 'alert', + RULE_SAVED_OBJECT_TYPE, 'd41a6abb-b93b-46df-a80a-926221ea847c' ), global_read: SavedObjectsUtils.getConvertedObjectId( 'space1', - 'alert', + RULE_SAVED_OBJECT_TYPE, '362e362b-a137-4aa2-9434-43e3d0d84a34' ), superuser: SavedObjectsUtils.getConvertedObjectId( 'space1', - 'alert', + RULE_SAVED_OBJECT_TYPE, 'b384be60-ec53-4b26-857e-0253ee55b277' ), }; 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 9623462b8ae45d..d038108d29f67d 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 @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -103,7 +104,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -164,7 +165,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -225,7 +226,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -293,7 +294,7 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; 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 3d9f49eb3cffb8..97add81c6d5b8e 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 @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -103,7 +104,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -164,7 +165,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -225,7 +226,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -297,7 +298,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; 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 31250862265ea5..b4a775b7a66354 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 @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import { Response as SupertestResponse } from 'supertest'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { checkAAD, @@ -146,7 +147,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -238,7 +239,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -330,7 +331,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -429,7 +430,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -526,7 +527,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); 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 7e2f4e74aa0235..3df05706501463 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 @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -99,7 +100,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -155,7 +156,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -211,7 +212,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -278,7 +279,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -340,7 +341,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; 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 c948791e5ea49d..8dec0a90e8d311 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 @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { checkAAD, @@ -123,7 +124,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts index 2cbec3853f02e7..90748d1b2d4cd0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/clone.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces, UserAtSpaceScenarios } from '../../../scenarios'; import { checkAAD, @@ -194,7 +195,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/user_managed_api_key.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/user_managed_api_key.ts index 905fe05e110e16..77c6efc4e92d89 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/user_managed_api_key.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/user_managed_api_key.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { generateAPIKeyName } from '@kbn/alerting-plugin/server/rules_client/common'; import { IValidatedEvent } from '@kbn/event-log-plugin/server'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { checkAAD, getEventLog, @@ -128,7 +129,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -184,7 +185,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -248,7 +249,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); @@ -311,7 +312,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); @@ -347,7 +348,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -382,7 +383,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -407,7 +408,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -431,7 +432,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -452,7 +453,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -472,7 +473,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -496,7 +497,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); @@ -519,7 +520,7 @@ export default function userManagedApiKeyTest({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: SuperuserAtSpace1.space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: ruleId, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts index 90ddf77f888c3b..bf6811b4ad1758 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/alerts.ts @@ -13,6 +13,7 @@ import { IValidatedEvent, nanosToMillis } from '@kbn/event-log-plugin/server'; import { TaskRunning, TaskRunningStage } from '@kbn/task-manager-plugin/server/task_running'; import { ConcreteTaskInstance } from '@kbn/task-manager-plugin/server'; import { ESTestIndexTool, ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios, Superuser } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -1916,7 +1917,7 @@ instanceStateValue: true expect(event?.kibana?.saved_objects).to.eql([ { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: alertId, namespace: spaceId, type_id: ruleObject.alertInfo.ruleTypeId, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts index 9ad165706bc3db..41963a2e488bac 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/event_log.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { descriptorToArray, SavedObjectDescriptor, @@ -85,7 +86,9 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateEvent(event, { spaceId, - savedObjects: [{ type: 'alert', id: alertId, rel: 'primary', type_id: 'test.noop' }], + savedObjects: [ + { type: RULE_SAVED_OBJECT_TYPE, id: alertId, rel: 'primary', type_id: 'test.noop' }, + ], outcome: 'failure', message: `test.noop:${alertId}: execution failed`, errorMessage: `Unable to decrypt attribute "apiKey" of saved object "${descriptorToArray( 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 8073ef48fbefe6..8c1fed7978b552 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 @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -114,7 +115,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -176,7 +177,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -238,7 +239,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -307,7 +308,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -388,7 +389,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); 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 2f697b0ee3aff7..eae8814a514fb5 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 @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { UserAtSpaceScenarios } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -98,7 +99,7 @@ export default function createUnsnoozeRuleTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -155,7 +156,7 @@ export default function createUnsnoozeRuleTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -212,7 +213,7 @@ export default function createUnsnoozeRuleTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; @@ -276,7 +277,7 @@ export default function createUnsnoozeRuleTests({ getService }: FtrProviderConte await checkAAD({ supertest, spaceId: space.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); break; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts index eb9f90cb41f2a9..3d97d390973488 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/create.ts @@ -9,6 +9,7 @@ import expect from '@kbn/expect'; import { SavedObject } from '@kbn/core/server'; import { RawRule } from '@kbn/alerting-plugin/server/types'; import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { checkAAD, @@ -122,7 +123,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); @@ -313,7 +314,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); @@ -380,7 +381,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: customId, }); }); @@ -399,7 +400,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: customId, }); }); @@ -556,7 +557,7 @@ export default function createAlertTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts index 39eaa216e7e04a..0dccb0ea5a545f 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/disable.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -75,7 +76,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -149,7 +150,12 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex validateEvent(event, { spaceId: Spaces.space1.id, savedObjects: [ - { type: 'alert', id: ruleId, rel: 'primary', type_id: 'test.cumulative-firing' }, + { + type: RULE_SAVED_OBJECT_TYPE, + id: ruleId, + rel: 'primary', + type_id: 'test.cumulative-firing', + }, ], message: "instance 'instance-0' has been untracked because the rule was disabled", shouldHaveEventEnd: false, @@ -193,7 +199,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -237,7 +243,7 @@ export default function createDisableRuleTests({ getService }: FtrProviderContex await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts index b9538c786a496c..cf49801cb61459 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/enable.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -68,7 +69,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -124,7 +125,7 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts index 2662ba69f3025e..4b0bcba103e109 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/event_log.ts @@ -10,6 +10,7 @@ import expect from '@kbn/expect'; import { IValidatedEvent, nanosToMillis } from '@kbn/event-log-plugin/server'; import { RuleNotifyWhen } from '@kbn/alerting-plugin/common'; import { ES_TEST_INDEX_NAME, ESTestIndexTool } from '@kbn/alerting-api-integration-helpers'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { getUrlPrefix, @@ -167,7 +168,12 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateEvent(event, { spaceId: space.id, savedObjects: [ - { type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' }, + { + type: RULE_SAVED_OBJECT_TYPE, + id: alertId, + rel: 'primary', + type_id: 'test.patternFiring', + }, ], message: `rule execution start: "${alertId}"`, shouldHaveTask: true, @@ -186,7 +192,12 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateEvent(event, { spaceId: space.id, savedObjects: [ - { type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' }, + { + type: RULE_SAVED_OBJECT_TYPE, + id: alertId, + rel: 'primary', + type_id: 'test.patternFiring', + }, { type: 'action', id: createdAction.id, type_id: 'test.noop' }, ], message: `alert: test.patternFiring:${alertId}: 'abc' instanceId: 'instance' scheduled actionGroup: 'default' action: test.noop:${createdAction.id}`, @@ -238,7 +249,12 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateEvent(event, { spaceId: space.id, savedObjects: [ - { type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' }, + { + type: RULE_SAVED_OBJECT_TYPE, + id: alertId, + rel: 'primary', + type_id: 'test.patternFiring', + }, ], outcome: 'success', message: `rule executed: test.patternFiring:${alertId}: 'abc'`, @@ -289,7 +305,12 @@ export default function eventLogTests({ getService }: FtrProviderContext) { validateEvent(event, { spaceId: space.id, savedObjects: [ - { type: 'alert', id: alertId, rel: 'primary', type_id: 'test.patternFiring' }, + { + type: RULE_SAVED_OBJECT_TYPE, + id: alertId, + rel: 'primary', + type_id: 'test.patternFiring', + }, ], message: `test.patternFiring:${alertId}: 'abc' ${subMessage}`, instanceId: 'instance', diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/execution_status.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/execution_status.ts index a21027ea448b9b..9f2dc2ff77eb65 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/execution_status.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/execution_status.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { checkAAD, @@ -49,7 +50,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); @@ -82,7 +83,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); @@ -118,7 +119,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); @@ -151,7 +152,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: response.body.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_all.ts index 9cfbb1e4775261..f6d6f563067534 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_all.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -45,7 +46,7 @@ export default function createMuteTests({ getService }: FtrProviderContext) { await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -74,7 +75,7 @@ export default function createMuteTests({ getService }: FtrProviderContext) { await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_instance.ts index 85dda60babfd00..85f55ce3ba51c9 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/mute_instance.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -46,7 +47,7 @@ export default function createMuteInstanceTests({ getService }: FtrProviderConte await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -79,7 +80,7 @@ export default function createMuteInstanceTests({ getService }: FtrProviderConte await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_all.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_all.ts index a39f576364d042..24c717a97dcdce 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_all.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -47,7 +48,7 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -80,7 +81,7 @@ export default function createUnmuteTests({ getService }: FtrProviderContext) { await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_instance.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_instance.ts index 3dda4b0db49b85..6e6c7c0d368b9d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/unmute_instance.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -47,7 +48,7 @@ export default function createUnmuteInstanceTests({ getService }: FtrProviderCon await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -88,7 +89,7 @@ export default function createUnmuteInstanceTests({ getService }: FtrProviderCon await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts index c7dc4e1484580e..623a2efc3f0057 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { checkAAD, getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -93,7 +94,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -190,7 +191,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts index bd3a12d9afdb63..546c4df51c62ec 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group2/update_api_key.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -53,7 +54,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); @@ -102,7 +103,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte await checkAAD({ supertest: supertestWithoutAuth, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts index 23e05ed530d4a2..7bbf87f9901c29 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/bulk_edit.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import { v4 as uuidv4 } from 'uuid'; import type { SanitizedRule } from '@kbn/alerting-plugin/common'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { checkAAD, @@ -81,7 +82,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -183,7 +184,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -229,7 +230,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -275,7 +276,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -340,7 +341,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -417,7 +418,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/migrations.ts index 5611341bd32234..b339f9492b0545 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/migrations.ts @@ -11,6 +11,7 @@ import type { RawRule, RawRuleAction } from '@kbn/alerting-plugin/server/types'; import { FILEBEAT_7X_INDICATOR_PATH } from '@kbn/alerting-plugin/server/saved_objects/migrations'; import type { SavedObjectReference } from '@kbn/core/server'; import { ALERTING_CASES_SAVED_OBJECT_INDEX } from '@kbn/core-saved-objects-server'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { getUrlPrefix } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -284,7 +285,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { { name: 'param:alert_0', id: '1a4ed6ae-3c89-44b2-999d-db554144504c', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, }, ]); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/snooze.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/snooze.ts index a658e461917f43..a027a427c9d012 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/snooze.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/snooze.ts @@ -7,6 +7,7 @@ import expect from '@kbn/expect'; import { v4 as uuidv4 } from 'uuid'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -92,7 +93,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -147,7 +148,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); @@ -390,7 +391,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdRule.id, }); }); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/unsnooze.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/unsnooze.ts index 81e246de3214a4..31b7c8bf9befc9 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/unsnooze.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/unsnooze.ts @@ -6,6 +6,7 @@ */ import expect from '@kbn/expect'; +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import { Spaces } from '../../../scenarios'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; import { @@ -73,7 +74,7 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext await checkAAD({ supertest, spaceId: Spaces.space1.id, - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: createdAlert.id, }); }); diff --git a/x-pack/test/apm_api_integration/tests/historical_data/has_data.spec.ts b/x-pack/test/apm_api_integration/tests/historical_data/has_data.spec.ts index 7fac147db62e03..a7017263e9db76 100644 --- a/x-pack/test/apm_api_integration/tests/historical_data/has_data.spec.ts +++ b/x-pack/test/apm_api_integration/tests/historical_data/has_data.spec.ts @@ -6,34 +6,54 @@ */ import expect from '@kbn/expect'; +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import moment from 'moment'; import { 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 synthtraceEsClient = getService('synthtraceEsClient'); - registry.when( - 'Historical data when data is not loaded', - { config: 'basic', archives: [] }, - () => { - it('handles the empty state', async () => { + registry.when('Historical data ', { config: 'basic', archives: [] }, () => { + describe('when there is not data', () => { + it('returns hasData=false', async () => { const response = await apmApiClient.readUser({ endpoint: `GET /internal/apm/has_data` }); expect(response.status).to.be(200); expect(response.body.hasData).to.be(false); }); - } - ); - - registry.when( - 'Historical data when data is loaded', - { config: 'basic', archives: [archiveName] }, - () => { - it('returns hasData: true', async () => { + }); + + describe('when there is data', () => { + before(async () => { + const start = moment().subtract(30, 'minutes').valueOf(); + const end = moment().valueOf(); + + const serviceInstance = apm + .service({ name: 'my-go-service', environment: 'production', agentName: 'go' }) + .instance('instance-a'); + + const documents = [ + timerange(start, end) + .interval('1m') + .generator((timestamp) => + serviceInstance + .transaction({ transactionName: 'GET /users' }) + .timestamp(timestamp) + .duration(10) + ), + ]; + + await synthtraceEsClient.index(documents); + }); + + after(() => synthtraceEsClient.clean()); + + it('returns hasData=true', async () => { const response = await apmApiClient.readUser({ endpoint: `GET /internal/apm/has_data` }); expect(response.status).to.be(200); expect(response.body.hasData).to.be(true); }); - } - ); + }); + }); } diff --git a/x-pack/test/cloud_security_posture_api/config.ts b/x-pack/test/cloud_security_posture_api/config.ts index e7a34bafe9fb55..625236022cd140 100644 --- a/x-pack/test/cloud_security_posture_api/config.ts +++ b/x-pack/test/cloud_security_posture_api/config.ts @@ -18,6 +18,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('./telemetry/telemetry.ts'), require.resolve('./routes/vulnerabilities_dashboard.ts'), require.resolve('./routes/stats.ts'), + require.resolve('./routes/csp_benchmark_rules_bulk_update.ts'), ], junit: { reportName: 'X-Pack Cloud Security Posture API Tests', diff --git a/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts new file mode 100644 index 00000000000000..dad7845e60e317 --- /dev/null +++ b/x-pack/test/cloud_security_posture_api/routes/csp_benchmark_rules_bulk_update.ts @@ -0,0 +1,247 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { expect as expectExpect } from 'expect'; + +import { + ELASTIC_HTTP_VERSION_HEADER, + X_ELASTIC_INTERNAL_ORIGIN_REQUEST, +} from '@kbn/core-http-common'; +import type { FtrProviderContext } from '../ftr_provider_context'; + +interface RuleIdentifier { + benchmarkId: string; + benchmarkVersion: string; + ruleNumber: string; +} + +// eslint-disable-next-line import/no-default-export +export default function ({ getService }: FtrProviderContext) { + const retry = getService('retry'); + const supertest = getService('supertest'); + const log = getService('log'); + const kibanaServer = getService('kibanaServer'); + + const generateRuleKey = (ruleParams: RuleIdentifier): string => { + return `${ruleParams.benchmarkId};${ruleParams.benchmarkVersion};${ruleParams.ruleNumber}`; + }; + + const generateRandomRule = (): RuleIdentifier => { + const majorVersionNumber = Math.floor(Math.random() * 10); // Random major number between 0 and 9 + const minorVersionNumber = Math.floor(Math.random() * 10); + const benchmarksIds = ['cis_aws', 'cis_k8s', 'cis_k8s']; + const benchmarksVersions = ['v2.0.0', 'v2.0.1', 'v2.0.3', 'v3.0.0']; + const randomBenchmarkId = benchmarksIds[Math.floor(Math.random() * benchmarksIds.length)]; + const randomBenchmarkVersion = + benchmarksVersions[Math.floor(Math.random() * benchmarksVersions.length)]; + + return { + benchmarkId: randomBenchmarkId, + benchmarkVersion: randomBenchmarkVersion, + ruleNumber: `${majorVersionNumber}.${minorVersionNumber}`, + }; + }; + + /** + * required before indexing findings + */ + const waitForPluginInitialized = (): Promise => + retry.try(async () => { + log.debug('Check CSP plugin is initialized'); + const response = await supertest + .get('/internal/cloud_security_posture/status?check=init') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .expect(200); + expect(response.body).to.eql({ isPluginInitialized: true }); + log.debug('CSP plugin is initialized'); + }); + + describe('Verify update csp rules states API', async () => { + before(async () => { + await waitForPluginInitialized(); + }); + + afterEach(async () => { + await kibanaServer.savedObjects.clean({ + types: ['cloud-security-posture-settings'], + }); + }); + + it('mute rules successfully', async () => { + const rule1 = generateRandomRule(); + const rule2 = generateRandomRule(); + + const { body } = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'mute', + rules: [ + { + benchmark_id: rule1.benchmarkId, + benchmark_version: rule1.benchmarkVersion, + rule_number: rule1.ruleNumber, + }, + { + benchmark_id: rule2.benchmarkId, + benchmark_version: rule2.benchmarkVersion, + rule_number: rule2.ruleNumber, + }, + ], + }) + .expect(200); + + expectExpect(body.updated_benchmark_rules).toEqual( + expectExpect.objectContaining({ + [generateRuleKey(rule1)]: { muted: true }, + [generateRuleKey(rule2)]: { muted: true }, + }) + ); + }); + + it('unmute rules successfully', async () => { + const rule1 = generateRandomRule(); + const rule2 = generateRandomRule(); + + const { body } = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'unmute', + rules: [ + { + benchmark_id: rule1.benchmarkId, + benchmark_version: rule1.benchmarkVersion, + rule_number: rule1.ruleNumber, + }, + { + benchmark_id: rule2.benchmarkId, + benchmark_version: rule2.benchmarkVersion, + rule_number: rule2.ruleNumber, + }, + ], + }) + .expect(200); + + expectExpect(body.updated_benchmark_rules).toEqual( + expectExpect.objectContaining({ + [generateRuleKey(rule1)]: { muted: false }, + [generateRuleKey(rule2)]: { muted: false }, + }) + ); + }); + + it('verify new rules are added and existing rules are set.', async () => { + const rule1 = generateRandomRule(); + const rule2 = generateRandomRule(); + const rule3 = generateRandomRule(); + + // unmute rule1 and rule2 + const cspSettingsResponse = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'unmute', + rules: [ + { + benchmark_id: rule1.benchmarkId, + benchmark_version: rule1.benchmarkVersion, + rule_number: rule1.ruleNumber, + }, + { + benchmark_id: rule2.benchmarkId, + benchmark_version: rule2.benchmarkVersion, + rule_number: rule2.ruleNumber, + }, + ], + }) + .expect(200); + + expectExpect(cspSettingsResponse.body.updated_benchmark_rules).toEqual( + expectExpect.objectContaining({ + [generateRuleKey(rule1)]: { muted: false }, + [generateRuleKey(rule2)]: { muted: false }, + }) + ); + + // mute rule1 and rule3 + const updatedCspSettingsResponse = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'mute', + rules: [ + { + benchmark_id: rule1.benchmarkId, + benchmark_version: rule1.benchmarkVersion, + rule_number: rule1.ruleNumber, + }, + { + benchmark_id: rule3.benchmarkId, + benchmark_version: rule3.benchmarkVersion, + rule_number: rule3.ruleNumber, + }, + ], + }) + .expect(200); + + expectExpect(updatedCspSettingsResponse.body.updated_benchmark_rules).toEqual( + expectExpect.objectContaining({ + [generateRuleKey(rule1)]: { muted: true }, + [generateRuleKey(rule3)]: { muted: true }, + }) + ); + }); + + it('set wrong action input', async () => { + const rule1 = generateRandomRule(); + + const { body } = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'foo', + rules: [ + { + benchmark_id: rule1.benchmarkId, + benchmark_version: rule1.benchmarkVersion, + rule_number: rule1.ruleNumber, + }, + ], + }); + + expect(body.error).to.eql('Bad Request'); + expect(body.statusCode).to.eql(400); + }); + + it('set wrong rule ids input', async () => { + const { body } = await supertest + .post(`/internal/cloud_security_posture/rules/_bulk_action`) + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .set('kbn-xsrf', 'xxxx') + .send({ + action: 'mute', + rule_ids: ['invalid_rule_structure'], + }); + + expect(body.error).to.eql('Bad Request'); + expect(body.statusCode).to.eql(400); + }); + }); +} diff --git a/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.ts new file mode 100644 index 00000000000000..ba38cc432ff8c6 --- /dev/null +++ b/x-pack/test/dataset_quality_api_integration/tests/data_streams/degraded_docs.spec.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 { log, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { DatasetQualityApiClientKey } from '../../common/config'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; + +export default function ApiTest({ getService }: FtrProviderContext) { + const registry = getService('registry'); + const synthtrace = getService('logSynthtraceEsClient'); + const datasetQualityApiClient = getService('datasetQualityApiClient'); + const start = '2023-12-11T18:00:00.000Z'; + const end = '2023-12-11T18:01:00.000Z'; + + async function callApiAs(user: DatasetQualityApiClientKey) { + return await datasetQualityApiClient[user]({ + endpoint: 'GET /internal/dataset_quality/data_streams/degraded_docs', + params: { + query: { + type: 'logs', + start, + end, + }, + }, + }); + } + + registry.when('Degraded docs', { config: 'basic' }, () => { + describe('and there are log documents', () => { + before(async () => { + await synthtrace.index([ + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset('synth.1') + .defaults({ + 'log.file.path': '/my-service.log', + }) + ), + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset('synth.2') + .logLevel( + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?' + ) + .defaults({ + 'log.file.path': '/my-service.log', + }) + ), + ]); + }); + + it('returns stats correctly', async () => { + const stats = await callApiAs('datasetQualityLogsUser'); + expect(stats.body.degradedDocs.length).to.be(2); + + const percentages = stats.body.degradedDocs.reduce( + (acc, curr) => ({ + ...acc, + [curr.dataset]: curr.percentage, + }), + {} as Record + ); + + expect(percentages['logs-synth.1-default']).to.be(0); + expect(percentages['logs-synth.2-default']).to.be(100); + }); + + after(async () => { + await synthtrace.clean(); + }); + }); + + describe('and there are not log documents', () => { + it('returns stats correctly', async () => { + const stats = await callApiAs('datasetQualityLogsUser'); + + expect(stats.body.degradedDocs.length).to.be(0); + }); + }); + }); +} diff --git a/x-pack/test/dataset_quality_api_integration/tests/es_utils.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams/es_utils.ts similarity index 100% rename from x-pack/test/dataset_quality_api_integration/tests/es_utils.ts rename to x-pack/test/dataset_quality_api_integration/tests/data_streams/es_utils.ts diff --git a/x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts similarity index 86% rename from x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts rename to x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts index 6d11326bf213ed..7fa60dcb4b118e 100644 --- a/x-pack/test/dataset_quality_api_integration/tests/data_streams.spec.ts +++ b/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts @@ -7,10 +7,10 @@ import { log, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; -import { DatasetQualityApiClientKey } from '../common/config'; -import { DatasetQualityApiError } from '../common/dataset_quality_api_supertest'; -import { FtrProviderContext } from '../common/ftr_provider_context'; -import { expectToReject } from '../utils'; +import { DatasetQualityApiClientKey } from '../../common/config'; +import { DatasetQualityApiError } from '../../common/dataset_quality_api_supertest'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; +import { expectToReject } from '../../utils'; import { cleanLogIndexTemplate, addIntegrationToLogIndexTemplate } from './es_utils'; export default function ApiTest({ getService }: FtrProviderContext) { @@ -43,7 +43,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); describe('when required privileges are set', () => { - describe('and uncategorized datastreams', () => { + describe('and categorized datastreams', () => { const integration = 'my-custom-integration'; before(async () => { @@ -67,8 +67,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(stats.body.dataStreamsStats.length).to.be(1); expect(stats.body.dataStreamsStats[0].integration).to.be(integration); expect(stats.body.dataStreamsStats[0].size).not.empty(); - expect(stats.body.dataStreamsStats[0].size_bytes).greaterThan(0); - expect(stats.body.dataStreamsStats[0].last_activity).greaterThan(0); + expect(stats.body.dataStreamsStats[0].sizeBytes).greaterThan(0); + expect(stats.body.dataStreamsStats[0].lastActivity).greaterThan(0); }); after(async () => { @@ -77,7 +77,7 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); - describe('and categorized datastreams', () => { + describe('and uncategorized datastreams', () => { before(async () => { await synthtrace.index([ timerange('2023-11-20T15:00:00.000Z', '2023-11-20T15:01:00.000Z') @@ -97,8 +97,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(stats.body.dataStreamsStats.length).to.be(1); expect(stats.body.dataStreamsStats[0].integration).not.ok(); expect(stats.body.dataStreamsStats[0].size).not.empty(); - expect(stats.body.dataStreamsStats[0].size_bytes).greaterThan(0); - expect(stats.body.dataStreamsStats[0].last_activity).greaterThan(0); + expect(stats.body.dataStreamsStats[0].sizeBytes).greaterThan(0); + expect(stats.body.dataStreamsStats[0].lastActivity).greaterThan(0); }); after(async () => { diff --git a/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts b/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts index 5884e30f153a39..b6b514fe2c75db 100644 --- a/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts +++ b/x-pack/test/functional/apps/dev_tools/searchprofiler_editor.ts @@ -6,26 +6,27 @@ */ import expect from '@kbn/expect'; -import { compressToEncodedURIComponent } from 'lz-string'; import { asyncForEach } from '@kbn/std'; import { FtrProviderContext } from '../../ftr_provider_context'; +const testIndex = 'test-index'; +const testQuery = { + query: { + match_all: {}, + }, +}; export default function ({ getPageObjects, getService }: FtrProviderContext) { - const PageObjects = getPageObjects(['common']); - const testSubjects = getService('testSubjects'); - const aceEditor = getService('aceEditor'); + const PageObjects = getPageObjects(['common', 'searchProfiler']); const retry = getService('retry'); const security = getService('security'); const es = getService('es'); const log = getService('log'); - const editorTestSubjectSelector = 'searchProfilerEditor'; - describe('Search Profiler Editor', () => { before(async () => { await security.testUser.setRoles(['global_devtools_read']); await PageObjects.common.navigateToApp('searchProfiler'); - expect(await testSubjects.exists('searchProfilerEditor')).to.be(true); + expect(await PageObjects.searchProfiler.editorExists()).to.be(true); }); after(async () => { @@ -36,7 +37,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // The below inputs are written to work _with_ ace's autocomplete unlike console's unit test // counterparts in src/legacy/core_plugins/console/public/tests/src/editor.test.js - const okInput = [ + const okInputs = [ `{ "query": { "match_all": {}`, @@ -46,7 +47,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { "test": """{ "more": "json" }"""`, ]; - const notOkInput = [ + const notOkInputs = [ `{ "query": { "match_all": { @@ -59,24 +60,24 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const expectHasParseErrorsToBe = (expectation: boolean) => async (inputs: string[]) => { for (const input of inputs) { - await aceEditor.setValue(editorTestSubjectSelector, input); + await PageObjects.searchProfiler.setQuery(input); await retry.waitFor( `parser errors to match expectation: HAS ${expectation ? 'ERRORS' : 'NO ERRORS'}`, async () => { - const actual = await aceEditor.hasParseErrors(editorTestSubjectSelector); + const actual = await PageObjects.searchProfiler.editorHasParseErrors(); return expectation === actual; } ); } }; - await expectHasParseErrorsToBe(false)(okInput); - await expectHasParseErrorsToBe(true)(notOkInput); + await expectHasParseErrorsToBe(false)(okInputs); + await expectHasParseErrorsToBe(true)(notOkInputs); }); it('supports pre-configured search query', async () => { - const searchQuery = { + const query = { query: { bool: { should: [ @@ -106,24 +107,21 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // this index name is just an input placeholder and does not exist const indexName = 'my_index'; - const searchQueryURI = compressToEncodedURIComponent(JSON.stringify(searchQuery, null, 2)); - await PageObjects.common.navigateToUrl( 'searchProfiler', - `/searchprofiler?index=${indexName}&load_from=${searchQueryURI}`, + PageObjects.searchProfiler.getUrlWithIndexAndQuery({ indexName, query }), { useActualUrl: true, } ); - const indexInput = await testSubjects.find('indexName'); - const indexInputValue = await indexInput.getAttribute('value'); + const indexInputValue = await PageObjects.searchProfiler.getIndexName(); expect(indexInputValue).to.eql(indexName); await retry.try(async () => { - const searchProfilerInput = JSON.parse(await aceEditor.getValue('searchProfilerEditor')); - expect(searchProfilerInput).to.eql(searchQuery); + const searchProfilerInput = await PageObjects.searchProfiler.getQuery(); + expect(searchProfilerInput).to.eql(query); }); }); @@ -148,23 +146,35 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('returns error if profile is executed with no valid indices', async () => { - const input = { - query: { - match_all: {}, - }, - }; - - await testSubjects.setValue('indexName', '_all'); - await aceEditor.setValue(editorTestSubjectSelector, JSON.stringify(input)); + await PageObjects.searchProfiler.setIndexName('_all'); + await PageObjects.searchProfiler.setQuery(testQuery); - await testSubjects.click('profileButton'); + await PageObjects.searchProfiler.clickProfileButton(); await retry.waitFor('notification renders', async () => { - const notification = await testSubjects.find('noShardsNotification'); - const notificationText = await notification.getVisibleText(); - return notificationText.includes('Unable to profile'); + return await PageObjects.searchProfiler.editorHasErrorNotification(); }); }); }); + + describe('With a test index', () => { + before(async () => { + await es.indices.create({ index: testIndex }); + }); + + after(async () => { + await es.indices.delete({ index: testIndex }); + }); + + it('profiles a simple query', async () => { + await PageObjects.searchProfiler.setIndexName(testIndex); + await PageObjects.searchProfiler.setQuery(testQuery); + + await PageObjects.searchProfiler.clickProfileButton(); + + const content = await PageObjects.searchProfiler.getProfileContent(); + expect(content).to.contain(testIndex); + }); + }); }); } diff --git a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts index 99985787c53a0c..56a4ad07285f58 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/agg_based/table.ts @@ -18,6 +18,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { ]); const testSubjects = getService('testSubjects'); + const comboBox = getService('comboBox'); describe('Table', function describeIndexTests() { const isNewChartsLibraryEnabled = true; @@ -85,8 +86,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(await dimensions[0].getVisibleText()).to.be('Average machine.ram'); await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); - const summaryRowFunction = await testSubjects.find('lnsDatatable_summaryrow_function'); - expect(await summaryRowFunction.getVisibleText()).to.be('Sum'); + expect(await comboBox.getComboBoxSelectedOptions('lnsDatatable_summaryrow_function')).to.eql([ + 'Sum', + ]); }); it('should convert sibling pipeline aggregation', async () => { @@ -171,8 +173,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const percentageColumnText = await lens.getDimensionTriggerText('lnsDatatable_metrics', 1); await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger', 0, 1); - const format = await testSubjects.find('indexPattern-dimension-format'); - expect(await format.getVisibleText()).to.be('Percent'); + expect(await comboBox.getComboBoxSelectedOptions('indexPattern-dimension-format')).to.eql([ + 'Percent', + ]); const dimensions = await testSubjects.findAll('lns-dimensionTrigger'); expect(dimensions).to.have.length(2); diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts index d2f8b49c1ae92e..9e9f301859db5c 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/table.ts @@ -114,8 +114,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await lens.waitForVisualization('lnsDataTable'); await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); await testSubjects.click('indexPattern-advanced-accordion'); - const reducedTimeRange = await testSubjects.find('indexPattern-dimension-reducedTimeRange'); - expect(await reducedTimeRange.getVisibleText()).to.be('1 minute (1m)'); + const reducedTimeRange = await testSubjects.find( + 'indexPattern-dimension-reducedTimeRange > comboBoxSearchInput' + ); + expect(await reducedTimeRange.getAttribute('value')).to.be('1 minute (1m)'); await retry.try(async () => { const layerCount = await lens.getLayerCount(); expect(layerCount).to.be(1); diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts index 10b8e2136deb15..5207b18035837c 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/top_n.ts @@ -115,8 +115,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await lens.waitForVisualization('xyVisChart'); await lens.openDimensionEditor('lnsXY_yDimensionPanel > lns-dimensionTrigger'); await testSubjects.click('indexPattern-advanced-accordion'); - const reducedTimeRange = await testSubjects.find('indexPattern-dimension-reducedTimeRange'); - expect(await reducedTimeRange.getVisibleText()).to.be('1 minute (1m)'); + const reducedTimeRange = await testSubjects.find( + 'indexPattern-dimension-reducedTimeRange > comboBoxSearchInput' + ); + expect(await reducedTimeRange.getAttribute('value')).to.be('1 minute (1m)'); await retry.try(async () => { const layerCount = await lens.getLayerCount(); expect(layerCount).to.be(1); diff --git a/x-pack/test/functional/apps/maps/group4/layer_errors.js b/x-pack/test/functional/apps/maps/group4/layer_errors.js index e597f1bb0fe521..e47c0e582c8f49 100644 --- a/x-pack/test/functional/apps/maps/group4/layer_errors.js +++ b/x-pack/test/functional/apps/maps/group4/layer_errors.js @@ -11,6 +11,7 @@ export default function ({ getPageObjects, getService }) { const PageObjects = getPageObjects(['maps', 'header']); const inspector = getService('inspector'); const testSubjects = getService('testSubjects'); + const comboBox = getService('comboBox'); describe('layer errors', () => { before(async () => { @@ -33,8 +34,9 @@ export default function ({ getPageObjects, getService }) { it('should open request in inspector', async () => { await testSubjects.click('viewEsErrorButton'); - const selectedRequest = await testSubjects.getVisibleText('euiComboBoxPill'); - expect(selectedRequest).to.equal('load layer features (connections)'); + expect(await comboBox.getComboBoxSelectedOptions('inspectorRequestChooser')).to.eql([ + 'load layer features (connections)', + ]); }); }); diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 75f86f76459542..b4ea0f741e1175 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -50,6 +50,7 @@ import { UpgradeAssistantPageObject } from './upgrade_assistant_page'; import { UptimePageObject } from './uptime_page'; import { UserProfilePageProvider } from './user_profile_page'; import { WatcherPageObject } from './watcher_page'; +import { SearchProfilerPageProvider } from './search_profiler_page'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -87,6 +88,7 @@ export const pageObjects = { reporting: ReportingPageObject, roleMappings: RoleMappingsPageProvider, rollup: RollupPageObject, + searchProfiler: SearchProfilerPageProvider, searchSessionsManagement: SearchSessionsPageProvider, security: SecurityPageObject, shareSavedObjectsToSpace: ShareSavedObjectsToSpacePageProvider, diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index a867535ea06ee0..0247ecde88ac91 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -337,7 +337,7 @@ export function InfraHomePageProvider({ getService, getPageObjects }: FtrProvide await testSubjects.click('superDatePickerAbsoluteTab'); const datePickerInput = await testSubjects.find('superDatePickerAbsoluteDateInput'); await datePickerInput.clearValueWithKeyboard(); - await datePickerInput.type([date]); + await datePickerInput.type([date, browser.keys.RETURN]); }, async setAnomaliesThreshold(threshold: string) { const thresholdInput = await find.byCssSelector( diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index d0c962d8c574a5..429b30b6864854 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -912,8 +912,8 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont `[data-test-subj^="lnsXY_axisSide_groups_"]` ); for (const axisSideGroup of axisSideGroups) { - const input = await axisSideGroup.findByTagName('input'); - const isSelected = await input.isSelected(); + const ariaPressed = await axisSideGroup.getAttribute('aria-pressed'); + const isSelected = ariaPressed === 'true'; if (isSelected) { return axisSideGroup?.getVisibleText(); } @@ -1439,7 +1439,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont */ async assertFocusedField(name: string) { const input = await find.activeElement(); - const fieldAncestor = await input.findByXpath('./../../..'); + const fieldAncestor = await input.findByXpath('./../..'); const focusedElementText = await fieldAncestor.getVisibleText(); const dataTestSubj = await fieldAncestor.getAttribute('data-test-subj'); expect(focusedElementText).to.eql(name); diff --git a/x-pack/test/functional/page_objects/search_profiler_page.ts b/x-pack/test/functional/page_objects/search_profiler_page.ts new file mode 100644 index 00000000000000..a110bd16eeafee --- /dev/null +++ b/x-pack/test/functional/page_objects/search_profiler_page.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { compressToEncodedURIComponent } from 'lz-string'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export function SearchProfilerPageProvider({ getService }: FtrProviderContext) { + const find = getService('find'); + const testSubjects = getService('testSubjects'); + const aceEditor = getService('aceEditor'); + const editorTestSubjectSelector = 'searchProfilerEditor'; + + return { + async editorExists() { + return await testSubjects.exists(editorTestSubjectSelector); + }, + async setQuery(query: any) { + await aceEditor.setValue(editorTestSubjectSelector, JSON.stringify(query)); + }, + async getQuery() { + return JSON.parse(await aceEditor.getValue(editorTestSubjectSelector)); + }, + async setIndexName(indexName: string) { + await testSubjects.setValue('indexName', indexName); + }, + async getIndexName() { + const indexInput = await testSubjects.find('indexName'); + return await indexInput.getAttribute('value'); + }, + async clickProfileButton() { + await testSubjects.click('profileButton'); + }, + async getProfileContent() { + const profileTree = await find.byClassName('prfDevTool__main__profiletree'); + return profileTree.getVisibleText(); + }, + getUrlWithIndexAndQuery({ indexName, query }: { indexName: string; query: any }) { + const searchQueryURI = compressToEncodedURIComponent(JSON.stringify(query, null, 2)); + return `/searchprofiler?index=${indexName}&load_from=${searchQueryURI}`; + }, + async editorHasParseErrors() { + return await aceEditor.hasParseErrors(editorTestSubjectSelector); + }, + async editorHasErrorNotification() { + const notification = await testSubjects.find('noShardsNotification'); + const text = await notification.getVisibleText(); + return text.includes('Unable to profile'); + }, + }; +} diff --git a/x-pack/test/functional/services/ml/stack_management_jobs.ts b/x-pack/test/functional/services/ml/stack_management_jobs.ts index e99172b374f9d3..f8db28deb50928 100644 --- a/x-pack/test/functional/services/ml/stack_management_jobs.ts +++ b/x-pack/test/functional/services/ml/stack_management_jobs.ts @@ -142,27 +142,22 @@ export function MachineLearningStackManagementJobsProvider({ await testSubjects.missingOrFail('share-to-space-flyout', { timeout: 2000 }); }, - async selectShareToSpacesMode(inputTestSubj: 'shareToExplicitSpacesId' | 'shareToAllSpacesId') { - // The input element can not be clicked directly. - // Instead, we need to click the parent label - const getInputLabel = async () => { - const input = await testSubjects.find(inputTestSubj, 1000); - return await input.findByXpath('./../../..'); // Clicks the parent label 3 levels up - }; + async selectShareToSpacesMode( + buttonTestSubj: 'shareToExplicitSpacesId' | 'shareToAllSpacesId' + ) { await retry.tryForTime(5000, async () => { - const labelElement = await getInputLabel(); - await labelElement.click(); + const button = await testSubjects.find(buttonTestSubj, 1000); + await button.click(); - const checked = await testSubjects.getAttribute(inputTestSubj, 'checked', 1000); - expect(checked).to.eql('true', `Input '${inputTestSubj}' should be checked`); + const isPressed = await button.getAttribute('aria-pressed'); + expect(isPressed).to.eql('true', `Button '${buttonTestSubj}' should be checked`); - // sometimes the checked attribute of the input is set but it's not actually + // sometimes the aria-pressed attribute of the button is set but it's not actually // selected, so we're also checking the class of the corresponding label - const updatedLabelElement = await getInputLabel(); - const labelClasses = await updatedLabelElement.getAttribute('class'); + const labelClasses = await button.getAttribute('class'); expect(labelClasses).to.contain( 'euiButtonGroupButton-isSelected', - `Label for '${inputTestSubj}' should be selected` + `Label for '${buttonTestSubj}' should be selected` ); }); }, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts index 8d5b537dd3bceb..eef28b77e7ac58 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_endpoint_exception.cy.ts @@ -195,8 +195,8 @@ describe('Add endpoint exception from rule details', { tags: ['@ess', '@serverle .eq(0) .find(FIELD_INPUT_PARENT) .eq(0) - .should('have.text', ITEM_FIELD); - cy.get(VALUES_INPUT).should('have.text', 'foo'); + .should('have.value', ITEM_FIELD); + cy.get(VALUES_INPUT).should('have.value', 'foo'); // edit conditions editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception.cy.ts index 70c35610476b8a..b1115b5833bd05 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception.cy.ts @@ -149,7 +149,7 @@ describe( .eq(0) .find(FIELD_INPUT_PARENT) .eq(0) - .should('have.text', ITEM_FIELD); + .should('have.value', ITEM_FIELD); cy.get(VALUES_MATCH_ANY_INPUT).should('have.text', 'foo'); // edit conditions diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts index 3f585dbad90cf4..18c75ce25cbfa8 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/exceptions/rule_details_flow/add_edit_exception_data_view.cy.ts @@ -165,8 +165,8 @@ describe( .eq(0) .find(FIELD_INPUT_PARENT) .eq(0) - .should('have.text', ITEM_FIELD); - cy.get(VALUES_INPUT).should('have.text', 'foo'); + .should('have.value', ITEM_FIELD); + cy.get(VALUES_INPUT).should('have.value', 'foo'); // edit conditions editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts index 5b0fc1f1229287..b2b000803e6c47 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_creation/indicator_match_rule.cy.ts @@ -287,10 +287,9 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@brokenInServerless }); getIndicatorDeleteButton().click(); getIndicatorIndexComboField().find('input').should('have.value', 'agent.name'); - getIndicatorMappingComboField().should( - 'have.text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].value - ); + getIndicatorMappingComboField() + .find('input') + .should('have.value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].value); getIndicatorIndexComboField(2).should('not.exist'); getIndicatorMappingComboField(2).should('not.exist'); }); @@ -343,8 +342,14 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@brokenInServerless indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value, }); getIndicatorDeleteButton().click(); - getIndicatorIndexComboField().should('text', 'Search'); - getIndicatorMappingComboField().should('text', 'Search'); + getIndicatorIndexComboField() + .find('input') + .should('value', '') + .should('have.attr', 'placeholder', 'Search'); + getIndicatorMappingComboField() + .find('input') + .should('value', '') + .should('have.attr', 'placeholder', 'Search'); getIndicatorIndexComboField(2).should('not.exist'); getIndicatorMappingComboField(2).should('not.exist'); }); @@ -368,22 +373,18 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@brokenInServerless indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value, }); getIndicatorDeleteButton(2).click(); - getIndicatorIndexComboField(1).should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field - ); - getIndicatorMappingComboField(1).should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].value - ); - getIndicatorIndexComboField(2).should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field - ); - getIndicatorMappingComboField(2).should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].value - ); + getIndicatorIndexComboField(1) + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].field); + getIndicatorMappingComboField(1) + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].value); + getIndicatorIndexComboField(2) + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].field); + getIndicatorMappingComboField(2) + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].value); getIndicatorIndexComboField(3).should('not.exist'); getIndicatorMappingComboField(3).should('not.exist'); }); @@ -401,14 +402,12 @@ describe('indicator match', { tags: ['@ess', '@serverless', '@brokenInServerless indicatorIndexField: getNewThreatIndicatorRule().threat_mapping[0].entries[0].value, }); getIndicatorDeleteButton().click(); - getIndicatorIndexComboField().should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].field - ); - getIndicatorMappingComboField().should( - 'text', - getNewThreatIndicatorRule().threat_mapping[0].entries[0].value - ); + getIndicatorIndexComboField() + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].field); + getIndicatorMappingComboField() + .find('input') + .should('value', getNewThreatIndicatorRule().threat_mapping[0].entries[0].value); getIndicatorIndexComboField(2).should('not.exist'); getIndicatorMappingComboField(2).should('not.exist'); }); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts index 80d4a9780c6e75..4867ba79183f3f 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/row_renderers.cy.ts @@ -116,7 +116,7 @@ describe('Row renderers', { tags: ['@ess', '@serverless'] }, () => { // A follw-up ticket to tackle this issue has been created. it.skip('Signature tooltips do not overlap', () => { // Hover the signature to show the tooltips - cy.get(TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE).parents('.euiPopover__anchor').realHover(); + cy.get(TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE).parents('.euiPopover').realHover(); cy.get(TIMELINE_ROW_RENDERERS_SURICATA_LINK_TOOLTIP).then(($googleLinkTooltip) => { cy.get(TIMELINE_ROW_RENDERERS_SURICATA_SIGNATURE_TOOLTIP).then(($signatureTooltip) => { diff --git a/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts index f93e01271fda9f..b4032167ebe431 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts @@ -12,19 +12,20 @@ export const CLOSE_SINGLE_ALERT_CHECKBOX = '[data-test-subj="closeAlertOnAddExce export const CONFIRM_BTN = '[data-test-subj="addExceptionConfirmButton"]'; export const FIELD_INPUT = - '[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxInput"] input'; + '[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxSearchInput"]'; export const FIELD_INPUT_PARENT = - '[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxInput"]'; + '[data-test-subj="fieldAutocompleteComboBox"] [data-test-subj="comboBoxSearchInput"]'; export const LOADING_SPINNER = '[data-test-subj="loading-spinner"]'; export const EXCEPTION_FLYOUT_LOADING_SPINNER = '[data-test-subj="loadingAddExceptionFlyout"]'; -export const OPERATOR_INPUT = '[data-test-subj="operatorAutocompleteComboBox"]'; +export const OPERATOR_INPUT = + '[data-test-subj="operatorAutocompleteComboBox"] [data-test-subj="comboBoxInput"]'; export const VALUES_INPUT = - '[data-test-subj="valuesAutocompleteMatch"] [data-test-subj="comboBoxInput"]'; + '[data-test-subj="valuesAutocompleteMatch"] [data-test-subj="comboBoxSearchInput"]'; export const VALUES_MATCH_ANY_INPUT = '[data-test-subj="valuesAutocompleteMatchAny"] [data-test-subj="comboBoxInput"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts b/x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts index 00d5a892593b6e..99823f357dc90d 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/date_picker.ts @@ -76,7 +76,7 @@ export const updateDateRangeInLocalDatePickers = ( cy.get(DATE_PICKER_ABSOLUTE_INPUT).click(); cy.get(DATE_PICKER_ABSOLUTE_INPUT).clear(); - cy.get(DATE_PICKER_ABSOLUTE_INPUT).type(startDate); + cy.get(DATE_PICKER_ABSOLUTE_INPUT).type(`${startDate}{enter}`); cy.get(GET_LOCAL_DATE_PICKER_APPLY_BUTTON(localQueryBarSelector)).click(); cy.get(GET_LOCAL_DATE_PICKER_APPLY_BUTTON(localQueryBarSelector)).should( 'not.have.text', @@ -89,7 +89,7 @@ export const updateDateRangeInLocalDatePickers = ( cy.get(DATE_PICKER_ABSOLUTE_INPUT).click(); cy.get(DATE_PICKER_ABSOLUTE_INPUT).clear(); - cy.get(DATE_PICKER_ABSOLUTE_INPUT).type(endDate); + cy.get(DATE_PICKER_ABSOLUTE_INPUT).type(`${endDate}{enter}`); cy.get(GET_LOCAL_DATE_PICKER_APPLY_BUTTON(localQueryBarSelector)).click(); }; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts index 4ed5ff5ef2f8da..db260fab5ad6bd 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts @@ -74,7 +74,7 @@ export const addExceptionEntryFieldValueOfItemX = ( .eq(itemIndex) .find(FIELD_INPUT) .eq(fieldIndex) - .type(`${field}{enter}`); + .type(`{selectall}${field}{enter}`); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; @@ -99,7 +99,7 @@ export const selectCurrentEntryField = (index = 0) => { }; export const addExceptionEntryFieldValue = (field: string, index = 0) => { - cy.get(FIELD_INPUT).eq(index).type(`${field}{enter}`); + cy.get(FIELD_INPUT).eq(index).type(`{selectall}${field}{enter}`); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; @@ -109,23 +109,23 @@ export const addExceptionEntryFieldValueAndSelectSuggestion = (field: string, in }; export const addExceptionEntryOperatorValue = (operator: string, index = 0) => { - cy.get(OPERATOR_INPUT).eq(index).type(`${operator}{enter}`); + cy.get(OPERATOR_INPUT).eq(index).type(`{selectall}${operator}{enter}`); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; export const addExceptionEntryFieldValueValue = (value: string, index = 0) => { - cy.get(VALUES_INPUT).eq(index).type(`${value}{enter}`); + cy.get(VALUES_INPUT).eq(index).type(`{selectall}${value}{enter}`); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; export const addExceptionEntryFieldMatchAnyValue = (values: string[], index = 0) => { values.forEach((value) => { - cy.get(VALUES_MATCH_ANY_INPUT).eq(index).type(`${value}{enter}`); + cy.get(VALUES_MATCH_ANY_INPUT).eq(index).type(`{selectall}${value}{enter}`); }); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; export const addExceptionEntryFieldMatchIncludedValue = (value: string, index = 0) => { - cy.get(VALUES_MATCH_INCLUDED_INPUT).eq(index).type(`${value}{enter}`); + cy.get(VALUES_MATCH_INCLUDED_INPUT).eq(index).type(`{selectall}${value}{enter}`); cy.get(EXCEPTION_FLYOUT_TITLE).click(); }; @@ -148,13 +148,13 @@ export const addExceptionFlyoutItemName = (name: string) => { cy.get(EXCEPTION_ITEM_NAME_INPUT).scrollIntoView(); cy.get(EXCEPTION_ITEM_NAME_INPUT).should('be.visible'); cy.get(EXCEPTION_ITEM_NAME_INPUT).first().focus(); - cy.get(EXCEPTION_ITEM_NAME_INPUT).type(`${name}{enter}`, { force: true }); + cy.get(EXCEPTION_ITEM_NAME_INPUT).type(`{selectall}${name}{enter}`, { force: true }); cy.get(EXCEPTION_ITEM_NAME_INPUT).should('have.value', name); }; export const editExceptionFlyoutItemName = (name: string) => { cy.get(EXCEPTION_ITEM_NAME_INPUT).clear(); - cy.get(EXCEPTION_ITEM_NAME_INPUT).type(`${name}{enter}`); + cy.get(EXCEPTION_ITEM_NAME_INPUT).type(`{selectall}${name}{enter}`); cy.get(EXCEPTION_ITEM_NAME_INPUT).should('have.value', name); }; @@ -169,12 +169,12 @@ export const selectCloseSingleAlerts = () => { export const addExceptionConditions = (exception: Exception) => { cy.get(FIELD_INPUT).type(`${exception.field}{downArrow}{enter}`); - cy.get(OPERATOR_INPUT).type(`${exception.operator}{enter}`); + cy.get(OPERATOR_INPUT).type(`{selectall}${exception.operator}{enter}`); if (exception.operator === 'is one of') { addExceptionEntryFieldMatchAnyValue(exception.values, 0); } else { exception.values.forEach((value) => { - cy.get(VALUES_INPUT).type(`${value}{enter}`); + cy.get(VALUES_INPUT).type(`{selectall}${value}{enter}`); }); } }; @@ -189,7 +189,7 @@ export const submitNewExceptionItem = () => { cy.get(CONFIRM_BTN).should('exist'); /* Sometimes a toaster error message unrelated with the test performed is displayed. The toaster is blocking the confirm button we have to click. Using force true would solve the issue, but should not be used. - There are some tests that use the closeErrorToast() method to close error toasters before continuing with the interactions with the page. + There are some tests that use the closeErrorToast() method to close error toasters before continuing with the interactions with the page. In this case we check if a toaster is displayed and if so, close it to continue with the test. */ cy.root().then(($page) => { diff --git a/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts b/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts index aab49b3c5c2996..539101c795047c 100644 --- a/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts +++ b/x-pack/test/security_solution_endpoint/apps/integrations/endpoint_exceptions.ts @@ -26,6 +26,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const supertest = getService('supertest'); const find = getService('find'); const unzipPromisify = promisify(unzip); + const comboBox = getService('comboBox'); // FLAKY: https://github.com/elastic/kibana/issues/173184 describe.skip('Endpoint Exceptions', function () { @@ -60,7 +61,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const setLastFieldsValue = async ({ testSubj, value, - optionSelector = `button[title="${value}"]`, }: { testSubj: string; value: string; @@ -71,11 +71,16 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const lastField = fields[fields.length - 1]; await lastField.click(); - const inputField = await lastField.findByTagName('input'); - await inputField.type(value); - - const dropdownOptionSelector = `[data-test-subj="comboBoxOptionsList ${testSubj}-optionsList"] ${optionSelector}`; - await find.clickByCssSelector(dropdownOptionSelector); + await retry.try( + async () => { + await comboBox.setElement(lastField, value); + }, + async () => { + // If the above fails due to an option not existing, create the value custom instead + await comboBox.setFilterValue(lastField, value); + await pageObjects.common.pressEnterKey(); + } + ); }; const setLastEntry = async ({ @@ -92,7 +97,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await setLastFieldsValue({ testSubj: operator === 'matches' ? 'valuesAutocompleteWildcard' : 'valuesAutocompleteMatch', value, - optionSelector: 'p', }); }; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts b/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts index b0813a55325f1f..be10f9b83ac6ba 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/alerting/rules.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; import expect from '@kbn/expect'; import { omit } from 'lodash'; import { FtrProviderContext } from '../../../ftr_provider_context'; @@ -926,7 +927,7 @@ function validateEventLog(event: any, params: ValidateEventLogParams) { expect(event?.kibana?.saved_objects).to.eql([ { rel: 'primary', - type: 'alert', + type: RULE_SAVED_OBJECT_TYPE, id: params.ruleId, type_id: params.ruleTypeId, }, diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index 643c5379404840..501a23c2580467 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -103,6 +103,10 @@ export function createTestConfig(options: CreateTestConfigOptions) { pathname: '/app/discover', hash: '/context', }, + searchProfiler: { + pathname: '/app/dev_tools', + hash: '/searchprofiler', + }, }, // choose where screenshots should be saved screenshots: { diff --git a/x-pack/plugins/dataset_quality/server/types/integration.ts b/x-pack/test_serverless/functional/test_suites/common/dev_tools/index.ts similarity index 50% rename from x-pack/plugins/dataset_quality/server/types/integration.ts rename to x-pack/test_serverless/functional/test_suites/common/dev_tools/index.ts index 2595a120c8b706..067a17062c3a9b 100644 --- a/x-pack/plugins/dataset_quality/server/types/integration.ts +++ b/x-pack/test_serverless/functional/test_suites/common/dev_tools/index.ts @@ -5,17 +5,10 @@ * 2.0. */ -export interface Integration { - name: string; - title?: string; - version?: string; - icons?: IntegrationIcon[]; -} +import { FtrProviderContext } from '../../../ftr_provider_context'; -export interface IntegrationIcon { - path: string; - src: string; - title?: string; - size?: string; - type?: string; -} +export default ({ loadTestFile }: FtrProviderContext) => { + describe('Serverless Common UI - Dev Tools', function () { + loadTestFile(require.resolve('./search_profiler')); + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts b/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.ts new file mode 100644 index 00000000000000..1747d6a517c5fd --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/dev_tools/search_profiler.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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const testIndex = 'test-index'; +const testQuery = { + query: { + match_all: {}, + }, +}; +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const PageObjects = getPageObjects(['svlCommonPage', 'common', 'searchProfiler']); + const retry = getService('retry'); + const es = getService('es'); + + describe('Search Profiler Editor', () => { + before(async () => { + await PageObjects.svlCommonPage.login(); + await PageObjects.common.navigateToApp('searchProfiler'); + expect(await PageObjects.searchProfiler.editorExists()).to.be(true); + }); + + after(async () => { + await PageObjects.svlCommonPage.forceLogout(); + }); + + it('supports pre-configured search query', async () => { + const query = { + query: { + bool: { + should: [ + { + match: { + name: 'fred', + }, + }, + { + terms: { + name: ['sue', 'sally'], + }, + }, + ], + }, + }, + aggs: { + stats: { + stats: { + field: 'price', + }, + }, + }, + }; + + // Since we're not actually running the query in the test, + // this index name is just an input placeholder and does not exist + const indexName = 'my_index'; + + await PageObjects.common.navigateToUrl( + 'searchProfiler', + PageObjects.searchProfiler.getUrlWithIndexAndQuery({ indexName, query }), + { + useActualUrl: true, + } + ); + + const indexInputValue = await PageObjects.searchProfiler.getIndexName(); + + expect(indexInputValue).to.eql(indexName); + + await retry.try(async () => { + const searchProfilerInput = await PageObjects.searchProfiler.getQuery(); + expect(searchProfilerInput).to.eql(query); + }); + }); + + describe('With a test index', () => { + before(async () => { + await es.indices.create({ index: testIndex }); + }); + + after(async () => { + await es.indices.delete({ index: testIndex }); + }); + + it('profiles a simple query', async () => { + await PageObjects.searchProfiler.setIndexName(testIndex); + await PageObjects.searchProfiler.setQuery(testQuery); + + await PageObjects.searchProfiler.clickProfileButton(); + + const content = await PageObjects.searchProfiler.getProfileContent(); + expect(content).to.contain(testIndex); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/table.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/table.ts index be48300683d7c1..864e205e3ff5f5 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/table.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/table.ts @@ -22,6 +22,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const panelActions = getService('dashboardPanelActions'); const kibanaServer = getService('kibanaServer'); + const comboBox = getService('comboBox'); describe('Table', function describeIndexTests() { const fixture = @@ -83,8 +84,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await lens.openDimensionEditor('lnsDatatable_metrics > lns-dimensionTrigger'); await testSubjects.click('indexPattern-advanced-accordion'); - const reducedTimeRange = await testSubjects.find('indexPattern-dimension-reducedTimeRange'); - expect(await reducedTimeRange.getVisibleText()).to.be('1 minute (1m)'); + expect( + await comboBox.getComboBoxSelectedOptions('indexPattern-dimension-reducedTimeRange') + ).to.eql(['1 minute (1m)']); + await retry.try(async () => { const layerCount = await lens.getLayerCount(); expect(layerCount).to.be(1); diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/top_n.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/top_n.ts index dd7fdb01827ddd..4085e7faad08c4 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/top_n.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/top_n.ts @@ -17,6 +17,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const queryBar = getService('queryBar'); const panelActions = getService('dashboardPanelActions'); const kibanaServer = getService('kibanaServer'); + const comboBox = getService('comboBox'); describe('Top N', function describeIndexTests() { const fixture = @@ -102,7 +103,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await lens.openDimensionEditor('lnsXY_yDimensionPanel > lns-dimensionTrigger'); await testSubjects.click('indexPattern-advanced-accordion'); const reducedTimeRange = await testSubjects.find('indexPattern-dimension-reducedTimeRange'); - expect(await reducedTimeRange.getVisibleText()).to.be('1 minute (1m)'); + await comboBox.isOptionSelected(reducedTimeRange, '1 minute (1m)'); await retry.try(async () => { const layerCount = await lens.getLayerCount(); expect(layerCount).to.be(1); diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts index 79ace54bdc6acd..62f34915d6f15e 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group1.ts @@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('../../common/home_page'), require.resolve('../../common/management'), + require.resolve('../../common/dev_tools'), require.resolve('../../common/platform_security'), require.resolve('../../common/reporting'), require.resolve('../../common/grok_debugger'), diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts index 5cf92c7199d764..848aec3f340f55 100644 --- a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group1.ts @@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('../../common/home_page'), require.resolve('../../common/management'), + require.resolve('../../common/dev_tools'), require.resolve('../../common/platform_security'), require.resolve('../../common/reporting'), require.resolve('../../common/console'), diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts index c7771a0bf9c2d8..120359a8903b38 100644 --- a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts @@ -15,6 +15,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('../../common/home_page'), require.resolve('../../common/management'), + require.resolve('../../common/dev_tools'), require.resolve('../../common/platform_security'), require.resolve('../../common/reporting'), require.resolve('../../common/grok_debugger'), diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 72039a6ad13687..54c1e26f069d11 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -83,5 +83,6 @@ "@kbn/io-ts-utils", "@kbn/log-explorer-plugin", "@kbn/index-management-plugin", + "@kbn/alerting-plugin", ] } diff --git a/yarn.lock b/yarn.lock index 69b2efda65bde8..28da05fef02224 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1625,10 +1625,10 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui@90.0.1-backport.0": - version "90.0.1-backport.0" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-90.0.1-backport.0.tgz#c57910220dab4f85c813c4b7b44a80500b5abf82" - integrity sha512-mv8ucgZdBAJ7i7sDb6K1wHS9eboVe4rb3Vg0NSIMsat2skCfQAods+aPuXuKo323W57uZGnJnQlO07wF4iA3Tg== +"@elastic/eui@91.0.0-backport.0": + version "91.0.0-backport.0" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-91.0.0-backport.0.tgz#821306a580cc8fcf1a142106e425f3fcd1bebfbf" + integrity sha512-2T+8JiPs1Ejh2T8l7cwqv/IIlNV6I9RbXtJ60L9U4lJGtS/R8zIoikrR/2SEs8bXwyXXg4i/trhfbYbylAvZpw== dependencies: "@hello-pangea/dnd" "^16.3.0" "@types/lodash" "^4.14.198" @@ -3271,6 +3271,10 @@ version "0.0.0" uid "" +"@kbn/code-owners@link:packages/kbn-code-owners": + version "0.0.0" + uid "" + "@kbn/coloring@link:packages/kbn-coloring": version "0.0.0" uid "" @@ -4623,6 +4627,10 @@ version "0.0.0" uid "" +"@kbn/ftr-common-functional-ui-services@link:packages/kbn-ftr-common-functional-ui-services": + version "0.0.0" + uid "" + "@kbn/ftr-screenshot-filename@link:packages/kbn-ftr-screenshot-filename": version "0.0.0" uid "" @@ -5427,6 +5435,10 @@ version "0.0.0" uid "" +"@kbn/router-utils@link:packages/kbn-router-utils": + version "0.0.0" + uid "" + "@kbn/routing-example-plugin@link:examples/routing_example": version "0.0.0" uid "" @@ -18734,10 +18746,10 @@ ignore@^4.0.3: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.4, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== +ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.4, ignore@^5.2.0, ignore@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== immediate@~3.0.5: version "3.0.6"