diff --git a/.buildkite/scripts/steps/es_snapshots/build.sh b/.buildkite/scripts/steps/es_snapshots/build.sh index c11f041836413..cdc1750e59bfc 100755 --- a/.buildkite/scripts/steps/es_snapshots/build.sh +++ b/.buildkite/scripts/steps/es_snapshots/build.sh @@ -69,6 +69,7 @@ echo "--- Build Elasticsearch" :distribution:archives:darwin-aarch64-tar:assemble \ :distribution:archives:darwin-tar:assemble \ :distribution:docker:docker-export:assemble \ + :distribution:docker:cloud-docker-export:assemble \ :distribution:archives:linux-aarch64-tar:assemble \ :distribution:archives:linux-tar:assemble \ :distribution:archives:windows-zip:assemble \ @@ -79,11 +80,26 @@ find distribution -type f \( -name 'elasticsearch-*-*-*-*.tar.gz' -o -name 'elas ls -alh "$destination" -echo "--- Create docker image archives" +echo "--- Create docker default image archives" docker images "docker.elastic.co/elasticsearch/elasticsearch" docker images "docker.elastic.co/elasticsearch/elasticsearch" --format "{{.Tag}}" | xargs -n1 echo 'docker save docker.elastic.co/elasticsearch/elasticsearch:${0} | gzip > ../es-build/elasticsearch-${0}-docker-image.tar.gz' docker images "docker.elastic.co/elasticsearch/elasticsearch" --format "{{.Tag}}" | xargs -n1 bash -c 'docker save docker.elastic.co/elasticsearch/elasticsearch:${0} | gzip > ../es-build/elasticsearch-${0}-docker-image.tar.gz' +echo "--- Create kibana-ci docker cloud image archives" +ES_CLOUD_ID=$(docker images "docker.elastic.co/elasticsearch-ci/elasticsearch-cloud" --format "{{.ID}}") +ES_CLOUD_VERSION=$(docker images "docker.elastic.co/elasticsearch-ci/elasticsearch-cloud" --format "{{.Tag}}") +KIBANA_ES_CLOUD_VERSION="$ES_CLOUD_VERSION-$ELASTICSEARCH_GIT_COMMIT" +KIBANA_ES_CLOUD_IMAGE="docker.elastic.co/kibana-ci/elasticsearch-cloud:$KIBANA_ES_CLOUD_VERSION" + +docker tag "$ES_CLOUD_ID" "$KIBANA_ES_CLOUD_IMAGE" + +echo "$KIBANA_DOCKER_PASSWORD" | docker login -u "$KIBANA_DOCKER_USERNAME" --password-stdin docker.elastic.co +trap 'docker logout docker.elastic.co' EXIT +docker image push "$KIBANA_ES_CLOUD_IMAGE" + +export ELASTICSEARCH_CLOUD_IMAGE="$KIBANA_ES_CLOUD_IMAGE" +export ELASTICSEARCH_CLOUD_IMAGE_CHECKSUM="$(docker images "$KIBANA_ES_CLOUD_IMAGE" --format "{{.Digest}}")" + echo "--- Create checksums for snapshot files" cd "$destination" find ./* -exec bash -c "shasum -a 512 {} > {}.sha512" \; diff --git a/.buildkite/scripts/steps/es_snapshots/create_manifest.js b/.buildkite/scripts/steps/es_snapshots/create_manifest.js index cb4ea29a9c534..9357cd72fff06 100644 --- a/.buildkite/scripts/steps/es_snapshots/create_manifest.js +++ b/.buildkite/scripts/steps/es_snapshots/create_manifest.js @@ -16,6 +16,8 @@ const { BASE_BUCKET_DAILY } = require('./bucket_config.js'); const destination = process.argv[2] || __dirname + '/test'; const ES_BRANCH = process.env.ELASTICSEARCH_BRANCH; + const ES_CLOUD_IMAGE = process.env.ELASTICSEARCH_CLOUD_IMAGE; + const ES_CLOUD_IMAGE_CHECKSUM = process.env.ELASTICSEARCH_CLOUD_IMAGE_CHECKSUM; const GIT_COMMIT = process.env.ELASTICSEARCH_GIT_COMMIT; const GIT_COMMIT_SHORT = process.env.ELASTICSEARCH_GIT_COMMIT_SHORT; @@ -59,6 +61,17 @@ const { BASE_BUCKET_DAILY } = require('./bucket_config.js'); }; }); + if (ES_CLOUD_IMAGE && ES_CLOUD_IMAGE_CHECKSUM) { + manifestEntries.push({ + checksum: ES_CLOUD_IMAGE_CHECKSUM, + url: ES_CLOUD_IMAGE, + version: VERSION, + platform: 'docker', + architecture: 'image', + license: 'default', + }); + } + const manifest = { id: SNAPSHOT_ID, bucket: `${BASE_BUCKET_DAILY}/${DESTINATION}`.toString(), diff --git a/.eslintrc.js b/.eslintrc.js index af9d77c4a9662..37c951e7e0763 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -274,12 +274,7 @@ module.exports = { * Licence headers */ { - files: [ - '**/*.{js,mjs,ts,tsx}', - '!plugins/**/*', - '!packages/elastic-datemath/**/*', - '!packages/elastic-eslint-config-kibana/**/*', - ], + files: ['**/*.{js,mjs,ts,tsx}'], rules: { '@kbn/eslint/require-license-header': [ 'error', diff --git a/docs/development/core/public/kibana-plugin-core-public.applicationstart.md b/docs/development/core/public/kibana-plugin-core-public.applicationstart.md index cadf0f91b01d6..eeb8ff3753f13 100644 --- a/docs/development/core/public/kibana-plugin-core-public.applicationstart.md +++ b/docs/development/core/public/kibana-plugin-core-public.applicationstart.md @@ -25,5 +25,5 @@ export interface ApplicationStart | --- | --- | | [getUrlForApp(appId, options)](./kibana-plugin-core-public.applicationstart.geturlforapp.md) | Returns the absolute path (or URL) to a given app, including the global base path.By default, it returns the absolute path of the application (e.g /basePath/app/my-app). Use the absolute option to generate an absolute url instead (e.g http://host:port/basePath/app/my-app)Note that when generating absolute urls, the origin (protocol, host and port) are determined from the browser's current location. | | [navigateToApp(appId, options)](./kibana-plugin-core-public.applicationstart.navigatetoapp.md) | Navigate to a given app | -| [navigateToUrl(url)](./kibana-plugin-core-public.applicationstart.navigatetourl.md) | Navigate to given URL in a SPA friendly way when possible (when the URL will redirect to a valid application within the current basePath).The method resolves pathnames the same way browsers do when resolving a <a href> value. The provided url can be: - an absolute URL - an absolute path - a path relative to the current URL (window.location.href)If all these criteria are true for the given URL: - (only for absolute URLs) The origin of the URL matches the origin of the browser's current location - The resolved pathname of the provided URL/path starts with the current basePath (eg. /mybasepath/s/my-space) - The pathname segment after the basePath matches any known application route (eg. /app// or any application's appRoute configuration)Then a SPA navigation will be performed using navigateToApp using the corresponding application and path. Otherwise, fallback to a full page reload to navigate to the url using window.location.assign | +| [navigateToUrl(url, options)](./kibana-plugin-core-public.applicationstart.navigatetourl.md) | Navigate to given URL in a SPA friendly way when possible (when the URL will redirect to a valid application within the current basePath).The method resolves pathnames the same way browsers do when resolving a <a href> value. The provided url can be: - an absolute URL - an absolute path - a path relative to the current URL (window.location.href)If all these criteria are true for the given URL: - (only for absolute URLs) The origin of the URL matches the origin of the browser's current location - The resolved pathname of the provided URL/path starts with the current basePath (eg. /mybasepath/s/my-space) - The pathname segment after the basePath matches any known application route (eg. /app// or any application's appRoute configuration)Then a SPA navigation will be performed using navigateToApp using the corresponding application and path. Otherwise, fallback to a full page reload to navigate to the url using window.location.assign | diff --git a/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md b/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md index 9e6644e2b1ca7..b7fbb12f12e29 100644 --- a/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md +++ b/docs/development/core/public/kibana-plugin-core-public.applicationstart.navigatetourl.md @@ -15,7 +15,7 @@ Then a SPA navigation will be performed using `navigateToApp` using the correspo Signature: ```typescript -navigateToUrl(url: string): Promise; +navigateToUrl(url: string, options?: NavigateToUrlOptions): Promise; ``` ## Parameters @@ -23,6 +23,7 @@ navigateToUrl(url: string): Promise; | Parameter | Type | Description | | --- | --- | --- | | url | string | an absolute URL, an absolute path or a relative path, to navigate to. | +| options | NavigateToUrlOptions | | Returns: diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index 2e51a036dfe9f..241cd378ebcda 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -85,6 +85,7 @@ The plugin integrates with the core system via lifecycle events: `setup` | [IHttpResponseInterceptorOverrides](./kibana-plugin-core-public.ihttpresponseinterceptoroverrides.md) | Properties that can be returned by HttpInterceptor.request to override the response. | | [IUiSettingsClient](./kibana-plugin-core-public.iuisettingsclient.md) | Client-side client that provides access to the advanced settings stored in elasticsearch. The settings provide control over the behavior of the Kibana application. For example, a user can specify how to display numeric or date fields. Users can adjust the settings via Management UI. [IUiSettingsClient](./kibana-plugin-core-public.iuisettingsclient.md) | | [NavigateToAppOptions](./kibana-plugin-core-public.navigatetoappoptions.md) | Options for the [navigateToApp API](./kibana-plugin-core-public.applicationstart.navigatetoapp.md) | +| [NavigateToUrlOptions](./kibana-plugin-core-public.navigatetourloptions.md) | Options for the [navigateToUrl API](./kibana-plugin-core-public.applicationstart.navigatetourl.md) | | [NotificationsSetup](./kibana-plugin-core-public.notificationssetup.md) | | | [NotificationsStart](./kibana-plugin-core-public.notificationsstart.md) | | | [OverlayBannersStart](./kibana-plugin-core-public.overlaybannersstart.md) | | diff --git a/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.md b/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.md index c8ec5bdaf8c0d..337e9db1f80d2 100644 --- a/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.md +++ b/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.md @@ -20,5 +20,6 @@ export interface NavigateToAppOptions | [openInNewTab?](./kibana-plugin-core-public.navigatetoappoptions.openinnewtab.md) | boolean | (Optional) if true, will open the app in new tab, will share session information via window.open if base | | [path?](./kibana-plugin-core-public.navigatetoappoptions.path.md) | string | (Optional) optional path inside application to deep link to. If undefined, will use [the app's default path](./kibana-plugin-core-public.app.defaultpath.md) as default. | | [replace?](./kibana-plugin-core-public.navigatetoappoptions.replace.md) | boolean | (Optional) if true, will not create a new history entry when navigating (using replace instead of push) | +| [skipAppLeave?](./kibana-plugin-core-public.navigatetoappoptions.skipappleave.md) | boolean | (Optional) if true, will bypass the default onAppLeave behavior | | [state?](./kibana-plugin-core-public.navigatetoappoptions.state.md) | unknown | (Optional) optional state to forward to the application | diff --git a/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.skipappleave.md b/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.skipappleave.md new file mode 100644 index 0000000000000..553d557a92daa --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.navigatetoappoptions.skipappleave.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [NavigateToAppOptions](./kibana-plugin-core-public.navigatetoappoptions.md) > [skipAppLeave](./kibana-plugin-core-public.navigatetoappoptions.skipappleave.md) + +## NavigateToAppOptions.skipAppLeave property + +if true, will bypass the default onAppLeave behavior + +Signature: + +```typescript +skipAppLeave?: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.forceredirect.md b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.forceredirect.md new file mode 100644 index 0000000000000..1603524322dd7 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.forceredirect.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [NavigateToUrlOptions](./kibana-plugin-core-public.navigatetourloptions.md) > [forceRedirect](./kibana-plugin-core-public.navigatetourloptions.forceredirect.md) + +## NavigateToUrlOptions.forceRedirect property + +if true, will redirect directly to the url + +Signature: + +```typescript +forceRedirect?: boolean; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.md b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.md new file mode 100644 index 0000000000000..ccf09e21189ef --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [NavigateToUrlOptions](./kibana-plugin-core-public.navigatetourloptions.md) + +## NavigateToUrlOptions interface + +Options for the [navigateToUrl API](./kibana-plugin-core-public.applicationstart.navigatetourl.md) + +Signature: + +```typescript +export interface NavigateToUrlOptions +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [forceRedirect?](./kibana-plugin-core-public.navigatetourloptions.forceredirect.md) | boolean | (Optional) if true, will redirect directly to the url | +| [skipAppLeave?](./kibana-plugin-core-public.navigatetourloptions.skipappleave.md) | boolean | (Optional) if true, will bypass the default onAppLeave behavior | + diff --git a/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.skipappleave.md b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.skipappleave.md new file mode 100644 index 0000000000000..f3685c02ff40d --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.navigatetourloptions.skipappleave.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [NavigateToUrlOptions](./kibana-plugin-core-public.navigatetourloptions.md) > [skipAppLeave](./kibana-plugin-core-public.navigatetourloptions.skipappleave.md) + +## NavigateToUrlOptions.skipAppLeave property + +if true, will bypass the default onAppLeave behavior + +Signature: + +```typescript +skipAppLeave?: boolean; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.savedobjectsfieldmapping.md b/docs/development/core/server/kibana-plugin-core-server.savedobjectsfieldmapping.md index 85b52bacafa25..cf5b5d7e6e339 100644 --- a/docs/development/core/server/kibana-plugin-core-server.savedobjectsfieldmapping.md +++ b/docs/development/core/server/kibana-plugin-core-server.savedobjectsfieldmapping.md @@ -13,5 +13,6 @@ Please refer to [elasticsearch documentation](https://www.elastic.co/guide/en/el ```typescript export declare type SavedObjectsFieldMapping = estypes.MappingProperty & { dynamic?: false | 'strict'; + properties?: Record; }; ``` diff --git a/docs/management/connectors/action-types/servicenow-sir.asciidoc b/docs/management/connectors/action-types/servicenow-sir.asciidoc index 70500b26c16e6..81db72be0fb38 100644 --- a/docs/management/connectors/action-types/servicenow-sir.asciidoc +++ b/docs/management/connectors/action-types/servicenow-sir.asciidoc @@ -5,7 +5,7 @@ ServiceNow SecOps ++++ -The {sn} SecOps connector uses the https://docs.servicenow.com/bundle/orlando-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html[V2 Table API] to create {sn} security incidents. +The {sn} SecOps connector uses the https://developer.servicenow.com/dev.do#!/reference/api/sandiego/rest/c_ImportSetAPI[Import Set API] to create {sn} security incidents. [float] [[servicenow-sir-connector-prerequisites]] diff --git a/docs/management/connectors/action-types/servicenow.asciidoc b/docs/management/connectors/action-types/servicenow.asciidoc index 73e3baaca2ad1..333a26c075c49 100644 --- a/docs/management/connectors/action-types/servicenow.asciidoc +++ b/docs/management/connectors/action-types/servicenow.asciidoc @@ -5,7 +5,7 @@ ServiceNow ITSM ++++ -The {sn} ITSM connector uses the https://docs.servicenow.com/bundle/orlando-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html[V2 Table API] to create {sn} incidents. +The {sn} ITSM connector uses the https://developer.servicenow.com/dev.do#!/reference/api/sandiego/rest/c_ImportSetAPI[Import Set API] to create {sn} incidents. [float] [[servicenow-itsm-connector-prerequisites]] diff --git a/fleet_packages.json b/fleet_packages.json index c620d438d4f8d..3a12e605316a7 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -27,7 +27,7 @@ }, { "name": "fleet_server", - "version": "1.1.0" + "version": "1.1.1" }, { "name": "synthetics", diff --git a/package.json b/package.json index 76a84675c2eb2..6e7886823fca1 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "@elastic/apm-synthtrace": "link:bazel-bin/packages/elastic-apm-synthtrace", "@elastic/charts": "45.1.1", "@elastic/datemath": "link:bazel-bin/packages/elastic-datemath", - "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.2.0-canary.1", + "@elastic/elasticsearch": "npm:@elastic/elasticsearch-canary@8.2.0-canary.2", "@elastic/ems-client": "8.2.0", "@elastic/eui": "53.0.1", "@elastic/filesaver": "1.1.2", @@ -753,7 +753,7 @@ "callsites": "^3.1.0", "chai": "3.5.0", "chance": "1.0.18", - "chromedriver": "^99.0.0", + "chromedriver": "^100.0.0", "clean-webpack-plugin": "^3.0.0", "cmd-shim": "^2.1.0", "compression-webpack-plugin": "^4.0.0", diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 1d9406ac37447..7d209035ab65a 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -242,6 +242,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { asyncSearch: `${ELASTICSEARCH_DOCS}async-search-intro.html`, dataStreams: `${ELASTICSEARCH_DOCS}data-streams.html`, deprecationLogging: `${ELASTICSEARCH_DOCS}logging.html#deprecation-logging`, + createIndex: `${ELASTICSEARCH_DOCS}indices-create-index.html`, frozenIndices: `${ELASTICSEARCH_DOCS}frozen-indices.html`, gettingStarted: `${ELASTICSEARCH_DOCS}getting-started.html`, hiddenIndices: `${ELASTICSEARCH_DOCS}multi-index.html#hidden`, diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts index f984484dd4091..023af9fc7050e 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/actions/index.ts @@ -12,8 +12,8 @@ import * as t from 'io-ts'; import { saved_object_attributes } from '../saved_object_attributes'; /** - * Params is an "object", since it is a type of AlertActionParams which is action templates. - * @see x-pack/plugins/alerting/common/alert.ts + * Params is an "object", since it is a type of RuleActionParams which is action templates. + * @see x-pack/plugins/alerting/common/rule.ts */ export const action_group = t.string; export const action_id = t.string; diff --git a/packages/kbn-shared-ux-components/src/index.ts b/packages/kbn-shared-ux-components/src/index.ts index 9216f5b21d7f5..557ac980a14c6 100644 --- a/packages/kbn-shared-ux-components/src/index.ts +++ b/packages/kbn-shared-ux-components/src/index.ts @@ -95,6 +95,23 @@ export const LazyIconButtonGroup = React.lazy(() => */ export const IconButtonGroup = withSuspense(LazyIconButtonGroup); +/** + * The lazily loaded `KibanaPageTemplateSolutionNav` component that is wrapped by the `withSuspense` HOC. Consumers should use + * `React.Suspense` or `withSuspense` HOC to load this component. + */ +export const KibanaPageTemplateSolutionNavLazy = React.lazy(() => + import('./page_template/solution_nav').then(({ KibanaPageTemplateSolutionNav }) => ({ + default: KibanaPageTemplateSolutionNav, + })) +); + +/** + * A `KibanaPageTemplateSolutionNav` component that is wrapped by the `withSuspense` HOC. This component can + * be used directly by consumers and will load the `KibanaPageTemplateSolutionNavLazy` component lazily with + * a predefined fallback and error boundary. + */ +export const KibanaPageTemplateSolutionNav = withSuspense(KibanaPageTemplateSolutionNavLazy); + /** * The Lazily-loaded `KibanaSolutionAvatar` component. Consumers should use `React.Suspense` or * the withSuspense` HOC to load this component. diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap new file mode 100644 index 0000000000000..fce0e996d99cd --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav.test.tsx.snap @@ -0,0 +1,267 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KibanaPageTemplateSolutionNav accepts EuiSideNavProps 1`] = ` + + + + Solution + + + } + isOpenOnMobile={false} + items={ + Array [ + Object { + "id": "1", + "items": Array [ + Object { + "id": "1.1", + "items": undefined, + "name": "Ingest Node Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.2", + "items": undefined, + "name": "Logstash Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.3", + "items": undefined, + "name": "Beats Central Management", + "tabIndex": undefined, + }, + ], + "name": "Ingest", + "tabIndex": undefined, + }, + Object { + "id": "2", + "items": Array [ + Object { + "id": "2.1", + "items": undefined, + "name": "Index Management", + "tabIndex": undefined, + }, + Object { + "id": "2.2", + "items": undefined, + "name": "Index Lifecycle Policies", + "tabIndex": undefined, + }, + Object { + "id": "2.3", + "items": undefined, + "name": "Snapshot and Restore", + "tabIndex": undefined, + }, + ], + "name": "Data", + "tabIndex": undefined, + }, + ] + } + mobileTitle={ + + + + } + toggleOpenOnMobile={[Function]} + /> + +`; + +exports[`KibanaPageTemplateSolutionNav renders 1`] = ` + + + + Solution + + + } + isOpenOnMobile={false} + items={ + Array [ + Object { + "id": "1", + "items": Array [ + Object { + "id": "1.1", + "items": undefined, + "name": "Ingest Node Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.2", + "items": undefined, + "name": "Logstash Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.3", + "items": undefined, + "name": "Beats Central Management", + "tabIndex": undefined, + }, + ], + "name": "Ingest", + "tabIndex": undefined, + }, + Object { + "id": "2", + "items": Array [ + Object { + "id": "2.1", + "items": undefined, + "name": "Index Management", + "tabIndex": undefined, + }, + Object { + "id": "2.2", + "items": undefined, + "name": "Index Lifecycle Policies", + "tabIndex": undefined, + }, + Object { + "id": "2.3", + "items": undefined, + "name": "Snapshot and Restore", + "tabIndex": undefined, + }, + ], + "name": "Data", + "tabIndex": undefined, + }, + ] + } + mobileTitle={ + + + + } + toggleOpenOnMobile={[Function]} + /> + +`; + +exports[`KibanaPageTemplateSolutionNav renders with icon 1`] = ` + + + + + Solution + + + } + isOpenOnMobile={false} + items={ + Array [ + Object { + "id": "1", + "items": Array [ + Object { + "id": "1.1", + "items": undefined, + "name": "Ingest Node Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.2", + "items": undefined, + "name": "Logstash Pipelines", + "tabIndex": undefined, + }, + Object { + "id": "1.3", + "items": undefined, + "name": "Beats Central Management", + "tabIndex": undefined, + }, + ], + "name": "Ingest", + "tabIndex": undefined, + }, + Object { + "id": "2", + "items": Array [ + Object { + "id": "2.1", + "items": undefined, + "name": "Index Management", + "tabIndex": undefined, + }, + Object { + "id": "2.2", + "items": undefined, + "name": "Index Lifecycle Policies", + "tabIndex": undefined, + }, + Object { + "id": "2.3", + "items": undefined, + "name": "Snapshot and Restore", + "tabIndex": undefined, + }, + ], + "name": "Data", + "tabIndex": undefined, + }, + ] + } + mobileTitle={ + + + + + } + toggleOpenOnMobile={[Function]} + /> + +`; diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav_collapse_button.test.tsx.snap b/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav_collapse_button.test.tsx.snap new file mode 100644 index 0000000000000..d2548b3e8df43 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/__snapshots__/solution_nav_collapse_button.test.tsx.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`KibanaPageTemplateSolutionNavCollapseButton isCollapsed 1`] = ` + +`; + +exports[`KibanaPageTemplateSolutionNavCollapseButton renders 1`] = ` + +`; diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/index.ts b/packages/kbn-shared-ux-components/src/page_template/solution_nav/index.ts new file mode 100644 index 0000000000000..59ef2924b048d --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/index.ts @@ -0,0 +1,12 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { KibanaPageTemplateSolutionNavProps } from './solution_nav'; +export { KibanaPageTemplateSolutionNav } from './solution_nav'; +export type { KibanaPageTemplateSolutionNavCollapseButtonProps } from './solution_nav_collapse_button'; +export { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button'; diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.scss b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.scss new file mode 100644 index 0000000000000..d0070cef729b7 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.scss @@ -0,0 +1,30 @@ +$euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7); +@import '@elastic/eui/src/components/side_nav/mixins'; + +// Put the page background color in the flyout version too +.kbnPageTemplateSolutionNav__flyout { + background-color: $euiPageBackgroundColor; +} + +.kbnPageTemplateSolutionNav { + @include euiSideNavEmbellish; + @include euiYScroll; + + @include euiBreakpoint('m' ,'l', 'xl') { + width: 248px; + padding: $euiSizeL; + } + + .kbnPageTemplateSolutionNavAvatar { + margin-right: $euiSize; + } +} + +.kbnPageTemplateSolutionNav--hidden { + pointer-events: none; + opacity: 0; + + @include euiCanAnimate { + transition: opacity $euiAnimSpeedFast $euiAnimSlightResistance; + } +} diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.stories.tsx b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.stories.tsx new file mode 100644 index 0000000000000..5ff1e2c07d9d8 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.stories.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav'; + +export default { + title: 'Page Template/Solution Nav/Solution Nav', + description: 'Solution-specific navigation for the sidebar', +}; + +type Params = Pick; + +const items: KibanaPageTemplateSolutionNavProps['items'] = [ + { + name:
Ingest
, + id: '1', + items: [ + { + name: 'Ingest Node Pipelines', + id: '1.1', + }, + { + name: 'Logstash Pipelines', + id: '1.2', + }, + { + name: 'Beats Central Management', + id: '1.3', + }, + ], + }, + { + name: 'Data', + id: '2', + items: [ + { + name: 'Index Management', + id: '2.1', + }, + { + name: 'Index Lifecycle Policies', + id: '2.2', + }, + { + name: 'Snapshot and Restore', + id: '2.3', + }, + ], + }, +]; + +export const PureComponent = (params: Params) => { + return ; +}; + +PureComponent.argTypes = { + name: { + control: 'text', + defaultValue: 'Kibana', + }, + icon: { + control: { type: 'radio' }, + options: ['logoKibana', 'logoObservability', 'logoSecurity'], + defaultValue: 'logoKibana', + }, +}; diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.test.tsx b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.test.tsx new file mode 100644 index 0000000000000..ed90894289169 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.test.tsx @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; +import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav'; + +jest.mock('@elastic/eui', () => ({ + useIsWithinBreakpoints: (args: string[]) => { + return args[0] === 'xs'; + }, +})); + +const items: KibanaPageTemplateSolutionNavProps['items'] = [ + { + name: 'Ingest', + id: '1', + items: [ + { + name: 'Ingest Node Pipelines', + id: '1.1', + }, + { + name: 'Logstash Pipelines', + id: '1.2', + }, + { + name: 'Beats Central Management', + id: '1.3', + }, + ], + }, + { + name: 'Data', + id: '2', + items: [ + { + name: 'Index Management', + id: '2.1', + }, + { + name: 'Index Lifecycle Policies', + id: '2.2', + }, + { + name: 'Snapshot and Restore', + id: '2.3', + }, + ], + }, +]; + +describe('KibanaPageTemplateSolutionNav', () => { + test('renders', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + }); + + test('renders with icon', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); + + test('accepts EuiSideNavProps', () => { + const component = shallow( + + ); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.tsx b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.tsx new file mode 100644 index 0000000000000..8bc91789c7054 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav.tsx @@ -0,0 +1,164 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 './solution_nav.scss'; + +import React, { FunctionComponent, useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { + EuiAvatarProps, + EuiFlyout, + EuiSideNav, + EuiSideNavItemType, + EuiSideNavProps, + useIsWithinBreakpoints, +} from '@elastic/eui'; + +import classNames from 'classnames'; +import { KibanaSolutionAvatar } from '../../solution_avatar'; +import { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button'; + +export type KibanaPageTemplateSolutionNavProps = EuiSideNavProps<{}> & { + /** + * Name of the solution, i.e. "Observability" + */ + name: EuiAvatarProps['name']; + /** + * Solution logo, i.e. "logoObservability" + */ + icon?: EuiAvatarProps['iconType']; + /** + * Control the collapsed state + */ + isOpenOnDesktop?: boolean; + onCollapse?: () => void; +}; + +const FLYOUT_SIZE = 248; + +const setTabIndex = (items: Array>, isHidden: boolean) => { + return items.map((item) => { + // @ts-ignore-next-line Can be removed on close of https://github.com/elastic/eui/issues/4925 + item.tabIndex = isHidden ? -1 : undefined; + item.items = item.items && setTabIndex(item.items, isHidden); + return item; + }); +}; + +/** + * A wrapper around EuiSideNav but also creates the appropriate title with optional solution logo + */ +export const KibanaPageTemplateSolutionNav: FunctionComponent< + KibanaPageTemplateSolutionNavProps +> = ({ name, icon, items, isOpenOnDesktop = false, onCollapse, ...rest }) => { + const isSmallerBreakpoint = useIsWithinBreakpoints(['xs', 's']); + const isMediumBreakpoint = useIsWithinBreakpoints(['m']); + const isLargerBreakpoint = useIsWithinBreakpoints(['l', 'xl']); + + // This is used for both the EuiSideNav and EuiFlyout toggling + const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false); + const toggleOpenOnMobile = () => { + setIsSideNavOpenOnMobile(!isSideNavOpenOnMobile); + }; + + const isHidden = isLargerBreakpoint && !isOpenOnDesktop; + + /** + * Create the avatar + */ + const solutionAvatar = icon ? ( + + ) : null; + + /** + * Create the titles + */ + const titleText = ( + <> + {solutionAvatar} + {name} + + ); + const mobileTitleText = ( + + ); + + /** + * Create the side nav component + */ + + const sideNav = () => { + if (!items) { + return null; + } + const sideNavClasses = classNames('kbnPageTemplateSolutionNav', { + 'kbnPageTemplateSolutionNav--hidden': isHidden, + }); + return ( + + {solutionAvatar} + {mobileTitleText} + + } + toggleOpenOnMobile={toggleOpenOnMobile} + isOpenOnMobile={isSideNavOpenOnMobile} + items={setTabIndex(items, isHidden)} + {...rest} + /> + ); + }; + + return ( + <> + {isSmallerBreakpoint && sideNav()} + {isMediumBreakpoint && ( + <> + {isSideNavOpenOnMobile && ( + setIsSideNavOpenOnMobile(false)} + side="left" + size={FLYOUT_SIZE} + closeButtonPosition="outside" + className="kbnPageTemplateSolutionNav__flyout" + > + {sideNav()} + + )} + + + )} + {isLargerBreakpoint && ( + <> + {sideNav()} + + + )} + + ); +}; diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.scss b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.scss new file mode 100644 index 0000000000000..61cea7962d956 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.scss @@ -0,0 +1,47 @@ +.kbnPageTemplateSolutionNavCollapseButton { + position: absolute; + opacity: 0; + left: 248px - $euiSize; + top: $euiSizeL; + z-index: 2; + + @include euiCanAnimate { + transition: opacity $euiAnimSpeedFast, left $euiAnimSpeedFast, background $euiAnimSpeedFast; + } + + &:hover, + &:focus { + transition-delay: 0s !important; + } + + .kbnPageTemplate__pageSideBar:hover &, + &:hover, + &:focus { + opacity: 1; + left: 248px - $euiSizeL; + } + + .kbnPageTemplate__pageSideBar:hover & { + transition-delay: $euiAnimSpeedSlow * 2; + } + + &:not(&-isCollapsed) { + background-color: $euiColorEmptyShade !important; // Override all states + } +} + +// Make the button take up the entire area of the collapsed navigation +.kbnPageTemplateSolutionNavCollapseButton-isCollapsed { + opacity: 1 !important; + transition-delay: 0s !important; + left: 0 !important; + right: 0; + top: 0; + bottom: 0; + height: 100%; + width: 100%; + border-radius: 0; + // Keep the icon at the top instead of it getting shifted to the center of the page + padding-top: $euiSizeL + $euiSizeS; + align-items: flex-start; +} diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.test.tsx b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.test.tsx new file mode 100644 index 0000000000000..e7df2ddd54582 --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.test.tsx @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { shallow } from 'enzyme'; +import React from 'react'; +import { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button'; + +describe('KibanaPageTemplateSolutionNavCollapseButton', () => { + test('renders', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + expect(component.find('.kbnPageTemplateSolutionNavCollapseButton').prop('title')).toBe( + 'Collapse side navigation' + ); + }); + + test('isCollapsed', () => { + const component = shallow(); + expect(component).toMatchSnapshot(); + expect(component.find('.kbnPageTemplateSolutionNavCollapseButton').prop('title')).toBe( + 'Open side navigation' + ); + }); +}); diff --git a/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.tsx b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.tsx new file mode 100644 index 0000000000000..35890b935ad3e --- /dev/null +++ b/packages/kbn-shared-ux-components/src/page_template/solution_nav/solution_nav_collapse_button.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 './solution_nav_collapse_button.scss'; + +import React from 'react'; +import classNames from 'classnames'; + +import { EuiButtonIcon, EuiButtonIconPropsForButton } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +export type KibanaPageTemplateSolutionNavCollapseButtonProps = + Partial & { + /** + * Boolean state of current collapsed status + */ + isCollapsed: boolean; + }; + +const collapseLabel = i18n.translate('sharedUXComponents.solutionNav.collapsibleLabel', { + defaultMessage: 'Collapse side navigation', +}); + +const openLabel = i18n.translate('sharedUXComponents.solutionNav.openLabel', { + defaultMessage: 'Open side navigation', +}); + +/** + * Creates the styled icon button for showing/hiding solution nav + */ +export const KibanaPageTemplateSolutionNavCollapseButton = ({ + className, + isCollapsed, + ...rest +}: KibanaPageTemplateSolutionNavCollapseButtonProps) => { + const classes = classNames( + 'kbnPageTemplateSolutionNavCollapseButton', + { + 'kbnPageTemplateSolutionNavCollapseButton-isCollapsed': isCollapsed, + }, + className + ); + + return ( + + ); +}; diff --git a/packages/kbn-shared-ux-components/src/solution_avatar/index.tsx b/packages/kbn-shared-ux-components/src/solution_avatar/index.tsx index db31c0fd5a3d4..efc597cbdcb13 100644 --- a/packages/kbn-shared-ux-components/src/solution_avatar/index.tsx +++ b/packages/kbn-shared-ux-components/src/solution_avatar/index.tsx @@ -5,5 +5,5 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ - export { KibanaSolutionAvatar } from './solution_avatar'; +export type { KibanaSolutionAvatarProps } from './solution_avatar'; diff --git a/packages/kbn-shared-ux-components/src/solution_avatar/solution_avatar.tsx b/packages/kbn-shared-ux-components/src/solution_avatar/solution_avatar.tsx index 78459b90e4b3b..deb71affc9c1a 100644 --- a/packages/kbn-shared-ux-components/src/solution_avatar/solution_avatar.tsx +++ b/packages/kbn-shared-ux-components/src/solution_avatar/solution_avatar.tsx @@ -8,9 +8,9 @@ import './solution_avatar.scss'; import React from 'react'; -import classNames from 'classnames'; import { DistributiveOmit, EuiAvatar, EuiAvatarProps } from '@elastic/eui'; +import classNames from 'classnames'; export type KibanaSolutionAvatarProps = DistributiveOmit & { /** @@ -20,7 +20,7 @@ export type KibanaSolutionAvatarProps = DistributiveOmit }; /** - * Applies extra styling to a typical EuiAvatar; + * Applies extra styling to a typical EuiAvatar. * The `name` value will be appended to 'logo' to configure the `iconType` unless `iconType` is provided. */ export const KibanaSolutionAvatar = ({ className, size, ...rest }: KibanaSolutionAvatarProps) => { @@ -34,9 +34,9 @@ export const KibanaSolutionAvatar = ({ className, size, ...rest }: KibanaSolutio }, className )} - color="plain" size={size === 'xxl' ? 'xl' : size} iconSize={size} + color="plain" iconType={`logo${rest.name}`} {...rest} /> diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index ccb0b220e0243..bb7378ff1f0f3 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -898,10 +898,9 @@ describe('#start()', () => { it('should call private function shouldNavigate with overlays and the nextAppId', async () => { service.setup(setupDeps); - const shouldNavigateSpy = jest.spyOn(service as any, 'shouldNavigate'); + const shouldNavigateSpy = jest.spyOn(service as any, 'shouldNavigate'); const { navigateToApp } = await service.start(startDeps); - await navigateToApp('myTestApp'); expect(shouldNavigateSpy).toHaveBeenCalledWith(startDeps.overlays, 'myTestApp'); @@ -909,6 +908,14 @@ describe('#start()', () => { expect(shouldNavigateSpy).toHaveBeenCalledWith(startDeps.overlays, 'myOtherApp'); }); + it('should call private function shouldNavigate with overlays, nextAppId and skipAppLeave', async () => { + service.setup(setupDeps); + const shouldNavigateSpy = jest.spyOn(service as any, 'shouldNavigate'); + const { navigateToApp } = await service.start(startDeps); + await navigateToApp('myTestApp', { skipAppLeave: true }); + expect(shouldNavigateSpy).not.toHaveBeenCalledWith(startDeps.overlays, 'myTestApp'); + }); + describe('when `replace` option is true', () => { it('use `history.replace` instead of `history.push`', async () => { service.setup(setupDeps); @@ -1117,6 +1124,63 @@ describe('#start()', () => { expect(MockHistory.push).toHaveBeenCalledWith('/app/foo/some-path', undefined); expect(setupDeps.redirectTo).not.toHaveBeenCalled(); }); + + describe('navigateToUrl with options', () => { + let addListenerSpy: jest.SpyInstance; + let removeListenerSpy: jest.SpyInstance; + beforeEach(() => { + addListenerSpy = jest.spyOn(window, 'addEventListener'); + removeListenerSpy = jest.spyOn(window, 'removeEventListener'); + }); + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('calls `navigateToApp` with `skipAppLeave` option', async () => { + parseAppUrlMock.mockReturnValue({ app: 'foo', path: '/some-path' }); + service.setup(setupDeps); + const { navigateToUrl } = await service.start(startDeps); + + await navigateToUrl('/an-app-path', { skipAppLeave: true }); + + expect(MockHistory.push).toHaveBeenCalledWith('/app/foo/some-path', undefined); + expect(setupDeps.redirectTo).not.toHaveBeenCalled(); + }); + + it('calls `redirectTo` when `forceRedirect` option is true', async () => { + parseAppUrlMock.mockReturnValue({ app: 'foo', path: '/some-path' }); + service.setup(setupDeps); + + const { navigateToUrl } = await service.start(startDeps); + + await navigateToUrl('/an-app-path', { forceRedirect: true }); + + expect(addListenerSpy).toHaveBeenCalledTimes(1); + expect(addListenerSpy).toHaveBeenCalledWith('beforeunload', expect.any(Function)); + + expect(setupDeps.redirectTo).toHaveBeenCalledWith('/an-app-path'); + expect(MockHistory.push).not.toHaveBeenCalled(); + }); + + it('removes the beforeunload listener and calls `redirectTo` when `forceRedirect` and `skipAppLeave` option are both true', async () => { + parseAppUrlMock.mockReturnValue({ app: 'foo', path: '/some-path' }); + service.setup(setupDeps); + + const { navigateToUrl } = await service.start(startDeps); + + await navigateToUrl('/an-app-path', { skipAppLeave: true, forceRedirect: true }); + + expect(addListenerSpy).toHaveBeenCalledTimes(1); + expect(addListenerSpy).toHaveBeenCalledWith('beforeunload', expect.any(Function)); + const handler = addListenerSpy.mock.calls[0][1]; + + expect(MockHistory.push).toHaveBeenCalledTimes(0); + expect(setupDeps.redirectTo).toHaveBeenCalledWith('/an-app-path'); + + expect(removeListenerSpy).toHaveBeenCalledTimes(1); + expect(removeListenerSpy).toHaveBeenCalledWith('beforeunload', handler); + }); + }); }); }); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 1cfae598f67c8..d49a33e3f1371 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -31,6 +31,7 @@ import { InternalApplicationStart, Mounter, NavigateToAppOptions, + NavigateToUrlOptions, } from './types'; import { getLeaveAction, isConfirmAction } from './application_leave'; import { getUserConfirmationHandler } from './navigation_confirm'; @@ -234,13 +235,19 @@ export class ApplicationService { const navigateToApp: InternalApplicationStart['navigateToApp'] = async ( appId, - { deepLinkId, path, state, replace = false, openInNewTab = false }: NavigateToAppOptions = {} + { + deepLinkId, + path, + state, + replace = false, + openInNewTab = false, + skipAppLeave = false, + }: NavigateToAppOptions = {} ) => { const currentAppId = this.currentAppId$.value; const navigatingToSameApp = currentAppId === appId; - const shouldNavigate = navigatingToSameApp - ? true - : await this.shouldNavigate(overlays, appId); + const shouldNavigate = + navigatingToSameApp || skipAppLeave ? true : await this.shouldNavigate(overlays, appId); const targetApp = applications$.value.get(appId); @@ -304,13 +311,20 @@ export class ApplicationService { return absolute ? relativeToAbsolute(relUrl) : relUrl; }, navigateToApp, - navigateToUrl: async (url) => { + navigateToUrl: async ( + url: string, + { skipAppLeave = false, forceRedirect = false }: NavigateToUrlOptions = {} + ) => { const appInfo = parseAppUrl(url, http.basePath, this.apps); - if (appInfo) { - return navigateToApp(appInfo.app, { path: appInfo.path }); - } else { + if ((forceRedirect || !appInfo) === true) { + if (skipAppLeave) { + window.removeEventListener('beforeunload', this.onBeforeUnload); + } return this.redirectTo!(url); } + if (appInfo) { + return navigateToApp(appInfo.app, { path: appInfo.path, skipAppLeave }); + } }, getComponent: () => { if (!this.history) { diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index 882555fcd60e0..55ac8f47becfa 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -28,6 +28,7 @@ export type { AppLeaveDefaultAction, AppLeaveConfirmAction, NavigateToAppOptions, + NavigateToUrlOptions, PublicAppInfo, PublicAppDeepLinkInfo, // Internal types diff --git a/src/core/public/application/integration_tests/application_service.test.tsx b/src/core/public/application/integration_tests/application_service.test.tsx index dda029c66f4c3..99e6d86b6a941 100644 --- a/src/core/public/application/integration_tests/application_service.test.tsx +++ b/src/core/public/application/integration_tests/application_service.test.tsx @@ -170,7 +170,28 @@ describe('ApplicationService', () => { '/app/app1/deep-link', ]); }); - //// + + it('handles `skipOnAppLeave` option', async () => { + const { register } = service.setup(setupDeps); + + register(Symbol(), { + id: 'app1', + title: 'App1', + mount: async ({}: AppMountParameters) => { + return () => undefined; + }, + }); + + const { navigateToApp } = await service.start(startDeps); + + await navigateToApp('app1', { path: '/foo' }); + await navigateToApp('app1', { path: '/bar', skipAppLeave: true }); + expect(history.entries.map((entry) => entry.pathname)).toEqual([ + '/', + '/app/app1/foo', + '/app/app1/bar', + ]); + }); }); }); @@ -249,6 +270,38 @@ describe('ApplicationService', () => { expect(history.entries[2].pathname).toEqual('/app/app2'); }); + it('does not trigger the action if `skipAppLeave` is true', async () => { + const { register } = service.setup(setupDeps); + + register(Symbol(), { + id: 'app1', + title: 'App1', + mount: ({ onAppLeave }: AppMountParameters) => { + onAppLeave((actions) => actions.confirm('confirmation-message', 'confirmation-title')); + return () => undefined; + }, + }); + register(Symbol(), { + id: 'app2', + title: 'App2', + mount: ({}: AppMountParameters) => { + return () => undefined; + }, + }); + + const { navigateToApp, getComponent } = await service.start(startDeps); + + update = createRenderer(getComponent()); + + await act(async () => { + await navigate('/app/app1'); + await navigateToApp('app2', { skipAppLeave: true }); + }); + expect(startDeps.overlays.openConfirm).toHaveBeenCalledTimes(0); + expect(history.entries.length).toEqual(3); + expect(history.entries[1].pathname).toEqual('/app/app1'); + }); + it('blocks navigation to the new app if action is confirm and user declined', async () => { startDeps.overlays.openConfirm.mockResolvedValue(false); diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 659145a9958f1..4e96e96505083 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -740,6 +740,26 @@ export interface NavigateToAppOptions { * if true, will open the app in new tab, will share session information via window.open if base */ openInNewTab?: boolean; + + /** + * if true, will bypass the default onAppLeave behavior + */ + skipAppLeave?: boolean; +} + +/** + * Options for the {@link ApplicationStart.navigateToUrl | navigateToUrl API} + * @public + */ +export interface NavigateToUrlOptions { + /** + * if true, will bypass the default onAppLeave behavior + */ + skipAppLeave?: boolean; + /** + * if true will force a full page reload/refresh/assign, overriding the outcome of other url checks against current the location (effectively using `window.location.assign` instead of `push`) + */ + forceRedirect?: boolean; } /** @public */ @@ -781,7 +801,7 @@ export interface ApplicationStart { * - The pathname segment after the basePath matches any known application route (eg. /app// or any application's `appRoute` configuration) * * Then a SPA navigation will be performed using `navigateToApp` using the corresponding application and path. - * Otherwise, fallback to a full page reload to navigate to the url using `window.location.assign` + * Otherwise, fallback to a full page reload to navigate to the url using `window.location.assign`. * * @example * ```ts @@ -802,8 +822,7 @@ export interface ApplicationStart { * * @param url - an absolute URL, an absolute path or a relative path, to navigate to. */ - navigateToUrl(url: string): Promise; - + navigateToUrl(url: string, options?: NavigateToUrlOptions): Promise; /** * Returns the absolute path (or URL) to a given app, including the global base path. * diff --git a/src/core/public/chrome/ui/header/collapsible_nav.tsx b/src/core/public/chrome/ui/header/collapsible_nav.tsx index 498efcfd9076e..54adb34550462 100644 --- a/src/core/public/chrome/ui/header/collapsible_nav.tsx +++ b/src/core/public/chrome/ui/header/collapsible_nav.tsx @@ -89,7 +89,7 @@ const overviewIDsToHide = ['kibanaOverview', 'enterpriseSearch']; const overviewIDs = [ ...overviewIDsToHide, 'observability-overview', - 'securitySolutionUI:overview', + 'securitySolutionUI:get_started', 'management', ]; diff --git a/src/core/public/i18n/i18n_eui_mapping.test.ts b/src/core/public/i18n/i18n_eui_mapping.test.ts index aa78345a86de1..a2d35b37ac569 100644 --- a/src/core/public/i18n/i18n_eui_mapping.test.ts +++ b/src/core/public/i18n/i18n_eui_mapping.test.ts @@ -17,6 +17,7 @@ import { getEuiContextMapping } from './i18n_eui_mapping'; const VALUES_REGEXP = /\{\w+\}/; describe('@elastic/eui i18n tokens', () => { + const i18nTranslateActual = jest.requireActual('@kbn/i18n').i18n.translate; const i18nTranslateMock = jest .fn() .mockImplementation((id, { defaultMessage }) => defaultMessage); @@ -74,34 +75,9 @@ describe('@elastic/eui i18n tokens', () => { }); test('defaultMessage is in sync with defString', () => { - // Certain complex tokens (e.g. ones that have a function as a defaultMessage) - // need custom i18n handling, and can't be checked for basic defString equality - const tokensToSkip = [ - 'euiColumnSorting.buttonActive', - 'euiSelectable.searchResults', - 'euiPrettyDuration.lastDurationSeconds', - 'euiPrettyDuration.nextDurationSeconds', - 'euiPrettyDuration.lastDurationMinutes', - 'euiPrettyDuration.nextDurationMinutes', - 'euiPrettyDuration.lastDurationHours', - 'euiPrettyDuration.nextDurationHours', - 'euiPrettyDuration.lastDurationDays', - 'euiPrettyDuration.nexttDurationDays', - 'euiPrettyDuration.lastDurationWeeks', - 'euiPrettyDuration.nextDurationWeeks', - 'euiPrettyDuration.lastDurationMonths', - 'euiPrettyDuration.nextDurationMonths', - 'euiPrettyDuration.lastDurationYears', - 'euiPrettyDuration.nextDurationYears', - 'euiPrettyInterval.seconds', - 'euiPrettyInterval.minutes', - 'euiPrettyInterval.hours', - 'euiPrettyInterval.days', - 'euiPrettyInterval.weeks', - 'euiPrettyInterval.months', - 'euiPrettyInterval.years', - ]; - if (tokensToSkip.includes(token)) return; + const isDefFunction = defString.includes('}) =>'); + const isPluralizationDefFunction = + defString.includes(' === 1 ?') || defString.includes(' > 1 ?'); // Clean up typical errors from the `@elastic/eui` extraction token tool const normalizedDefString = defString @@ -114,7 +90,38 @@ describe('@elastic/eui i18n tokens', () => { .replace(/\s{2,}/g, ' ') .trim(); - expect(i18nTranslateCall[1].defaultMessage).toBe(normalizedDefString); + if (!isDefFunction) { + expect(i18nTranslateCall[1].defaultMessage).toBe(normalizedDefString); + } else { + // Certain EUI defStrings are actually functions (that currently primarily handle + // pluralization). To check EUI's pluralization against Kibana's pluralization, we + // need to eval the defString and then actually i18n.translate & compare the 2 outputs + const defFunction = eval(defString); // eslint-disable-line no-eval + const defFunctionArg = normalizedDefString.split('({ ')[1].split('})')[0]; // TODO: All EUI pluralization fns currently only pass 1 arg. If this changes in the future and 2 args are passed, we'll need to do some extra splitting by ',' + + if (isPluralizationDefFunction) { + const singularValue = { [defFunctionArg]: 1 }; + expect( + i18nTranslateActual(token, { + defaultMessage: i18nTranslateCall[1].defaultMessage, + values: singularValue, + }) + ).toEqual(defFunction(singularValue)); + + const pluralValue = { [defFunctionArg]: 2 }; + expect( + i18nTranslateActual(token, { + defaultMessage: i18nTranslateCall[1].defaultMessage, + values: pluralValue, + }) + ).toEqual(defFunction(pluralValue)); + } else { + throw new Error( + `We currently only have logic written for EUI pluralization def functions. + This is a new type of def function that will need custom logic written for it.` + ); + } + } }); test('values should match', () => { diff --git a/src/core/public/i18n/i18n_eui_mapping.tsx b/src/core/public/i18n/i18n_eui_mapping.tsx index b58780db3087d..9969f4ee23f57 100644 --- a/src/core/public/i18n/i18n_eui_mapping.tsx +++ b/src/core/public/i18n/i18n_eui_mapping.tsx @@ -1268,7 +1268,7 @@ export const getEuiContextMapping = (): EuiTokensObject => { ), 'euiSelectable.searchResults': ({ resultsLength }: EuiValues) => i18n.translate('core.euiSelectable.searchResults', { - defaultMessage: '{resultsLength, plural, one {# result} other {# results}}', + defaultMessage: '{resultsLength, plural, one {# result} other {# results}} available', values: { resultsLength }, }), 'euiSelectable.placeholderName': i18n.translate('core.euiSelectable.placeholderName', { diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 3b3bccd7ec18b..d62df68cf827d 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -91,6 +91,7 @@ export type { PublicAppInfo, PublicAppDeepLinkInfo, NavigateToAppOptions, + NavigateToUrlOptions, } from './application'; export { SimpleSavedObject } from './saved_objects'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 44224e6fcaea7..b60e26d282dc3 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -160,7 +160,7 @@ export interface ApplicationStart { deepLinkId?: string; }): string; navigateToApp(appId: string, options?: NavigateToAppOptions): Promise; - navigateToUrl(url: string): Promise; + navigateToUrl(url: string, options?: NavigateToUrlOptions): Promise; } // @public @@ -778,9 +778,16 @@ export interface NavigateToAppOptions { openInNewTab?: boolean; path?: string; replace?: boolean; + skipAppLeave?: boolean; state?: unknown; } +// @public +export interface NavigateToUrlOptions { + forceRedirect?: boolean; + skipAppLeave?: boolean; +} + // Warning: (ae-missing-release-tag) "NavType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) diff --git a/src/core/server/saved_objects/mappings/types.ts b/src/core/server/saved_objects/mappings/types.ts index e225d0ff31022..3fc088d0e82c4 100644 --- a/src/core/server/saved_objects/mappings/types.ts +++ b/src/core/server/saved_objects/mappings/types.ts @@ -107,6 +107,11 @@ export type SavedObjectsFieldMapping = estypes.MappingProperty & { * *never* use `dynamic: true`. */ dynamic?: false | 'strict'; + /** + * Some mapping types do not accept the `properties` attributes. Explicitly adding it as optional to our type + * to avoid type failures on all code using accessing them via `SavedObjectsFieldMapping.properties`. + */ + properties?: Record; }; /** @internal */ diff --git a/src/core/server/saved_objects/migrations/integration_tests/cluster_routing_allocation_disabled.test.ts b/src/core/server/saved_objects/migrations/integration_tests/cluster_routing_allocation_disabled.test.ts index 0f4522b156fe7..ea70478d6ce7b 100644 --- a/src/core/server/saved_objects/migrations/integration_tests/cluster_routing_allocation_disabled.test.ts +++ b/src/core/server/saved_objects/migrations/integration_tests/cluster_routing_allocation_disabled.test.ts @@ -113,8 +113,8 @@ describe('unsupported_cluster_routing_allocation', () => { await root.preboot(); await root.setup(); - await expect(root.start()).rejects.toMatchInlineSnapshot( - `[Error: Unable to complete saved object migrations for the [.kibana] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue. To proceed, please remove the cluster routing allocation settings with PUT /_cluster/settings {"transient": {"cluster.routing.allocation.enable": null}, "persistent": {"cluster.routing.allocation.enable": null}}]` + await expect(root.start()).rejects.toThrowError( + /Unable to complete saved object migrations for the \[\.kibana.*\] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue\. To proceed, please remove the cluster routing allocation settings with PUT \/_cluster\/settings {"transient": {"cluster\.routing\.allocation\.enable": null}, "persistent": {"cluster\.routing\.allocation\.enable": null}}/ ); await retryAsync( @@ -126,8 +126,8 @@ describe('unsupported_cluster_routing_allocation', () => { .map((str) => JSON5.parse(str)) as LogRecord[]; expect( records.find((rec) => - rec.message.startsWith( - `Unable to complete saved object migrations for the [.kibana] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue.` + /^Unable to complete saved object migrations for the \[\.kibana.*\] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue\./.test( + rec.message ) ) ).toBeDefined(); @@ -148,8 +148,8 @@ describe('unsupported_cluster_routing_allocation', () => { await root.preboot(); await root.setup(); - await expect(root.start()).rejects.toMatchInlineSnapshot( - `[Error: Unable to complete saved object migrations for the [.kibana] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue. To proceed, please remove the cluster routing allocation settings with PUT /_cluster/settings {"transient": {"cluster.routing.allocation.enable": null}, "persistent": {"cluster.routing.allocation.enable": null}}]` + await expect(root.start()).rejects.toThrowError( + /Unable to complete saved object migrations for the \[\.kibana.*\] index: The elasticsearch cluster has cluster routing allocation incorrectly set for migrations to continue\. To proceed, please remove the cluster routing allocation settings with PUT \/_cluster\/settings {"transient": {"cluster\.routing\.allocation\.enable": null}, "persistent": {"cluster\.routing\.allocation\.enable": null}}/ ); }); }); diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index c89a5fc89d2fa..7337a3809172e 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -2366,6 +2366,7 @@ export interface SavedObjectsExportTransformContext { // @public export type SavedObjectsFieldMapping = estypes.MappingProperty & { dynamic?: false | 'strict'; + properties?: Record; }; // @public (undocumented) diff --git a/src/dev/build/tasks/package_json/find_used_dependencies.ts b/src/dev/build/tasks/package_json/find_used_dependencies.ts index 6fb0c0060ecc7..e49d57c6f794f 100644 --- a/src/dev/build/tasks/package_json/find_used_dependencies.ts +++ b/src/dev/build/tasks/package_json/find_used_dependencies.ts @@ -58,7 +58,7 @@ export async function findUsedDependencies(listedPkgDependencies: any, baseDir: const listedDependencies = Object.keys(listedPkgDependencies); const filteredListedDependencies = listedDependencies.filter((entry) => { - return whiteListedModules.some((nonEntry) => entry.includes(nonEntry)); + return whiteListedModules.some((nonEntry) => entry === nonEntry); }); return filteredListedDependencies.reduce((foundUsedDeps: any, usedDep) => { diff --git a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx index 53e729466c1d2..b0fe277cebfd3 100644 --- a/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx +++ b/src/plugins/chart_expressions/expression_partition_vis/public/expression_renderers/partition_vis_renderer.tsx @@ -9,6 +9,7 @@ import React, { lazy } from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nProvider } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { ExpressionRenderDefinition } from '../../../../expressions/public'; import type { PersistedState } from '../../../../visualizations/public'; @@ -32,6 +33,12 @@ export const strings = { const LazyPartitionVisComponent = lazy(() => import('../components/partition_vis_component')); const PartitionVisComponent = withSuspense(LazyPartitionVisComponent); +const partitionVisRenderer = css({ + position: 'relative', + width: '100%', + height: '100%', +}); + export const getPartitionVisRenderer: ( deps: VisTypePieDependencies ) => ExpressionRenderDefinition = ({ theme, palettes, getStartDeps }) => ({ @@ -50,7 +57,7 @@ export const getPartitionVisRenderer: ( render( -
+
onCancel(flyout), + onClose: (flyout) => { + onCancel(flyout); + setFlyoutRef(undefined); + }, } ); + setFlyoutRef(flyoutInstance); }); initialInputPromise.then( diff --git a/src/plugins/controls/public/control_group/editor/edit_control.tsx b/src/plugins/controls/public/control_group/editor/edit_control.tsx index 5b7177a64c633..7c114350f3679 100644 --- a/src/plugins/controls/public/control_group/editor/edit_control.tsx +++ b/src/plugins/controls/public/control_group/editor/edit_control.tsx @@ -20,7 +20,7 @@ import { IEditableControlFactory, ControlInput } from '../../types'; import { controlGroupReducers } from '../state/control_group_reducers'; import { EmbeddableFactoryNotFoundError } from '../../../../embeddable/public'; import { useReduxContainerContext } from '../../../../presentation_util/public'; -import { ControlGroupContainer } from '../embeddable/control_group_container'; +import { ControlGroupContainer, setFlyoutRef } from '../embeddable/control_group_container'; export const EditControlButton = ({ embeddableId }: { embeddableId: string }) => { // Controls Services Context @@ -127,9 +127,13 @@ export const EditControlButton = ({ embeddableId }: { embeddableId: string }) => ), { outsideClickCloses: false, - onClose: (flyout) => onCancel(flyout), + onClose: (flyout) => { + setFlyoutRef(undefined); + onCancel(flyout); + }, } ); + setFlyoutRef(flyoutInstance); }; return ( diff --git a/src/plugins/controls/public/control_group/editor/edit_control_group.tsx b/src/plugins/controls/public/control_group/editor/edit_control_group.tsx index dcf955666657f..8d9f81637ef65 100644 --- a/src/plugins/controls/public/control_group/editor/edit_control_group.tsx +++ b/src/plugins/controls/public/control_group/editor/edit_control_group.tsx @@ -15,6 +15,7 @@ import { ControlGroupEditor } from './control_group_editor'; import { OverlayRef } from '../../../../../core/public'; import { pluginServices } from '../../services'; import { ControlGroupContainer } from '..'; +import { setFlyoutRef } from '../embeddable/control_group_container'; export interface EditControlGroupButtonProps { controlGroupContainer: ControlGroupContainer; @@ -60,9 +61,13 @@ export const EditControlGroup = ({ ), { outsideClickCloses: false, - onClose: () => flyoutInstance.close(), + onClose: () => { + flyoutInstance.close(); + setFlyoutRef(undefined); + }, } ); + setFlyoutRef(flyoutInstance); }; const commonButtonProps = { diff --git a/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx b/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx index 7abcfbb5af6a3..5ee41946a14aa 100644 --- a/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx +++ b/src/plugins/controls/public/control_group/embeddable/control_group_container.tsx @@ -46,11 +46,17 @@ import { Container, EmbeddableFactory } from '../../../../embeddable/public'; import { ControlEmbeddable, ControlInput, ControlOutput } from '../../types'; import { ControlGroupChainingSystems } from './control_group_chaining_system'; import { CreateControlButton, CreateControlButtonTypes } from '../editor/create_control'; +import { OverlayRef } from '../../../../../core/public'; const ControlGroupReduxWrapper = withSuspense< ReduxEmbeddableWrapperPropsWithChildren >(LazyReduxEmbeddableWrapper); +let flyoutRef: OverlayRef | undefined; +export const setFlyoutRef = (newRef: OverlayRef | undefined) => { + flyoutRef = newRef; +}; + export interface ChildEmbeddableOrderCache { IdsToOrder: { [key: string]: number }; idsInOrder: string[]; @@ -96,6 +102,11 @@ export class ControlGroupContainer extends Container< return this.lastUsedDataViewId ?? this.relevantDataViewId; }; + public closeAllFlyouts() { + flyoutRef?.close(); + flyoutRef = undefined; + } + /** * Returns a button that allows controls to be created externally using the embeddable * @param buttonType Controls the button styling @@ -367,6 +378,7 @@ export class ControlGroupContainer extends Container< public destroy() { super.destroy(); + this.closeAllFlyouts(); this.subscriptions.unsubscribe(); if (this.domNode) ReactDOM.unmountComponentAtNode(this.domNode); } diff --git a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx index e66525398b86b..23bc301f788c0 100644 --- a/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx +++ b/src/plugins/dashboard/public/application/top_nav/dashboard_top_nav.tsx @@ -210,16 +210,17 @@ export function DashboardTopNav({ [stateTransferService, data.search.session, trackUiMetric] ); - const clearAddPanel = useCallback(() => { + const closeAllFlyouts = useCallback(() => { + dashboardAppState.dashboardContainer.controlGroup?.closeAllFlyouts(); if (state.addPanelOverlay) { state.addPanelOverlay.close(); setState((s) => ({ ...s, addPanelOverlay: undefined })); } - }, [state.addPanelOverlay]); + }, [state.addPanelOverlay, dashboardAppState.dashboardContainer.controlGroup]); const onChangeViewMode = useCallback( (newMode: ViewMode) => { - clearAddPanel(); + closeAllFlyouts(); const willLoseChanges = newMode === ViewMode.VIEW && dashboardAppState.hasUnsavedChanges; if (!willLoseChanges) { @@ -231,7 +232,7 @@ export function DashboardTopNav({ dashboardAppState.resetToLastSavedState?.() ); }, - [clearAddPanel, core.overlays, dashboardAppState, dispatchDashboardStateChange] + [closeAllFlyouts, core.overlays, dashboardAppState, dispatchDashboardStateChange] ); const runSaveAs = useCallback(async () => { @@ -296,7 +297,7 @@ export function DashboardTopNav({ showCopyOnSave={lastDashboardId ? true : false} /> ); - clearAddPanel(); + closeAllFlyouts(); showSaveModal(dashboardSaveModal, core.i18n.Context); }, [ dispatchDashboardStateChange, @@ -305,7 +306,7 @@ export function DashboardTopNav({ dashboardAppState, core.i18n.Context, chrome.docTitle, - clearAddPanel, + closeAllFlyouts, kibanaVersion, timefilter, redirectTo, @@ -468,7 +469,7 @@ export function DashboardTopNav({ ]); UseUnmount(() => { - clearAddPanel(); + closeAllFlyouts(); setMounted(false); }); diff --git a/src/plugins/data/common/index.ts b/src/plugins/data/common/index.ts index a97b8025426f2..93aeb918bc53a 100644 --- a/src/plugins/data/common/index.ts +++ b/src/plugins/data/common/index.ts @@ -139,7 +139,6 @@ export { DEFAULT_ASSETS_TO_IGNORE, META_FIELDS, DATA_VIEW_SAVED_OBJECT_TYPE, - INDEX_PATTERN_SAVED_OBJECT_TYPE, isFilterable, fieldList, DataViewField, diff --git a/src/plugins/data_views/common/constants.ts b/src/plugins/data_views/common/constants.ts index 42f869908ec25..d6a9def882a1b 100644 --- a/src/plugins/data_views/common/constants.ts +++ b/src/plugins/data_views/common/constants.ts @@ -37,10 +37,4 @@ export const META_FIELDS = 'metaFields'; /** @public **/ export const DATA_VIEW_SAVED_OBJECT_TYPE = 'index-pattern'; -/** - * @deprecated Use DATA_VIEW_SAVED_OBJECT_TYPE. All index pattern interfaces were renamed. - */ - -export const INDEX_PATTERN_SAVED_OBJECT_TYPE = DATA_VIEW_SAVED_OBJECT_TYPE; - export const PLUGIN_NAME = 'DataViews'; diff --git a/src/plugins/data_views/common/index.ts b/src/plugins/data_views/common/index.ts index 954d3ed7e3590..13842b62a9d53 100644 --- a/src/plugins/data_views/common/index.ts +++ b/src/plugins/data_views/common/index.ts @@ -11,7 +11,6 @@ export { DEFAULT_ASSETS_TO_IGNORE, META_FIELDS, DATA_VIEW_SAVED_OBJECT_TYPE, - INDEX_PATTERN_SAVED_OBJECT_TYPE, } from './constants'; export type { IFieldType, IIndexPatternFieldList } from './fields'; export { diff --git a/src/plugins/discover/public/application/context/components/action_bar/action_bar.tsx b/src/plugins/discover/public/application/context/components/action_bar/action_bar.tsx index 9b7ba6345111f..07cb6029a77de 100644 --- a/src/plugins/discover/public/application/context/components/action_bar/action_bar.tsx +++ b/src/plugins/discover/public/application/context/components/action_bar/action_bar.tsx @@ -92,7 +92,6 @@ export function ActionBar({ { diff --git a/src/plugins/discover/public/application/view_alert/view_alert_route.tsx b/src/plugins/discover/public/application/view_alert/view_alert_route.tsx index 82481660d339c..2a6fa70ef0e2b 100644 --- a/src/plugins/discover/public/application/view_alert/view_alert_route.tsx +++ b/src/plugins/discover/public/application/view_alert/view_alert_route.tsx @@ -9,7 +9,7 @@ import { useEffect, useMemo } from 'react'; import { useHistory, useLocation, useParams } from 'react-router-dom'; import { sha256 } from 'js-sha256'; -import type { Alert } from '../../../../../../x-pack/plugins/alerting/common'; +import type { Rule } from '../../../../../../x-pack/plugins/alerting/common'; import { getTime, IndexPattern } from '../../../../data/common'; import type { Filter } from '../../../../data/public'; import { DiscoverAppLocatorParams } from '../../locator'; @@ -27,7 +27,7 @@ const isActualAlert = (queryParams: QueryParams): queryParams is NonNullableEntr const buildTimeRangeFilter = ( dataView: IndexPattern, - fetchedAlert: Alert, + fetchedAlert: Rule, timeFieldName: string ) => { const filter = getTime(dataView, { diff --git a/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx b/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx index b61f0c9a8720c..585da8c676417 100644 --- a/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx +++ b/src/plugins/discover/public/application/view_alert/view_alert_utils.tsx @@ -9,13 +9,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { CoreStart, ToastsStart } from 'kibana/public'; -import type { Alert } from '../../../../../../x-pack/plugins/alerting/common'; -import type { AlertTypeParams } from '../../../../../../x-pack/plugins/alerting/common'; +import type { Rule } from '../../../../../../x-pack/plugins/alerting/common'; +import type { RuleTypeParams } from '../../../../../../x-pack/plugins/alerting/common'; import { SerializedSearchSourceFields } from '../../../../data/common'; import type { DataPublicPluginStart } from '../../../../data/public'; import { MarkdownSimple, toMountPoint } from '../../../../kibana_react/public'; -export interface SearchThresholdAlertParams extends AlertTypeParams { +export interface SearchThresholdAlertParams extends RuleTypeParams { searchConfiguration: SerializedSearchSourceFields; } @@ -78,7 +78,7 @@ export const getAlertUtils = ( const fetchAlert = async (id: string) => { try { - return await core.http.get>( + return await core.http.get>( `${LEGACY_BASE_ALERT_API_PATH}/alert/${id}` ); } catch (error) { @@ -92,7 +92,7 @@ export const getAlertUtils = ( } }; - const fetchSearchSource = async (fetchedAlert: Alert) => { + const fetchSearchSource = async (fetchedAlert: Rule) => { try { return await data.search.searchSource.create(fetchedAlert.params.searchConfiguration); } catch (error) { diff --git a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.ts b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.ts index 3f98ead25ff4e..174e200a6c996 100644 --- a/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.ts +++ b/src/plugins/telemetry/server/telemetry_collection/get_data_telemetry/get_data_telemetry.ts @@ -228,6 +228,7 @@ export async function getDataTelemetry(esClient: ElasticsearchClient) { const indices = indexNames.map((name) => { const baseIndexInfo = { name, + // @ts-expect-error 'properties' does not exist on type 'MappingMatchOnlyTextProperty' isECS: !!indexMappings[name]?.mappings?.properties?.ecs?.properties?.version?.type, shipper: indexMappings[name]?.mappings?._meta?.beat, packageName: indexMappings[name]?.mappings?._meta?.package?.name, diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts index a09e92fe7dd80..c0453f470de4b 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.test.ts @@ -31,30 +31,43 @@ import { initVegaLayer, initTmsRasterLayer } from './layers'; import { mapboxgl } from '@kbn/mapbox-gl'; -jest.mock('@kbn/mapbox-gl', () => ({ - mapboxgl: { - setRTLTextPlugin: jest.fn(), - Map: jest.fn().mockImplementation(() => ({ - getLayer: () => '', - removeLayer: jest.fn(), - once: (eventName: string, handler: Function) => handler(), - remove: () => jest.fn(), - getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), - getCenter: () => ({ lat: 20, lng: 20 }), - getZoom: () => 3, - addControl: jest.fn(), - addLayer: jest.fn(), - dragRotate: { - disable: jest.fn(), +jest.mock('@kbn/mapbox-gl', () => { + const zoomTo = jest.fn(); + const setCenter = jest.fn(); + const fitBounds = jest.fn(); + return { + mapboxgl: { + mocks: { + zoomTo, + setCenter, + fitBounds, }, - touchZoomRotate: { - disableRotation: jest.fn(), - }, - })), - MapboxOptions: jest.fn(), - NavigationControl: jest.fn(), - }, -})); + setRTLTextPlugin: jest.fn(), + Map: jest.fn().mockImplementation(() => ({ + getLayer: () => '', + removeLayer: jest.fn(), + once: (eventName: string, handler: Function) => handler(), + remove: () => jest.fn(), + getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), + getCenter: () => ({ lat: 20, lng: 20 }), + getZoom: () => 3, + zoomTo, + setCenter, + fitBounds, + addControl: jest.fn(), + addLayer: jest.fn(), + dragRotate: { + disable: jest.fn(), + }, + touchZoomRotate: { + disableRotation: jest.fn(), + }, + })), + MapboxOptions: jest.fn(), + NavigationControl: jest.fn(), + }, + }; +}); jest.mock('./layers', () => ({ initVegaLayer: jest.fn(), @@ -206,5 +219,57 @@ describe('vega_map_view/view', () => { expect(mapboxgl.NavigationControl).toHaveBeenCalled(); }); + + describe('setMapView', () => { + let vegaMapView: VegaMapView; + beforeEach(async () => { + vegaMapView = await createVegaMapView(); + await vegaMapView.init(); + mapboxgl.mocks.setCenter.mockReset(); + mapboxgl.mocks.zoomTo.mockReset(); + mapboxgl.mocks.fitBounds.mockReset(); + }); + + test('should set just lat lng', async () => { + vegaMapView.setMapViewHandler(1, 2); + expect(mapboxgl.mocks.setCenter).toHaveBeenCalledWith({ lat: 1, lng: 2 }); + }); + + test('should set just lng lat via array', async () => { + vegaMapView.setMapViewHandler([1, 2]); + expect(mapboxgl.mocks.setCenter).toHaveBeenCalledWith({ lat: 2, lng: 1 }); + }); + + test('should set lat lng and zoom', async () => { + vegaMapView.setMapViewHandler(1, 2, 6); + expect(mapboxgl.mocks.setCenter).toHaveBeenCalledWith({ lat: 1, lng: 2 }); + expect(mapboxgl.mocks.zoomTo).toHaveBeenCalledWith(6); + }); + + test('should set bounds', async () => { + vegaMapView.setMapViewHandler([ + [1, 2], + [6, 7], + ]); + expect(mapboxgl.mocks.fitBounds).toHaveBeenCalledWith([ + { lat: 2, lng: 1 }, + { lat: 7, lng: 6 }, + ]); + }); + + test('should throw on invalid input', async () => { + expect(() => { + vegaMapView.setMapViewHandler(undefined); + }).toThrow(); + + expect(() => { + vegaMapView.setMapViewHandler(['a', 'b'] as unknown as [number, number]); + }).toThrow(); + + expect(() => { + vegaMapView.setMapViewHandler([1, 2, 3, 4, 5] as unknown as [number, number]); + }).toThrow(); + }); + }); }); }); diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts index fe8d85a011442..2050e0271d03f 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_map_view/view.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { Map, Style, MapboxOptions } from '@kbn/mapbox-gl'; -import { View, parse } from 'vega'; +import { View, parse, expressionFunction } from 'vega'; import { mapboxgl } from '@kbn/mapbox-gl'; @@ -45,6 +45,30 @@ async function updateVegaView(mapBoxInstance: Map, vegaView: View) { } } +type SetMapViewArgs = + | [number, number, number] + | [number, number] + | [[number, number], number] + | [[number, number]] + | [[[number, number], [number, number]]]; + +expressionFunction( + 'setMapView', + function handlerFwd( + this: { + context: { dataflow: { _kibanaView: VegaMapView; runAfter: (fn: () => void) => void } }; + }, + ...args: SetMapViewArgs + ) { + const view = this.context.dataflow; + if (!('setMapViewHandler' in view._kibanaView)) { + // not a map view, don't do anything + return; + } + view.runAfter(() => view._kibanaView.setMapViewHandler(...args)); + } +); + export class VegaMapView extends VegaBaseView { private mapBoxInstance?: Map; @@ -200,4 +224,86 @@ export class VegaMapView extends VegaBaseView { protected async onViewContainerResize() { this.mapBoxInstance?.resize(); } + + public setMapViewHandler(...args: SetMapViewArgs) { + if (!this.mapBoxInstance) { + return; + } + function throwError() { + throw new Error( + i18n.translate('visTypeVega.visualization.setMapViewErrorMessage', { + defaultMessage: + 'Unexpected setMapView() parameters. It could be called with a bounding box setMapView([[longitude1,latitude1],[longitude2,latitude2]]), or it could be the center point setMapView([longitude, latitude], optional_zoom), or it can be used as setMapView(latitude, longitude, optional_zoom)', + }) + ); + } + + function checkArray( + val: number | [number, number] | [[number, number], [number, number]] + ): [number, number] { + if ( + !Array.isArray(val) || + val.length !== 2 || + typeof val[0] !== 'number' || + typeof val[1] !== 'number' + ) { + throwError(); + } + return val as [number, number]; + } + + let lng: number | undefined; + let lat: number | undefined; + let zoom: number | undefined; + switch (args.length) { + default: + throwError(); + break; + case 1: { + const arg = args[0]; + if ( + Array.isArray(arg) && + arg.length === 2 && + Array.isArray(arg[0]) && + Array.isArray(arg[1]) + ) { + // called with a bounding box, need to reverse order + const [lng1, lat1] = checkArray(arg[0]); + const [lng2, lat2] = checkArray(arg[1]); + this.mapBoxInstance.fitBounds([ + { lat: lat1, lng: lng1 }, + { lat: lat2, lng: lng2 }, + ]); + } else { + // called with a center point and no zoom + [lng, lat] = checkArray(arg); + } + break; + } + case 2: + if (Array.isArray(args[0])) { + [lng, lat] = checkArray(args[0]); + zoom = args[1]; + } else { + [lat, lng] = args; + } + break; + case 3: + [lat, lng, zoom] = args; + break; + } + + if (lat !== undefined && lng !== undefined) { + if (typeof lat !== 'number' || typeof lng !== 'number') { + throwError(); + } + if (zoom !== undefined && typeof zoom !== 'number') { + throwError(); + } + this.mapBoxInstance.setCenter({ lat, lng }); + if (zoom !== undefined) { + this.mapBoxInstance.zoomTo(zoom); + } + } + } } diff --git a/test/functional/apps/dashboard_elements/controls/control_group_settings.ts b/test/functional/apps/dashboard_elements/controls/control_group_settings.ts index ffda165443337..3ca09bba99cea 100644 --- a/test/functional/apps/dashboard_elements/controls/control_group_settings.ts +++ b/test/functional/apps/dashboard_elements/controls/control_group_settings.ts @@ -99,5 +99,33 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardControls.deleteAllControls(); }); }); + + describe('control group settings flyout closes', async () => { + it('on save', async () => { + await dashboardControls.openControlGroupSettingsFlyout(); + await dashboard.saveDashboard('Test Control Group Settings', { + saveAsNew: false, + exitFromEditMode: false, + }); + await testSubjects.missingOrFail('control-group-settings-flyout'); + }); + + it('on view mode change', async () => { + await dashboardControls.openControlGroupSettingsFlyout(); + await dashboard.clickCancelOutOfEditMode(); + await testSubjects.missingOrFail('control-group-settings-flyout'); + }); + + it('when navigating away from dashboard', async () => { + await dashboard.switchToEditMode(); + await dashboardControls.openControlGroupSettingsFlyout(); + await dashboard.gotoDashboardLandingPage(); + await testSubjects.missingOrFail('control-group-settings-flyout'); + }); + + after(async () => { + await dashboard.loadSavedDashboard('Test Control Group Settings'); + }); + }); }); } diff --git a/test/package/roles/assert_kibana_available/tasks/main.yml b/test/package/roles/assert_kibana_available/tasks/main.yml index db3805f7ad7fb..29b82aa7b39f8 100644 --- a/test/package/roles/assert_kibana_available/tasks/main.yml +++ b/test/package/roles/assert_kibana_available/tasks/main.yml @@ -4,6 +4,6 @@ status_code: [200, 401] timeout: 120 register: result - until: result.status != 503 + until: result.status not in [503, -1] retries: 3 delay: 30 diff --git a/versions.json b/versions.json new file mode 100644 index 0000000000000..6dfe620c9fd7e --- /dev/null +++ b/versions.json @@ -0,0 +1,27 @@ +{ + "notice": "This file is not maintained outside of the main branch and should only be used for tooling.", + "versions": [ + { + "version": "8.3.0", + "branch": "main", + "currentMajor": true, + "currentMinor": true + }, + { + "version": "8.2.0", + "branch": "8.2", + "currentMajor": true, + "previousMinor": true + }, + { + "version": "8.1.3", + "branch": "8.1", + "currentMajor": true + }, + { + "version": "7.17.3", + "branch": "7.17", + "previousMajor": true + } + ] +} diff --git a/x-pack/examples/alerting_example/README.md b/x-pack/examples/alerting_example/README.md index bf963c64586d3..f9e2f6009b12f 100644 --- a/x-pack/examples/alerting_example/README.md +++ b/x-pack/examples/alerting_example/README.md @@ -1,5 +1,5 @@ ## Alerting Example -This example plugin shows you how to create a custom Alert Type, create alerts based on that type and corresponding UI for viewing the details of all the alerts within the custom plugin. +This example plugin shows you how to create a custom Rule Type, create rules based on that type and corresponding UI for viewing the details of all the rules within the custom plugin. To run this example, use the command `yarn start --run-examples`. \ No newline at end of file diff --git a/x-pack/examples/alerting_example/common/constants.ts b/x-pack/examples/alerting_example/common/constants.ts index 14342e3381531..83cb074328f42 100644 --- a/x-pack/examples/alerting_example/common/constants.ts +++ b/x-pack/examples/alerting_example/common/constants.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertTypeParams } from '../../../plugins/alerting/common'; +import { RuleTypeParams } from '../../../plugins/alerting/common'; export const ALERTING_EXAMPLE_APP_ID = 'AlertingExample'; @@ -16,7 +16,7 @@ export interface AlwaysFiringThresholds { medium?: number; large?: number; } -export interface AlwaysFiringParams extends AlertTypeParams { +export interface AlwaysFiringParams extends RuleTypeParams { instances?: number; thresholds?: AlwaysFiringThresholds; } diff --git a/x-pack/examples/alerting_example/public/alert_types/astros.tsx b/x-pack/examples/alerting_example/public/alert_types/astros.tsx index 63ffa48c94399..d7fe322a083b1 100644 --- a/x-pack/examples/alerting_example/public/alert_types/astros.tsx +++ b/x-pack/examples/alerting_example/public/alert_types/astros.tsx @@ -20,7 +20,7 @@ import { import { i18n } from '@kbn/i18n'; import { flatten } from 'lodash'; import { ALERTING_EXAMPLE_APP_ID, Craft, Operator } from '../../common/constants'; -import { SanitizedAlert } from '../../../../plugins/alerting/common'; +import { SanitizedRule } from '../../../../plugins/alerting/common'; import { PluginSetupContract as AlertingSetup } from '../../../../plugins/alerting/public'; import { RuleTypeModel } from '../../../../plugins/triggers_actions_ui/public'; @@ -28,7 +28,7 @@ export function registerNavigation(alerting: AlertingSetup) { alerting.registerNavigation( ALERTING_EXAMPLE_APP_ID, 'example.people-in-space', - (alert: SanitizedAlert) => `/astros/${alert.id}` + (rule: SanitizedRule) => `/astros/${rule.id}` ); } @@ -49,8 +49,8 @@ export function getAlertType(): RuleTypeModel { iconClass: 'globe', documentationUrl: null, ruleParamsExpression: PeopleinSpaceExpression, - validate: (alertParams: PeopleinSpaceParamsProps['ruleParams']) => { - const { outerSpaceCapacity, craft, op } = alertParams; + validate: (ruleParams: PeopleinSpaceParamsProps['ruleParams']) => { + const { outerSpaceCapacity, craft, op } = ruleParams; const validationResult = { errors: { diff --git a/x-pack/examples/alerting_example/public/alert_types/index.ts b/x-pack/examples/alerting_example/public/alert_types/index.ts index 93c59c55bf3ce..5b62fe138c018 100644 --- a/x-pack/examples/alerting_example/public/alert_types/index.ts +++ b/x-pack/examples/alerting_example/public/alert_types/index.ts @@ -7,14 +7,14 @@ import { registerNavigation as registerPeopleInSpaceNavigation } from './astros'; import { ALERTING_EXAMPLE_APP_ID } from '../../common/constants'; -import { SanitizedAlert } from '../../../../plugins/alerting/common'; +import { SanitizedRule } from '../../../../plugins/alerting/common'; import { PluginSetupContract as AlertingSetup } from '../../../../plugins/alerting/public'; export function registerNavigation(alerting: AlertingSetup) { // register default navigation alerting.registerDefaultNavigation( ALERTING_EXAMPLE_APP_ID, - (alert: SanitizedAlert) => `/rule/${alert.id}` + (rule: SanitizedRule) => `/rule/${rule.id}` ); registerPeopleInSpaceNavigation(alerting); diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index 6dde7de84aab4..c77e600df5f0e 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -224,28 +224,28 @@ This example rule type receives server and threshold as parameters. It will read ```typescript import { schema } from '@kbn/config-schema'; -import { RuleType, AlertExecutorOptions } from '../../../alerting/server'; +import { RuleType, RuleExecutorOptions } from '../../../alerting/server'; // These type names will eventually be updated to reflect the new terminology import { - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, } from '../../../alerting/common'; ... -interface MyRuleTypeParams extends AlertTypeParams { +interface MyRuleTypeParams extends RuleTypeParams { server: string; threshold: number; testSavedObjectId: string; } -interface MyRuleTypeExtractedParams extends AlertTypeParams { +interface MyRuleTypeExtractedParams extends RuleTypeParams { server: string; threshold: number; testSavedObjectRef: string; } -interface MyRuleTypeState extends AlertTypeState { +interface MyRuleTypeState extends RuleTypeState { lastChecked: Date; } @@ -306,7 +306,7 @@ const myRuleType: RuleType< params, state, rule, - }: AlertExecutorOptions< + }: RuleExecutorOptions< MyRuleTypeParams, MyRuleTypeExtractedParams, MyRuleTypeState, @@ -677,8 +677,8 @@ The signature of such a handler is: ```typescript type AlertNavigationHandler = ( - alert: SanitizedAlert, - alertType: RuleType + rule: SanitizedRule, + ruleType: RuleType ) => string; ``` @@ -692,7 +692,7 @@ The _registerNavigation_ api allows you to register a handler for a specific ale alerting.registerNavigation( 'my-application-id', 'my-application-id.my-rule-type', - (alert: SanitizedAlert) => `/my-unique-rule/${rule.id}` + (rule: SanitizedRule) => `/my-unique-rule/${rule.id}` ); ``` @@ -708,7 +708,7 @@ The _registerDefaultNavigation_ API allows you to register a handler for any rul ``` alerting.registerDefaultNavigation( 'my-application-id', - (alert: SanitizedAlert) => `/my-other-rules/${rule.id}` + (rule: SanitizedRule) => `/my-other-rules/${rule.id}` ); ``` diff --git a/x-pack/plugins/alerting/common/execution_log_types.ts b/x-pack/plugins/alerting/common/execution_log_types.ts index e5047aae9f154..df74c46ad9b43 100644 --- a/x-pack/plugins/alerting/common/execution_log_types.ts +++ b/x-pack/plugins/alerting/common/execution_log_types.ts @@ -36,7 +36,21 @@ export interface IExecutionLog { timed_out: boolean; } +export interface IExecutionErrors { + id: string; + timestamp: string; + type: string; + message: string; +} + +export interface IExecutionErrorsResult { + totalErrors: number; + errors: IExecutionErrors[]; +} + export interface IExecutionLogResult { total: number; data: IExecutionLog[]; } + +export type IExecutionLogWithErrorsResult = IExecutionLogResult & IExecutionErrorsResult; diff --git a/x-pack/plugins/alerting/common/index.ts b/x-pack/plugins/alerting/common/index.ts index 732d9061e58da..f056ad7e0e4b7 100644 --- a/x-pack/plugins/alerting/common/index.ts +++ b/x-pack/plugins/alerting/common/index.ts @@ -8,17 +8,17 @@ // TODO: https://github.com/elastic/kibana/issues/110895 /* eslint-disable @kbn/eslint/no_export_all */ -import { AlertsHealth } from './alert'; +import { AlertsHealth } from './rule'; -export * from './alert'; +export * from './rule'; export * from './rule_type'; -export * from './alert_instance'; export * from './rule_task_instance'; -export * from './alert_navigation'; +export * from './rule_navigation'; +export * from './alert_instance'; export * from './alert_summary'; export * from './builtin_action_groups'; export * from './disabled_action_groups'; -export * from './alert_notify_when_type'; +export * from './rule_notify_when_type'; export * from './parse_duration'; export * from './execution_log_types'; diff --git a/x-pack/plugins/alerting/common/alert.ts b/x-pack/plugins/alerting/common/rule.ts similarity index 72% rename from x-pack/plugins/alerting/common/alert.ts rename to x-pack/plugins/alerting/common/rule.ts index 9e48acd523d22..d6904c7164600 100644 --- a/x-pack/plugins/alerting/common/alert.ts +++ b/x-pack/plugins/alerting/common/rule.ts @@ -11,10 +11,10 @@ import { SavedObjectsResolveResponse, } from 'kibana/server'; import { RuleExecutionMetrics } from '.'; -import { AlertNotifyWhenType } from './alert_notify_when_type'; +import { RuleNotifyWhenType } from './rule_notify_when_type'; -export type AlertTypeState = Record; -export type AlertTypeParams = Record; +export type RuleTypeState = Record; +export type RuleTypeParams = Record; export interface IntervalSchedule extends SavedObjectAttributes { interval: string; @@ -22,7 +22,7 @@ export interface IntervalSchedule extends SavedObjectAttributes { // for the `typeof ThingValues[number]` types below, become string types that // only accept the values in the associated string arrays -export const AlertExecutionStatusValues = [ +export const RuleExecutionStatusValues = [ 'ok', 'active', 'error', @@ -30,9 +30,9 @@ export const AlertExecutionStatusValues = [ 'unknown', 'warning', ] as const; -export type AlertExecutionStatuses = typeof AlertExecutionStatusValues[number]; +export type RuleExecutionStatuses = typeof RuleExecutionStatusValues[number]; -export enum AlertExecutionStatusErrorReasons { +export enum RuleExecutionStatusErrorReasons { Read = 'read', Decrypt = 'decrypt', Execute = 'execute', @@ -42,38 +42,38 @@ export enum AlertExecutionStatusErrorReasons { Disabled = 'disabled', } -export enum AlertExecutionStatusWarningReasons { +export enum RuleExecutionStatusWarningReasons { MAX_EXECUTABLE_ACTIONS = 'maxExecutableActions', } -export interface AlertExecutionStatus { - status: AlertExecutionStatuses; +export interface RuleExecutionStatus { + status: RuleExecutionStatuses; numberOfTriggeredActions?: number; numberOfScheduledActions?: number; metrics?: RuleExecutionMetrics; lastExecutionDate: Date; lastDuration?: number; error?: { - reason: AlertExecutionStatusErrorReasons; + reason: RuleExecutionStatusErrorReasons; message: string; }; warning?: { - reason: AlertExecutionStatusWarningReasons; + reason: RuleExecutionStatusWarningReasons; message: string; }; } -export type AlertActionParams = SavedObjectAttributes; -export type AlertActionParam = SavedObjectAttribute; +export type RuleActionParams = SavedObjectAttributes; +export type RuleActionParam = SavedObjectAttribute; -export interface AlertAction { +export interface RuleAction { group: string; id: string; actionTypeId: string; - params: AlertActionParams; + params: RuleActionParams; } -export interface AlertAggregations { +export interface RuleAggregations { alertExecutionStatus: { [status: string]: number }; ruleEnabledStatus: { enabled: number; disabled: number }; ruleMutedStatus: { muted: number; unmuted: number }; @@ -87,15 +87,15 @@ export interface MappedParamsProperties { export type MappedParams = SavedObjectAttributes & MappedParamsProperties; -export interface Alert { +export interface Rule { id: string; enabled: boolean; name: string; tags: string[]; - alertTypeId: string; + alertTypeId: string; // this is persisted in the Rule saved object so we would need a migration to change this to ruleTypeId consumer: string; schedule: IntervalSchedule; - actions: AlertAction[]; + actions: RuleAction[]; params: Params; mapped_params?: MappedParams; scheduledTaskId?: string; @@ -106,20 +106,20 @@ export interface Alert { apiKey: string | null; apiKeyOwner: string | null; throttle: string | null; - notifyWhen: AlertNotifyWhenType | null; + notifyWhen: RuleNotifyWhenType | null; muteAll: boolean; mutedInstanceIds: string[]; - executionStatus: AlertExecutionStatus; + executionStatus: RuleExecutionStatus; monitoring?: RuleMonitoring; snoozeEndTime?: Date | null; // Remove ? when this parameter is made available in the public API } -export type SanitizedAlert = Omit, 'apiKey'>; -export type ResolvedSanitizedRule = SanitizedAlert & +export type SanitizedRule = Omit, 'apiKey'>; +export type ResolvedSanitizedRule = SanitizedRule & Omit; export type SanitizedRuleConfig = Pick< - SanitizedAlert, + SanitizedRule, | 'name' | 'tags' | 'consumer' diff --git a/x-pack/plugins/alerting/common/alert_navigation.ts b/x-pack/plugins/alerting/common/rule_navigation.ts similarity index 69% rename from x-pack/plugins/alerting/common/alert_navigation.ts rename to x-pack/plugins/alerting/common/rule_navigation.ts index 6ac21232b51a5..abc109a31c432 100644 --- a/x-pack/plugins/alerting/common/alert_navigation.ts +++ b/x-pack/plugins/alerting/common/rule_navigation.ts @@ -6,10 +6,10 @@ */ import { JsonObject } from '@kbn/utility-types'; -export interface AlertUrlNavigation { +export interface RuleUrlNavigation { path: string; } -export interface AlertStateNavigation { +export interface RuleStateNavigation { state: JsonObject; } -export type AlertNavigation = AlertUrlNavigation | AlertStateNavigation; +export type RuleNavigation = RuleUrlNavigation | RuleStateNavigation; diff --git a/x-pack/plugins/alerting/common/alert_notify_when_type.test.ts b/x-pack/plugins/alerting/common/rule_notify_when_type.test.ts similarity index 83% rename from x-pack/plugins/alerting/common/alert_notify_when_type.test.ts rename to x-pack/plugins/alerting/common/rule_notify_when_type.test.ts index 3bfaf0ea7cc7e..dca2296aaa7e5 100644 --- a/x-pack/plugins/alerting/common/alert_notify_when_type.test.ts +++ b/x-pack/plugins/alerting/common/rule_notify_when_type.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { validateNotifyWhenType } from './alert_notify_when_type'; +import { validateNotifyWhenType } from './rule_notify_when_type'; test('validates valid notify when type', () => { expect(validateNotifyWhenType('onActionGroupChange')).toBeUndefined(); @@ -14,6 +14,6 @@ test('validates valid notify when type', () => { }); test('returns error string if input is not valid notify when type', () => { expect(validateNotifyWhenType('randomString')).toEqual( - `string is not a valid AlertNotifyWhenType: randomString` + `string is not a valid RuleNotifyWhenType: randomString` ); }); diff --git a/x-pack/plugins/alerting/common/alert_notify_when_type.ts b/x-pack/plugins/alerting/common/rule_notify_when_type.ts similarity index 61% rename from x-pack/plugins/alerting/common/alert_notify_when_type.ts rename to x-pack/plugins/alerting/common/rule_notify_when_type.ts index fe7ca715e2bfb..700c87acdbdbb 100644 --- a/x-pack/plugins/alerting/common/alert_notify_when_type.ts +++ b/x-pack/plugins/alerting/common/rule_notify_when_type.ts @@ -5,16 +5,16 @@ * 2.0. */ -const AlertNotifyWhenTypeValues = [ +const RuleNotifyWhenTypeValues = [ 'onActionGroupChange', 'onActiveAlert', 'onThrottleInterval', ] as const; -export type AlertNotifyWhenType = typeof AlertNotifyWhenTypeValues[number]; +export type RuleNotifyWhenType = typeof RuleNotifyWhenTypeValues[number]; export function validateNotifyWhenType(notifyWhen: string) { - if (AlertNotifyWhenTypeValues.includes(notifyWhen as AlertNotifyWhenType)) { + if (RuleNotifyWhenTypeValues.includes(notifyWhen as RuleNotifyWhenType)) { return; } - return `string is not a valid AlertNotifyWhenType: ${notifyWhen}`; + return `string is not a valid RuleNotifyWhenType: ${notifyWhen}`; } diff --git a/x-pack/plugins/alerting/common/rule_task_instance.ts b/x-pack/plugins/alerting/common/rule_task_instance.ts index 54483babdfdd3..01d97efd57b15 100644 --- a/x-pack/plugins/alerting/common/rule_task_instance.ts +++ b/x-pack/plugins/alerting/common/rule_task_instance.ts @@ -8,7 +8,7 @@ import * as t from 'io-ts'; import { rawAlertInstance } from './alert_instance'; import { DateFromString } from './date_from_string'; -import { IntervalSchedule, RuleMonitoring } from './alert'; +import { IntervalSchedule, RuleMonitoring } from './rule'; export const ruleStateSchema = t.partial({ alertTypeState: t.record(t.string, t.unknown), diff --git a/x-pack/plugins/alerting/public/alert_api.test.ts b/x-pack/plugins/alerting/public/alert_api.test.ts index 8e6331a29c1c5..eae4bc72a02e8 100644 --- a/x-pack/plugins/alerting/public/alert_api.test.ts +++ b/x-pack/plugins/alerting/public/alert_api.test.ts @@ -5,19 +5,19 @@ * 2.0. */ -import { Alert, RuleType } from '../common'; +import { Rule, RuleType } from '../common'; import { httpServiceMock } from '../../../../src/core/public/mocks'; -import { loadAlert, loadAlertType, loadAlertTypes } from './alert_api'; +import { loadRule, loadRuleType, loadRuleTypes } from './alert_api'; const http = httpServiceMock.createStartContract(); beforeEach(() => jest.resetAllMocks()); -describe('loadAlertTypes', () => { - test('should call get alert types API', async () => { +describe('loadRuleTypes', () => { + test('should call get rule types API', async () => { http.get.mockResolvedValueOnce([getApiRuleType()]); - const result = await loadAlertTypes({ http }); + const result = await loadRuleTypes({ http }); expect(result).toMatchInlineSnapshot(` Array [ Object { @@ -77,22 +77,22 @@ describe('loadAlertTypes', () => { }); }); -describe('loadAlertType', () => { - test('should call get alert types API', async () => { +describe('loadRuleType', () => { + test('should call get rule types API', async () => { const ruleType = getApiRuleType(); http.get.mockResolvedValueOnce([ruleType]); - const result = await loadAlertType({ http, id: ruleType.id }); + const result = await loadRuleType({ http, id: ruleType.id }); expect(result).toEqual(getRuleType()); }); }); -describe('loadAlert', () => { +describe('loadRule', () => { test('should call get API with base parameters', async () => { const apiRule = getApiRule(); http.get.mockResolvedValueOnce(apiRule); - const res = await loadAlert({ http, alertId: apiRule.id }); + const res = await loadRule({ http, ruleId: apiRule.id }); expect(res).toEqual(getRule()); const fixedDate = new Date('2021-12-11T16:59:50.152Z'); @@ -292,7 +292,7 @@ function getApiRule() { }; } -function getRule(): Alert<{ x: number }> { +function getRule(): Rule<{ x: number }> { return { id: '3d534c70-582b-11ec-8995-2b1578a3bc5d', notifyWhen: 'onActiveAlert', diff --git a/x-pack/plugins/alerting/public/alert_api.ts b/x-pack/plugins/alerting/public/alert_api.ts index e64a236d5302b..93ea8c79bdd34 100644 --- a/x-pack/plugins/alerting/public/alert_api.ts +++ b/x-pack/plugins/alerting/public/alert_api.ts @@ -7,35 +7,35 @@ import { HttpSetup } from 'kibana/public'; import { BASE_ALERTING_API_PATH, INTERNAL_BASE_ALERTING_API_PATH } from '../common'; -import type { Alert, RuleType } from '../common'; +import type { Rule, RuleType } from '../common'; import { AsApiContract } from '../../actions/common'; -import { transformAlert, transformRuleType, ApiAlert } from './lib/common_transformations'; +import { transformRule, transformRuleType, ApiRule } from './lib/common_transformations'; -export async function loadAlertTypes({ http }: { http: HttpSetup }): Promise { +export async function loadRuleTypes({ http }: { http: HttpSetup }): Promise { const res = await http.get>>( `${BASE_ALERTING_API_PATH}/rule_types` ); return res.map((ruleType) => transformRuleType(ruleType)); } -export async function loadAlertType({ +export async function loadRuleType({ http, id, }: { http: HttpSetup; id: RuleType['id']; }): Promise { - const ruleTypes = await loadAlertTypes({ http }); + const ruleTypes = await loadRuleTypes({ http }); return ruleTypes.find((type) => type.id === id); } -export async function loadAlert({ +export async function loadRule({ http, - alertId, + ruleId, }: { http: HttpSetup; - alertId: string; -}): Promise { - const res = await http.get(`${INTERNAL_BASE_ALERTING_API_PATH}/rule/${alertId}`); - return transformAlert(res); + ruleId: string; +}): Promise { + const res = await http.get(`${INTERNAL_BASE_ALERTING_API_PATH}/rule/${ruleId}`); + return transformRule(res); } diff --git a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts index 0d07b708825cb..204076151614b 100644 --- a/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts +++ b/x-pack/plugins/alerting/public/alert_navigation_registry/alert_navigation_registry.test.ts @@ -6,12 +6,12 @@ */ import { AlertNavigationRegistry } from './alert_navigation_registry'; -import { RuleType, RecoveredActionGroup, SanitizedAlert } from '../../common'; +import { RuleType, RecoveredActionGroup, SanitizedRule } from '../../common'; import uuid from 'uuid'; beforeEach(() => jest.resetAllMocks()); -const mockAlertType = (id: string): RuleType => ({ +const mockRuleType = (id: string): RuleType => ({ id, name: id, actionGroups: [], @@ -30,33 +30,33 @@ const mockAlertType = (id: string): RuleType => ({ }); describe('AlertNavigationRegistry', () => { - function handler(alert: SanitizedAlert) { + function handler(rule: SanitizedRule) { return {}; } describe('has()', () => { test('returns false for unregistered consumer handlers', () => { const registry = new AlertNavigationRegistry(); - expect(registry.has('siem', mockAlertType(uuid.v4()))).toEqual(false); + expect(registry.has('siem', mockRuleType(uuid.v4()))).toEqual(false); }); - test('returns false for unregistered alert types handlers', () => { + test('returns false for unregistered rule types handlers', () => { const registry = new AlertNavigationRegistry(); - expect(registry.has('siem', mockAlertType('index_threshold'))).toEqual(false); + expect(registry.has('siem', mockRuleType('index_threshold'))).toEqual(false); }); - test('returns true for registered consumer & alert types handlers', () => { + test('returns true for registered consumer & rule types handlers', () => { const registry = new AlertNavigationRegistry(); - const alertType = mockAlertType('index_threshold'); - registry.register('siem', alertType.id, handler); - expect(registry.has('siem', alertType)).toEqual(true); + const ruleType = mockRuleType('index_threshold'); + registry.register('siem', ruleType.id, handler); + expect(registry.has('siem', ruleType)).toEqual(true); }); test('returns true for registered consumer with default handler', () => { const registry = new AlertNavigationRegistry(); - const alertType = mockAlertType('index_threshold'); + const ruleType = mockRuleType('index_threshold'); registry.registerDefault('siem', handler); - expect(registry.has('siem', alertType)).toEqual(true); + expect(registry.has('siem', ruleType)).toEqual(true); }); }); @@ -75,42 +75,42 @@ describe('AlertNavigationRegistry', () => { }); describe('register()', () => { - test('registers a handler by consumer & Alert Type', () => { + test('registers a handler by consumer & Rule Type', () => { const registry = new AlertNavigationRegistry(); - const alertType = mockAlertType('index_threshold'); - registry.register('siem', alertType.id, handler); - expect(registry.has('siem', alertType)).toEqual(true); + const ruleType = mockRuleType('index_threshold'); + registry.register('siem', ruleType.id, handler); + expect(registry.has('siem', ruleType)).toEqual(true); }); test('allows registeration of multiple handlers for the same consumer', () => { const registry = new AlertNavigationRegistry(); - const indexThresholdAlertType = mockAlertType('index_threshold'); + const indexThresholdAlertType = mockRuleType('index_threshold'); registry.register('siem', indexThresholdAlertType.id, handler); expect(registry.has('siem', indexThresholdAlertType)).toEqual(true); - const geoAlertType = mockAlertType('geogrid'); - registry.register('siem', geoAlertType.id, handler); - expect(registry.has('siem', geoAlertType)).toEqual(true); + const geoRuleType = mockRuleType('geogrid'); + registry.register('siem', geoRuleType.id, handler); + expect(registry.has('siem', geoRuleType)).toEqual(true); }); - test('allows registeration of multiple handlers for the same Alert Type', () => { + test('allows registeration of multiple handlers for the same Rule Type', () => { const registry = new AlertNavigationRegistry(); - const indexThresholdAlertType = mockAlertType('geogrid'); - registry.register('siem', indexThresholdAlertType.id, handler); - expect(registry.has('siem', indexThresholdAlertType)).toEqual(true); + const indexThresholdRuleType = mockRuleType('geogrid'); + registry.register('siem', indexThresholdRuleType.id, handler); + expect(registry.has('siem', indexThresholdRuleType)).toEqual(true); - registry.register('apm', indexThresholdAlertType.id, handler); - expect(registry.has('apm', indexThresholdAlertType)).toEqual(true); + registry.register('apm', indexThresholdRuleType.id, handler); + expect(registry.has('apm', indexThresholdRuleType)).toEqual(true); }); test('throws if an existing handler is registered', () => { const registry = new AlertNavigationRegistry(); - const alertType = mockAlertType('index_threshold'); - registry.register('siem', alertType.id, handler); + const ruleType = mockRuleType('index_threshold'); + registry.register('siem', ruleType.id, handler); expect(() => { - registry.register('siem', alertType.id, handler); + registry.register('siem', ruleType.id, handler); }).toThrowErrorMatchingInlineSnapshot( `"Navigation for Alert type \\"index_threshold\\" within \\"siem\\" is already registered."` ); @@ -130,9 +130,9 @@ describe('AlertNavigationRegistry', () => { registry.registerDefault('siem', handler); expect(registry.hasDefaultHandler('siem')).toEqual(true); - const geoAlertType = mockAlertType('geogrid'); - registry.register('siem', geoAlertType.id, handler); - expect(registry.has('siem', geoAlertType)).toEqual(true); + const geoRuleType = mockRuleType('geogrid'); + registry.register('siem', geoRuleType.id, handler); + expect(registry.has('siem', geoRuleType)).toEqual(true); }); test('throws if an existing handler is registered', () => { @@ -147,47 +147,47 @@ describe('AlertNavigationRegistry', () => { }); describe('get()', () => { - test('returns registered handlers by consumer & Alert Type', () => { + test('returns registered handlers by consumer & Rule Type', () => { const registry = new AlertNavigationRegistry(); - function indexThresholdHandler(alert: SanitizedAlert) { + function indexThresholdHandler(rule: SanitizedRule) { return {}; } - const indexThresholdAlertType = mockAlertType('indexThreshold'); - registry.register('siem', indexThresholdAlertType.id, indexThresholdHandler); - expect(registry.get('siem', indexThresholdAlertType)).toEqual(indexThresholdHandler); + const indexThresholdRuleType = mockRuleType('indexThreshold'); + registry.register('siem', indexThresholdRuleType.id, indexThresholdHandler); + expect(registry.get('siem', indexThresholdRuleType)).toEqual(indexThresholdHandler); }); - test('returns default handlers by consumer when there is no handler for requested alert type', () => { + test('returns default handlers by consumer when there is no handler for requested rule type', () => { const registry = new AlertNavigationRegistry(); - function defaultHandler(alert: SanitizedAlert) { + function defaultHandler(rule: SanitizedRule) { return {}; } registry.registerDefault('siem', defaultHandler); - expect(registry.get('siem', mockAlertType('geogrid'))).toEqual(defaultHandler); + expect(registry.get('siem', mockRuleType('geogrid'))).toEqual(defaultHandler); }); - test('returns default handlers by consumer when there are other alert type handler', () => { + test('returns default handlers by consumer when there are other rule type handler', () => { const registry = new AlertNavigationRegistry(); - registry.register('siem', mockAlertType('indexThreshold').id, () => ({})); + registry.register('siem', mockRuleType('indexThreshold').id, () => ({})); - function defaultHandler(alert: SanitizedAlert) { + function defaultHandler(rule: SanitizedRule) { return {}; } registry.registerDefault('siem', defaultHandler); - expect(registry.get('siem', mockAlertType('geogrid'))).toEqual(defaultHandler); + expect(registry.get('siem', mockRuleType('geogrid'))).toEqual(defaultHandler); }); test('throws if a handler isnt registered', () => { const registry = new AlertNavigationRegistry(); - const alertType = mockAlertType('index_threshold'); + const ruleType = mockRuleType('index_threshold'); - expect(() => registry.get('siem', alertType)).toThrowErrorMatchingInlineSnapshot( + expect(() => registry.get('siem', ruleType)).toThrowErrorMatchingInlineSnapshot( `"Navigation for Alert type \\"index_threshold\\" within \\"siem\\" is not registered."` ); }); diff --git a/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts b/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts index ea36d0edd1366..3c7b7aa3c8c06 100644 --- a/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts +++ b/x-pack/plugins/alerting/public/alert_navigation_registry/types.ts @@ -6,7 +6,7 @@ */ import { JsonObject } from '@kbn/utility-types'; -import { SanitizedAlert } from '../../common'; +import { SanitizedRule } from '../../common'; /** * Returns information that can be used to navigate to a specific page to view the given rule. @@ -17,4 +17,4 @@ import { SanitizedAlert } from '../../common'; * originally registered to {@link PluginSetupContract.registerNavigation}. * */ -export type AlertNavigationHandler = (alert: SanitizedAlert) => JsonObject | string; +export type AlertNavigationHandler = (rule: SanitizedRule) => JsonObject | string; diff --git a/x-pack/plugins/alerting/public/lib/common_transformations.test.ts b/x-pack/plugins/alerting/public/lib/common_transformations.test.ts index 00d830bcf7611..51d24538b449e 100644 --- a/x-pack/plugins/alerting/public/lib/common_transformations.test.ts +++ b/x-pack/plugins/alerting/public/lib/common_transformations.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ApiAlert, transformAlert } from './common_transformations'; -import { AlertExecutionStatusErrorReasons } from '../../common'; +import { ApiRule, transformRule } from './common_transformations'; +import { RuleExecutionStatusErrorReasons } from '../../common'; beforeEach(() => jest.resetAllMocks()); @@ -16,8 +16,8 @@ const dateUpdated = new Date(dateFixed - 1000); const dateExecuted = new Date(dateFixed); describe('common_transformations', () => { - test('transformAlert() with all optional fields', () => { - const apiAlert: ApiAlert = { + test('transformRule() with all optional fields', () => { + const apiRule: ApiRule = { id: 'some-id', name: 'some-name', enabled: true, @@ -50,12 +50,12 @@ describe('common_transformations', () => { last_duration: 42, status: 'error', error: { - reason: AlertExecutionStatusErrorReasons.Unknown, + reason: RuleExecutionStatusErrorReasons.Unknown, message: 'this is just a test', }, }, }; - expect(transformAlert(apiAlert)).toMatchInlineSnapshot(` + expect(transformRule(apiRule)).toMatchInlineSnapshot(` Object { "actions": Array [ Object { @@ -120,8 +120,8 @@ describe('common_transformations', () => { `); }); - test('transformAlert() with no optional fields', () => { - const apiAlert: ApiAlert = { + test('transformRule() with no optional fields', () => { + const apiRule: ApiRule = { id: 'some-id', name: 'some-name', enabled: true, @@ -153,7 +153,7 @@ describe('common_transformations', () => { status: 'error', }, }; - expect(transformAlert(apiAlert)).toMatchInlineSnapshot(` + expect(transformRule(apiRule)).toMatchInlineSnapshot(` Object { "actions": Array [ Object { diff --git a/x-pack/plugins/alerting/public/lib/common_transformations.ts b/x-pack/plugins/alerting/public/lib/common_transformations.ts index 4d2d0e3387082..8f1f0c5c72d84 100644 --- a/x-pack/plugins/alerting/public/lib/common_transformations.ts +++ b/x-pack/plugins/alerting/public/lib/common_transformations.ts @@ -4,21 +4,21 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { AlertExecutionStatus, Alert, AlertAction, RuleType } from '../../common'; +import { RuleExecutionStatus, Rule, RuleAction, RuleType } from '../../common'; import { AsApiContract } from '../../../actions/common'; -function transformAction(input: AsApiContract): AlertAction { +function transformAction(input: AsApiContract): RuleAction { const { connector_type_id: actionTypeId, ...rest } = input; return { actionTypeId, ...rest }; } // AsApiContract does not deal with object properties that are dates - the // API version needs to be a string, and the non-API version needs to be a Date -type ApiAlertExecutionStatus = Omit, 'last_execution_date'> & { +type ApiRuleExecutionStatus = Omit, 'last_execution_date'> & { last_execution_date: string; }; -function transformExecutionStatus(input: ApiAlertExecutionStatus): AlertExecutionStatus { +function transformExecutionStatus(input: ApiRuleExecutionStatus): RuleExecutionStatus { const { last_execution_date: lastExecutionDate, last_duration: lastDuration, ...rest } = input; return { lastExecutionDate: new Date(lastExecutionDate), @@ -29,8 +29,8 @@ function transformExecutionStatus(input: ApiAlertExecutionStatus): AlertExecutio // AsApiContract does not deal with object properties that also // need snake -> camel conversion, Dates, are renamed, etc, so we do by hand -export type ApiAlert = Omit< - AsApiContract, +export type ApiRule = Omit< + AsApiContract, | 'execution_status' | 'actions' | 'created_at' @@ -38,15 +38,15 @@ export type ApiAlert = Omit< | 'alert_type_id' | 'muted_instance_ids' > & { - execution_status: ApiAlertExecutionStatus; - actions: Array>; + execution_status: ApiRuleExecutionStatus; + actions: Array>; created_at: string; updated_at: string; rule_type_id: string; muted_alert_ids: string[]; }; -export function transformAlert(input: ApiAlert): Alert { +export function transformRule(input: ApiRule): Rule { const { rule_type_id: alertTypeId, created_by: createdBy, diff --git a/x-pack/plugins/alerting/public/plugin.ts b/x-pack/plugins/alerting/public/plugin.ts index 71fb0c7fe32b2..e1d683d74cc9f 100644 --- a/x-pack/plugins/alerting/public/plugin.ts +++ b/x-pack/plugins/alerting/public/plugin.ts @@ -8,8 +8,8 @@ import { CoreSetup, Plugin, CoreStart } from 'src/core/public'; import { AlertNavigationRegistry, AlertNavigationHandler } from './alert_navigation_registry'; -import { loadAlert, loadAlertType } from './alert_api'; -import { Alert, AlertNavigation } from '../common'; +import { loadRule, loadRuleType } from './alert_api'; +import { Rule, RuleNavigation } from '../common'; export interface PluginSetupContract { /** @@ -18,7 +18,7 @@ export interface PluginSetupContract { * anything with this information, but it can be used by other plugins via the `getNavigation` functionality. Currently * the trigger_actions_ui plugin uses it to expose the link from the generic rule details view in Stack Management. * - * @param applicationId The application id that the user should be navigated to, to view a particular alert in a custom way. + * @param applicationId The application id that the user should be navigated to, to view a particular rule in a custom way. * @param ruleType The rule type that has been registered with Alerting.Server.PluginSetupContract.registerType. If * no such rule with that id exists, a warning is output to the console log. It used to throw an error, but that was temporarily moved * because it was causing flaky test failures with https://github.com/elastic/kibana/issues/59229 and needs to be @@ -39,14 +39,14 @@ export interface PluginSetupContract { * anything with this information, but it can be used by other plugins via the `getNavigation` functionality. Currently * the trigger_actions_ui plugin uses it to expose the link from the generic rule details view in Stack Management. * - * @param applicationId The application id that the user should be navigated to, to view a particular alert in a custom way. + * @param applicationId The application id that the user should be navigated to, to view a particular rule in a custom way. * @param handler The navigation handler should return either a relative URL, or a state object. This information can be used, * in conjunction with the consumer id, to navigate the user to a custom URL to view a rule's details. */ registerDefaultNavigation: (applicationId: string, handler: AlertNavigationHandler) => void; } export interface PluginStartContract { - getNavigation: (alertId: Alert['id']) => Promise; + getNavigation: (ruleId: Rule['id']) => Promise; } export class AlertingPublicPlugin implements Plugin { @@ -75,21 +75,21 @@ export class AlertingPublicPlugin implements Plugin { - const alert = await loadAlert({ http: core.http, alertId }); - const alertType = await loadAlertType({ http: core.http, id: alert.alertTypeId }); + getNavigation: async (ruleId: Rule['id']) => { + const rule = await loadRule({ http: core.http, ruleId }); + const ruleType = await loadRuleType({ http: core.http, id: rule.alertTypeId }); - if (!alertType) { + if (!ruleType) { // eslint-disable-next-line no-console console.log( - `Unable to get navigation for alert type "${alert.alertTypeId}" because it is not registered on the server side.` + `Unable to get navigation for rule type "${rule.alertTypeId}" because it is not registered on the server side.` ); return; } - if (this.alertNavigationRegistry!.has(alert.consumer, alertType)) { - const navigationHandler = this.alertNavigationRegistry!.get(alert.consumer, alertType); - const state = navigationHandler(alert); + if (this.alertNavigationRegistry!.has(rule.consumer, ruleType)) { + const navigationHandler = this.alertNavigationRegistry!.get(rule.consumer, ruleType); + const state = navigationHandler(rule); return typeof state === 'string' ? { path: state } : { state }; } }, 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 c31a71138248b..19d528d44e54f 100644 --- a/x-pack/plugins/alerting/server/health/get_health.test.ts +++ b/x-pack/plugins/alerting/server/health/get_health.test.ts @@ -9,13 +9,13 @@ import { savedObjectsRepositoryMock, savedObjectsServiceMock, } from '../../../../../src/core/server/mocks'; -import { AlertExecutionStatusErrorReasons, HealthStatus } from '../types'; +import { RuleExecutionStatusErrorReasons, HealthStatus } from '../types'; import { getAlertingHealthStatus, getHealth } from './get_health'; const savedObjectsRepository = savedObjectsRepositoryMock.create(); describe('getHealth()', () => { - test('return true if some of alerts has a decryption error', async () => { + test('return true if some rules has a decryption error', async () => { const lastExecutionDateError = new Date().toISOString(); const lastExecutionDate = new Date().toISOString(); savedObjectsRepository.find.mockResolvedValueOnce({ @@ -46,7 +46,7 @@ describe('getHealth()', () => { status: 'error', lastExecutionDate: lastExecutionDateError, error: { - reason: AlertExecutionStatusErrorReasons.Decrypt, + reason: RuleExecutionStatusErrorReasons.Decrypt, message: 'Failed decrypt', }, }, @@ -120,7 +120,7 @@ describe('getHealth()', () => { expect(savedObjectsRepository.find).toHaveBeenCalledTimes(4); }); - test('return false if no alerts with a decryption error', async () => { + test('return false if no rules with a decryption error', async () => { const lastExecutionDateError = new Date().toISOString(); const lastExecutionDate = new Date().toISOString(); savedObjectsRepository.find.mockResolvedValueOnce({ @@ -158,7 +158,7 @@ describe('getHealth()', () => { status: 'error', lastExecutionDate: lastExecutionDateError, error: { - reason: AlertExecutionStatusErrorReasons.Execute, + reason: RuleExecutionStatusErrorReasons.Execute, message: 'Failed', }, }, @@ -226,7 +226,7 @@ describe('getHealth()', () => { }); describe('getAlertingHealthStatus()', () => { - test('return the proper framework state if some of alerts has a decryption error', async () => { + test('return the proper framework state if some rules has a decryption error', async () => { const savedObjects = savedObjectsServiceMock.createStartContract(); const lastExecutionDateError = new Date().toISOString(); savedObjectsRepository.find.mockResolvedValueOnce({ @@ -257,7 +257,7 @@ describe('getAlertingHealthStatus()', () => { status: 'error', lastExecutionDate: lastExecutionDateError, error: { - reason: AlertExecutionStatusErrorReasons.Decrypt, + reason: RuleExecutionStatusErrorReasons.Decrypt, message: 'Failed decrypt', }, }, diff --git a/x-pack/plugins/alerting/server/health/get_health.ts b/x-pack/plugins/alerting/server/health/get_health.ts index 09a5922576192..2bf554894917d 100644 --- a/x-pack/plugins/alerting/server/health/get_health.ts +++ b/x-pack/plugins/alerting/server/health/get_health.ts @@ -6,7 +6,7 @@ */ import { ISavedObjectsRepository, SavedObjectsServiceStart } from 'src/core/server'; -import { AlertsHealth, HealthStatus, RawRule, AlertExecutionStatusErrorReasons } from '../types'; +import { AlertsHealth, HealthStatus, RawRule, RuleExecutionStatusErrorReasons } from '../types'; export const getHealth = async ( internalSavedObjectsRepository: ISavedObjectsRepository @@ -27,7 +27,7 @@ export const getHealth = async ( }; const { saved_objects: decryptErrorData } = await internalSavedObjectsRepository.find({ - filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Decrypt}`, + filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Decrypt}`, fields: ['executionStatus'], type: 'alert', sortField: 'executionStatus.lastExecutionDate', @@ -45,7 +45,7 @@ export const getHealth = async ( } const { saved_objects: executeErrorData } = await internalSavedObjectsRepository.find({ - filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Execute}`, + filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Execute}`, fields: ['executionStatus'], type: 'alert', sortField: 'executionStatus.lastExecutionDate', @@ -63,7 +63,7 @@ export const getHealth = async ( } const { saved_objects: readErrorData } = await internalSavedObjectsRepository.find({ - filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${AlertExecutionStatusErrorReasons.Read}`, + filter: `alert.attributes.executionStatus.status:error and alert.attributes.executionStatus.error.reason:${RuleExecutionStatusErrorReasons.Read}`, fields: ['executionStatus'], type: 'alert', sortField: 'executionStatus.lastExecutionDate', diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index b44df6c3d1c86..f73fb7f964b25 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -18,12 +18,12 @@ export type { ActionGroup, ActionGroupIdsOf, AlertingPlugin, - AlertExecutorOptions, - AlertActionParams, - AlertServices, - AlertTypeState, - AlertTypeParams, - PartialAlert, + RuleExecutorOptions, + RuleExecutorServices, + RuleActionParams, + RuleTypeState, + RuleTypeParams, + PartialRule, AlertInstanceState, AlertInstanceContext, AlertingApiRequestHandlerContext, diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts index 6290d5d213046..b0a46807af5c1 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.test.ts @@ -6,7 +6,7 @@ */ import { random, mean } from 'lodash'; -import { SanitizedAlert, AlertSummary } from '../types'; +import { SanitizedRule, AlertSummary } from '../types'; import { IValidatedEvent } from '../../../event_log/server'; import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER, LEGACY_EVENT_LOG_ACTIONS } from '../plugin'; import { alertSummaryFromEventLog } from './alert_summary_from_event_log'; @@ -716,11 +716,11 @@ export class EventsFactory { } } -function createRule(overrides: Partial): SanitizedAlert<{ bar: boolean }> { +function createRule(overrides: Partial): SanitizedRule<{ bar: boolean }> { return { ...BaseRule, ...overrides }; } -const BaseRule: SanitizedAlert<{ bar: boolean }> = { +const BaseRule: SanitizedRule<{ bar: boolean }> = { id: 'rule-123', alertTypeId: '123', schedule: { interval: '10s' }, diff --git a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts index 9a40c4ebf1940..e42a135b3de04 100644 --- a/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts +++ b/x-pack/plugins/alerting/server/lib/alert_summary_from_event_log.ts @@ -6,14 +6,14 @@ */ import { mean } from 'lodash'; -import { SanitizedAlert, AlertSummary, AlertStatus } from '../types'; +import { SanitizedRule, AlertSummary, AlertStatus } from '../types'; import { IEvent } from '../../../event_log/server'; import { EVENT_LOG_ACTIONS, EVENT_LOG_PROVIDER, LEGACY_EVENT_LOG_ACTIONS } from '../plugin'; const Millis2Nanos = 1000 * 1000; export interface AlertSummaryFromEventLogParams { - rule: SanitizedAlert<{ bar: boolean }>; + rule: SanitizedRule<{ bar: boolean }>; events: IEvent[]; executionEvents: IEvent[]; dateStart: string; diff --git a/x-pack/plugins/alerting/server/lib/error_with_reason.test.ts b/x-pack/plugins/alerting/server/lib/error_with_reason.test.ts index 0316db497124a..2370e2d6fef20 100644 --- a/x-pack/plugins/alerting/server/lib/error_with_reason.test.ts +++ b/x-pack/plugins/alerting/server/lib/error_with_reason.test.ts @@ -6,21 +6,21 @@ */ import { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason'; -import { AlertExecutionStatusErrorReasons } from '../types'; +import { RuleExecutionStatusErrorReasons } from '../types'; describe('ErrorWithReason', () => { const plainError = new Error('well, actually'); - const errorWithReason = new ErrorWithReason(AlertExecutionStatusErrorReasons.Decrypt, plainError); + const errorWithReason = new ErrorWithReason(RuleExecutionStatusErrorReasons.Decrypt, plainError); test('ErrorWithReason class', () => { expect(errorWithReason.message).toBe(plainError.message); expect(errorWithReason.error).toBe(plainError); - expect(errorWithReason.reason).toBe(AlertExecutionStatusErrorReasons.Decrypt); + expect(errorWithReason.reason).toBe(RuleExecutionStatusErrorReasons.Decrypt); }); test('getReasonFromError()', () => { expect(getReasonFromError(plainError)).toBe('unknown'); - expect(getReasonFromError(errorWithReason)).toBe(AlertExecutionStatusErrorReasons.Decrypt); + expect(getReasonFromError(errorWithReason)).toBe(RuleExecutionStatusErrorReasons.Decrypt); }); test('isErrorWithReason()', () => { diff --git a/x-pack/plugins/alerting/server/lib/error_with_reason.ts b/x-pack/plugins/alerting/server/lib/error_with_reason.ts index 018694cb32c46..4c474d39426e3 100644 --- a/x-pack/plugins/alerting/server/lib/error_with_reason.ts +++ b/x-pack/plugins/alerting/server/lib/error_with_reason.ts @@ -5,24 +5,24 @@ * 2.0. */ -import { AlertExecutionStatusErrorReasons } from '../types'; +import { RuleExecutionStatusErrorReasons } from '../types'; export class ErrorWithReason extends Error { - public readonly reason: AlertExecutionStatusErrorReasons; + public readonly reason: RuleExecutionStatusErrorReasons; public readonly error: Error; - constructor(reason: AlertExecutionStatusErrorReasons, error: Error) { + constructor(reason: RuleExecutionStatusErrorReasons, error: Error) { super(error.message); this.error = error; this.reason = reason; } } -export function getReasonFromError(error: Error): AlertExecutionStatusErrorReasons { +export function getReasonFromError(error: Error): RuleExecutionStatusErrorReasons { if (isErrorWithReason(error)) { return error.reason; } - return AlertExecutionStatusErrorReasons.Unknown; + return RuleExecutionStatusErrorReasons.Unknown; } export function isErrorWithReason(error: Error | ErrorWithReason): error is ErrorWithReason { diff --git a/x-pack/plugins/alerting/server/lib/errors/index.ts b/x-pack/plugins/alerting/server/lib/errors/index.ts index 7ac8d9fced5cd..a2dcd45bbb63b 100644 --- a/x-pack/plugins/alerting/server/lib/errors/index.ts +++ b/x-pack/plugins/alerting/server/lib/errors/index.ts @@ -16,6 +16,6 @@ export function isErrorThatHandlesItsOwnResponse( export type { ErrorThatHandlesItsOwnResponse, ElasticsearchError }; export { getEsErrorMessage }; -export type { AlertTypeDisabledReason } from './alert_type_disabled'; -export { AlertTypeDisabledError } from './alert_type_disabled'; +export type { RuleTypeDisabledReason } from './rule_type_disabled'; +export { RuleTypeDisabledError } from './rule_type_disabled'; export { RuleMutedError } from './rule_muted'; diff --git a/x-pack/plugins/alerting/server/lib/errors/alert_type_disabled.ts b/x-pack/plugins/alerting/server/lib/errors/rule_type_disabled.ts similarity index 72% rename from x-pack/plugins/alerting/server/lib/errors/alert_type_disabled.ts rename to x-pack/plugins/alerting/server/lib/errors/rule_type_disabled.ts index 554497cc6c22b..f907436ddf955 100644 --- a/x-pack/plugins/alerting/server/lib/errors/alert_type_disabled.ts +++ b/x-pack/plugins/alerting/server/lib/errors/rule_type_disabled.ts @@ -8,16 +8,16 @@ import { KibanaResponseFactory } from '../../../../../../src/core/server'; import { ErrorThatHandlesItsOwnResponse } from './types'; -export type AlertTypeDisabledReason = +export type RuleTypeDisabledReason = | 'config' | 'license_unavailable' | 'license_invalid' | 'license_expired'; -export class AlertTypeDisabledError extends Error implements ErrorThatHandlesItsOwnResponse { - public readonly reason: AlertTypeDisabledReason; +export class RuleTypeDisabledError extends Error implements ErrorThatHandlesItsOwnResponse { + public readonly reason: RuleTypeDisabledReason; - constructor(message: string, reason: AlertTypeDisabledReason) { + constructor(message: string, reason: RuleTypeDisabledReason) { super(message); this.reason = reason; } diff --git a/x-pack/plugins/alerting/server/lib/format_execution_log_errors.ts b/x-pack/plugins/alerting/server/lib/format_execution_log_errors.ts index a169640c4fc83..ef5b931310f6a 100644 --- a/x-pack/plugins/alerting/server/lib/format_execution_log_errors.ts +++ b/x-pack/plugins/alerting/server/lib/format_execution_log_errors.ts @@ -7,6 +7,7 @@ import { get } from 'lodash'; import { QueryEventsBySavedObjectResult, IValidatedEvent } from '../../../event_log/server'; +import { IExecutionErrors, IExecutionErrorsResult } from '../../common'; const EXECUTION_UUID_FIELD = 'kibana.alert.rule.execution.uuid'; const TIMESTAMP_FIELD = '@timestamp'; @@ -14,18 +15,6 @@ const PROVIDER_FIELD = 'event.provider'; const MESSAGE_FIELD = 'message'; const ERROR_MESSAGE_FIELD = 'error.message'; -export interface IExecutionErrors { - id: string; - timestamp: string; - type: string; - message: string; -} - -export interface IExecutionErrorsResult { - totalErrors: number; - errors: IExecutionErrors[]; -} - export const EMPTY_EXECUTION_ERRORS_RESULT = { totalErrors: 0, errors: [], diff --git a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts index 75022427bea27..80090effca9d1 100644 --- a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts +++ b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts @@ -11,6 +11,7 @@ import { formatExecutionLogResult, formatSortForBucketSort, formatSortForTermSort, + ExecutionUuidAggResult, } from './get_execution_log_aggregation'; describe('formatSortForBucketSort', () => { @@ -128,92 +129,111 @@ describe('getExecutionLogAggregation', () => { sort: [{ timestamp: { order: 'asc' } }, { execution_duration: { order: 'desc' } }], }) ).toEqual({ - executionUuidCardinality: { cardinality: { field: 'kibana.alert.rule.execution.uuid' } }, - executionUuid: { - terms: { - field: 'kibana.alert.rule.execution.uuid', - size: 1000, - order: [ - { 'ruleExecution>executeStartTime': 'asc' }, - { 'ruleExecution>executionDuration': 'desc' }, - ], + excludeExecuteStart: { + filter: { + bool: { + must_not: [ + { + term: { + 'event.action': 'execute-start', + }, + }, + ], + }, }, aggs: { - executionUuidSorted: { - bucket_sort: { - sort: [ - { 'ruleExecution>executeStartTime': { order: 'asc' } }, - { 'ruleExecution>executionDuration': { order: 'desc' } }, + executionUuidCardinality: { cardinality: { field: 'kibana.alert.rule.execution.uuid' } }, + executionUuid: { + terms: { + field: 'kibana.alert.rule.execution.uuid', + size: 1000, + order: [ + { 'ruleExecution>executeStartTime': 'asc' }, + { 'ruleExecution>executionDuration': 'desc' }, ], - from: 10, - size: 10, - gap_policy: 'insert_zeros', - }, - }, - alertCounts: { - filters: { - filters: { - newAlerts: { match: { 'event.action': 'new-instance' } }, - activeAlerts: { match: { 'event.action': 'active-instance' } }, - recoveredAlerts: { match: { 'event.action': 'recovered-instance' } }, - }, - }, - }, - actionExecution: { - filter: { - bool: { - must: [ - { match: { 'event.action': 'execute' } }, - { match: { 'event.provider': 'actions' } }, - ], - }, - }, - aggs: { actionOutcomes: { terms: { field: 'event.outcome', size: 2 } } }, - }, - ruleExecution: { - filter: { - bool: { - must: [ - { match: { 'event.action': 'execute' } }, - { match: { 'event.provider': 'alerting' } }, - ], - }, }, aggs: { - executeStartTime: { min: { field: 'event.start' } }, - scheduleDelay: { - max: { - field: 'kibana.task.schedule_delay', + executionUuidSorted: { + bucket_sort: { + sort: [ + { 'ruleExecution>executeStartTime': { order: 'asc' } }, + { 'ruleExecution>executionDuration': { order: 'desc' } }, + ], + from: 10, + size: 10, + gap_policy: 'insert_zeros', }, }, - totalSearchDuration: { - max: { field: 'kibana.alert.rule.execution.metrics.total_search_duration_ms' }, - }, - esSearchDuration: { - max: { field: 'kibana.alert.rule.execution.metrics.es_search_duration_ms' }, - }, - numTriggeredActions: { - max: { field: 'kibana.alert.rule.execution.metrics.number_of_triggered_actions' }, + alertCounts: { + filters: { + filters: { + newAlerts: { match: { 'event.action': 'new-instance' } }, + activeAlerts: { match: { 'event.action': 'active-instance' } }, + recoveredAlerts: { match: { 'event.action': 'recovered-instance' } }, + }, + }, }, - numScheduledActions: { - max: { field: 'kibana.alert.rule.execution.metrics.number_of_scheduled_actions' }, + actionExecution: { + filter: { + bool: { + must: [ + { match: { 'event.action': 'execute' } }, + { match: { 'event.provider': 'actions' } }, + ], + }, + }, + aggs: { actionOutcomes: { terms: { field: 'event.outcome', size: 2 } } }, }, - executionDuration: { max: { field: 'event.duration' } }, - outcomeAndMessage: { - top_hits: { - size: 1, - _source: { includes: ['event.outcome', 'message', 'error.message'] }, + ruleExecution: { + filter: { + bool: { + must: [ + { match: { 'event.action': 'execute' } }, + { match: { 'event.provider': 'alerting' } }, + ], + }, + }, + aggs: { + executeStartTime: { min: { field: 'event.start' } }, + scheduleDelay: { + max: { + field: 'kibana.task.schedule_delay', + }, + }, + totalSearchDuration: { + max: { field: 'kibana.alert.rule.execution.metrics.total_search_duration_ms' }, + }, + esSearchDuration: { + max: { field: 'kibana.alert.rule.execution.metrics.es_search_duration_ms' }, + }, + numTriggeredActions: { + max: { + field: 'kibana.alert.rule.execution.metrics.number_of_triggered_actions', + }, + }, + numScheduledActions: { + max: { + field: 'kibana.alert.rule.execution.metrics.number_of_scheduled_actions', + }, + }, + executionDuration: { max: { field: 'event.duration' } }, + outcomeAndMessage: { + top_hits: { + size: 1, + _source: { includes: ['event.outcome', 'message', 'error.message'] }, + }, + }, }, }, - }, - }, - timeoutMessage: { - filter: { - bool: { - must: [ - { match: { 'event.action': 'execute-timeout' } }, - { match: { 'event.provider': 'alerting' } }, - ], + timeoutMessage: { + filter: { + bool: { + must: [ + { match: { 'event.action': 'execute-timeout' } }, + { match: { 'event.provider': 'alerting' } }, + ], + }, + }, }, }, }, @@ -230,188 +250,202 @@ describe('formatExecutionLogResult', () => { data: [], }); }); + test('should return empty results if aggregations.excludeExecuteStart are undefined', () => { + expect( + formatExecutionLogResult({ + aggregations: { excludeExecuteStart: undefined as unknown as ExecutionUuidAggResult }, + }) + ).toEqual({ + total: 0, + data: [], + }); + }); test('should format results correctly', () => { const results = { aggregations: { - executionUuid: { + excludeExecuteStart: { meta: {}, - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', - doc_count: 27, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + doc_count: 875, + executionUuid: { + meta: {}, + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', + doc_count: 27, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 0, + }, }, - newAlerts: { - doc_count: 5, + }, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 0, + numScheduledActions: { + value: 5.0, }, - }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ - { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'S4wIZX8B8TGQpG7XQZns', - _score: 1.0, - _source: { - event: { - outcome: 'success', + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'S4wIZX8B8TGQpG7XQZns', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, + ], + }, + }, + scheduleDelay: { + value: 3.074e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.056e9, + }, + executeStartTime: { + value: 1.646667512617e12, + value_as_string: '2022-03-07T15:38:32.617Z', + }, + }, + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.074e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.056e9, - }, - executeStartTime: { - value: 1.646667512617e12, - value_as_string: '2022-03-07T15:38:32.617Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', + { + key: '41b2755e-765a-4044-9745-b03875d5e79a', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { doc_count: 5, }, - ], + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 5, + }, + }, }, - }, - }, - { - key: '41b2755e-765a-4044-9745-b03875d5e79a', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - newAlerts: { - doc_count: 5, + numScheduledActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 5, + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'a4wIZX8B8TGQpG7Xwpnz', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + }, + }, + ], + }, + }, + scheduleDelay: { + value: 3.126e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.165e9, + }, + executeStartTime: { + value: 1.646667545604e12, + value_as_string: '2022-03-07T15:39:05.604Z', }, }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'a4wIZX8B8TGQpG7Xwpnz', - _score: 1.0, - _source: { - event: { - outcome: 'success', - }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - }, + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.126e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.165e9, - }, - executeStartTime: { - value: 1.646667545604e12, - value_as_string: '2022-03-07T15:39:05.604Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', - doc_count: 5, - }, - ], - }, - }, - }, - ], - }, - executionUuidCardinality: { - value: 374, + ], + }, + executionUuidCardinality: { + value: 374, + }, }, }, }; @@ -463,188 +497,192 @@ describe('formatExecutionLogResult', () => { test('should format results correctly with rule execution errors', () => { const results = { aggregations: { - executionUuid: { + excludeExecuteStart: { meta: {}, - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', - doc_count: 27, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + doc_count: 875, + executionUuid: { + meta: {}, + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', + doc_count: 27, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 0, + }, }, - newAlerts: { - doc_count: 5, + }, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 0, + numScheduledActions: { + value: 5.0, }, - }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ - { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'S4wIZX8B8TGQpG7XQZns', - _score: 1.0, - _source: { - event: { - outcome: 'failure', - }, - message: - "rule execution failure: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - error: { - message: 'I am erroring in rule execution!!', + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'S4wIZX8B8TGQpG7XQZns', + _score: 1.0, + _source: { + event: { + outcome: 'failure', + }, + message: + "rule execution failure: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + error: { + message: 'I am erroring in rule execution!!', + }, }, }, + ], + }, + }, + scheduleDelay: { + value: 3.074e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.056e9, + }, + executeStartTime: { + value: 1.646667512617e12, + value_as_string: '2022-03-07T15:38:32.617Z', + }, + }, + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.074e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.056e9, - }, - executeStartTime: { - value: 1.646667512617e12, - value_as_string: '2022-03-07T15:38:32.617Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', + { + key: '41b2755e-765a-4044-9745-b03875d5e79a', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { doc_count: 5, }, - ], + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 5, + }, + }, }, - }, - }, - { - key: '41b2755e-765a-4044-9745-b03875d5e79a', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - newAlerts: { - doc_count: 5, + numScheduledActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 5, + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'a4wIZX8B8TGQpG7Xwpnz', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + }, + }, + ], + }, + }, + scheduleDelay: { + value: 3.126e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.165e9, + }, + executeStartTime: { + value: 1.646667545604e12, + value_as_string: '2022-03-07T15:39:05.604Z', }, }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'a4wIZX8B8TGQpG7Xwpnz', - _score: 1.0, - _source: { - event: { - outcome: 'success', - }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - }, + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.126e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.165e9, - }, - executeStartTime: { - value: 1.646667545604e12, - value_as_string: '2022-03-07T15:39:05.604Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', - doc_count: 5, - }, - ], - }, - }, - }, - ], - }, - executionUuidCardinality: { - value: 374, + ], + }, + executionUuidCardinality: { + value: 374, + }, }, }, }; @@ -696,180 +734,184 @@ describe('formatExecutionLogResult', () => { test('should format results correctly when execution timeouts occur', () => { const results = { aggregations: { - executionUuid: { + excludeExecuteStart: { meta: {}, - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: '09b5aeab-d50d-43b2-88e7-f1a20f682b3f', - doc_count: 3, - timeoutMessage: { - meta: {}, - doc_count: 1, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 0, + doc_count: 875, + executionUuid: { + meta: {}, + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '09b5aeab-d50d-43b2-88e7-f1a20f682b3f', + doc_count: 3, + timeoutMessage: { + meta: {}, + doc_count: 1, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 0, + }, + newAlerts: { + doc_count: 0, + }, + recoveredAlerts: { + doc_count: 0, + }, }, - newAlerts: { - doc_count: 0, + }, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 0.0, }, - recoveredAlerts: { - doc_count: 0, + numScheduledActions: { + value: 0.0, }, - }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 0.0, - }, - numScheduledActions: { - value: 0.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ - { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'dJkWa38B1ylB1EvsAckB', - _score: 1.0, - _source: { - event: { - outcome: 'success', + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'dJkWa38B1ylB1EvsAckB', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, - }, - ], + ], + }, + }, + scheduleDelay: { + value: 3.074e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.0279e10, + }, + executeStartTime: { + value: 1.646769067607e12, + value_as_string: '2022-03-08T19:51:07.607Z', }, }, - scheduleDelay: { - value: 3.074e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.0279e10, - }, - executeStartTime: { - value: 1.646769067607e12, - value_as_string: '2022-03-08T19:51:07.607Z', + actionExecution: { + meta: {}, + doc_count: 0, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [], + }, }, }, - actionExecution: { - meta: {}, - doc_count: 0, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [], + { + key: '41b2755e-765a-4044-9745-b03875d5e79a', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 5, + }, + }, }, - }, - }, - { - key: '41b2755e-765a-4044-9745-b03875d5e79a', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - newAlerts: { - doc_count: 5, + numScheduledActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 5, + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'a4wIZX8B8TGQpG7Xwpnz', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + }, + }, + ], + }, + }, + scheduleDelay: { + value: 3.126e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.165e9, + }, + executeStartTime: { + value: 1.646667545604e12, + value_as_string: '2022-03-07T15:39:05.604Z', }, }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'a4wIZX8B8TGQpG7Xwpnz', - _score: 1.0, - _source: { - event: { - outcome: 'success', - }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - }, + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.126e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.165e9, - }, - executeStartTime: { - value: 1.646667545604e12, - value_as_string: '2022-03-07T15:39:05.604Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', - doc_count: 5, - }, - ], - }, - }, - }, - ], - }, - executionUuidCardinality: { - value: 374, + ], + }, + executionUuidCardinality: { + value: 374, + }, }, }, }; @@ -921,185 +963,189 @@ describe('formatExecutionLogResult', () => { test('should format results correctly when action errors occur', () => { const results = { aggregations: { - executionUuid: { + excludeExecuteStart: { meta: {}, - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'ecf7ac4c-1c15-4a1d-818a-cacbf57f6158', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + doc_count: 875, + executionUuid: { + meta: {}, + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'ecf7ac4c-1c15-4a1d-818a-cacbf57f6158', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 5, + }, }, - newAlerts: { - doc_count: 5, + }, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 5, + numScheduledActions: { + value: 5.0, }, - }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ - { - _index: '.kibana-event-log-8.2.0-000001', - _id: '7xKcb38BcntAq5ycFwiu', - _score: 1.0, - _source: { - event: { - outcome: 'success', + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: '7xKcb38BcntAq5ycFwiu', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, + ], + }, + }, + scheduleDelay: { + value: 3.126e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.374e9, + }, + executeStartTime: { + value: 1.646844973039e12, + value_as_string: '2022-03-09T16:56:13.039Z', + }, + }, + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'failure', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.126e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.374e9, - }, - executeStartTime: { - value: 1.646844973039e12, - value_as_string: '2022-03-09T16:56:13.039Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'failure', + { + key: '61bb867b-661a-471f-bf92-23471afa10b3', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { doc_count: 5, }, - ], + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 5, + }, + }, }, - }, - }, - { - key: '61bb867b-661a-471f-bf92-23471afa10b3', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - newAlerts: { - doc_count: 5, + numScheduledActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 5, + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'zRKbb38BcntAq5ycOwgk', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + }, + }, + ], + }, + }, + scheduleDelay: { + value: 3.133e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 4.18e8, + }, + executeStartTime: { + value: 1.646844917518e12, + value_as_string: '2022-03-09T16:55:17.518Z', }, }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'zRKbb38BcntAq5ycOwgk', - _score: 1.0, - _source: { - event: { - outcome: 'success', - }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - }, + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.133e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 4.18e8, - }, - executeStartTime: { - value: 1.646844917518e12, - value_as_string: '2022-03-09T16:55:17.518Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', - doc_count: 5, - }, - ], - }, - }, - }, - ], - }, - executionUuidCardinality: { - value: 417, + ], + }, + executionUuidCardinality: { + value: 417, + }, }, }, }; diff --git a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts index 6f8d0d8059b69..fbe72508dab2b 100644 --- a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts +++ b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts @@ -68,10 +68,15 @@ interface IExecutionUuidAggBucket extends estypes.AggregationsStringTermsBucketK }; } -interface ExecutionUuidAggResult +export interface ExecutionUuidAggResult extends estypes.AggregationsAggregateBase { buckets: TBucket[]; } + +interface ExcludeExecuteStartAggResult extends estypes.AggregationsAggregateBase { + executionUuid: ExecutionUuidAggResult; + executionUuidCardinality: estypes.AggregationsCardinalityAggregate; +} export interface IExecutionLogAggOptions { page: number; perPage: number; @@ -112,104 +117,119 @@ export function getExecutionLogAggregation({ page, perPage, sort }: IExecutionLo } return { - // Get total number of executions - executionUuidCardinality: { - cardinality: { - field: EXECUTION_UUID_FIELD, - }, - }, - executionUuid: { - // Bucket by execution UUID - terms: { - field: EXECUTION_UUID_FIELD, - size: DEFAULT_MAX_BUCKETS_LIMIT, - order: formatSortForTermSort(sort), + excludeExecuteStart: { + filter: { + bool: { + must_not: [ + { + term: { + [ACTION_FIELD]: 'execute-start', + }, + }, + ], + }, }, aggs: { - // Bucket sort to allow paging through executions - executionUuidSorted: { - bucket_sort: { - sort: formatSortForBucketSort(sort), - from: (page - 1) * perPage, - size: perPage, - gap_policy: 'insert_zeros' as estypes.AggregationsGapPolicy, + // Get total number of executions + executionUuidCardinality: { + cardinality: { + field: EXECUTION_UUID_FIELD, }, }, - // Get counts for types of alerts and whether there was an execution timeout - alertCounts: { - filters: { - filters: { - newAlerts: { match: { [ACTION_FIELD]: 'new-instance' } }, - activeAlerts: { match: { [ACTION_FIELD]: 'active-instance' } }, - recoveredAlerts: { match: { [ACTION_FIELD]: 'recovered-instance' } }, - }, + executionUuid: { + // Bucket by execution UUID + terms: { + field: EXECUTION_UUID_FIELD, + size: DEFAULT_MAX_BUCKETS_LIMIT, + order: formatSortForTermSort(sort), }, - }, - // Filter by action execute doc and get information from this event - actionExecution: { - filter: getProviderAndActionFilter('actions', 'execute'), aggs: { - actionOutcomes: { - terms: { - field: OUTCOME_FIELD, - size: 2, - }, - }, - }, - }, - // Filter by rule execute doc and get information from this event - ruleExecution: { - filter: getProviderAndActionFilter('alerting', 'execute'), - aggs: { - executeStartTime: { - min: { - field: START_FIELD, - }, - }, - scheduleDelay: { - max: { - field: SCHEDULE_DELAY_FIELD, - }, - }, - totalSearchDuration: { - max: { - field: TOTAL_SEARCH_DURATION_FIELD, - }, - }, - esSearchDuration: { - max: { - field: ES_SEARCH_DURATION_FIELD, - }, - }, - numTriggeredActions: { - max: { - field: NUMBER_OF_TRIGGERED_ACTIONS_FIELD, + // Bucket sort to allow paging through executions + executionUuidSorted: { + bucket_sort: { + sort: formatSortForBucketSort(sort), + from: (page - 1) * perPage, + size: perPage, + gap_policy: 'insert_zeros' as estypes.AggregationsGapPolicy, }, }, - numScheduledActions: { - max: { - field: NUMBER_OF_SCHEDULED_ACTIONS_FIELD, + // Get counts for types of alerts and whether there was an execution timeout + alertCounts: { + filters: { + filters: { + newAlerts: { match: { [ACTION_FIELD]: 'new-instance' } }, + activeAlerts: { match: { [ACTION_FIELD]: 'active-instance' } }, + recoveredAlerts: { match: { [ACTION_FIELD]: 'recovered-instance' } }, + }, }, }, - executionDuration: { - max: { - field: DURATION_FIELD, + // Filter by action execute doc and get information from this event + actionExecution: { + filter: getProviderAndActionFilter('actions', 'execute'), + aggs: { + actionOutcomes: { + terms: { + field: OUTCOME_FIELD, + size: 2, + }, + }, }, }, - outcomeAndMessage: { - top_hits: { - size: 1, - _source: { - includes: [OUTCOME_FIELD, MESSAGE_FIELD, ERROR_MESSAGE_FIELD], + // Filter by rule execute doc and get information from this event + ruleExecution: { + filter: getProviderAndActionFilter('alerting', 'execute'), + aggs: { + executeStartTime: { + min: { + field: START_FIELD, + }, + }, + scheduleDelay: { + max: { + field: SCHEDULE_DELAY_FIELD, + }, + }, + totalSearchDuration: { + max: { + field: TOTAL_SEARCH_DURATION_FIELD, + }, + }, + esSearchDuration: { + max: { + field: ES_SEARCH_DURATION_FIELD, + }, + }, + numTriggeredActions: { + max: { + field: NUMBER_OF_TRIGGERED_ACTIONS_FIELD, + }, + }, + numScheduledActions: { + max: { + field: NUMBER_OF_SCHEDULED_ACTIONS_FIELD, + }, + }, + executionDuration: { + max: { + field: DURATION_FIELD, + }, + }, + outcomeAndMessage: { + top_hits: { + size: 1, + _source: { + includes: [OUTCOME_FIELD, MESSAGE_FIELD, ERROR_MESSAGE_FIELD], + }, + }, }, }, }, + // If there was a timeout, this filter will return non-zero doc count + timeoutMessage: { + filter: getProviderAndActionFilter('alerting', 'execute-timeout'), + }, }, }, - // If there was a timeout, this filter will return non-zero doc count - timeoutMessage: { - filter: getProviderAndActionFilter('alerting', 'execute-timeout'), - }, }, }, }; @@ -280,13 +300,14 @@ export function formatExecutionLogResult( ): IExecutionLogResult { const { aggregations } = results; - if (!aggregations) { + if (!aggregations || !aggregations.excludeExecuteStart) { return EMPTY_EXECUTION_LOG_RESULT; } - const total = (aggregations.executionUuidCardinality as estypes.AggregationsCardinalityAggregate) - .value; - const buckets = (aggregations.executionUuid as ExecutionUuidAggResult).buckets; + const aggs = aggregations.excludeExecuteStart as ExcludeExecuteStartAggResult; + + const total = aggs.executionUuidCardinality.value; + const buckets = aggs.executionUuid.buckets; return { total, diff --git a/x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.test.ts b/x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.test.ts similarity index 64% rename from x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.test.ts rename to x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.test.ts index 92e7673c2e48e..747f5a8a8cd21 100644 --- a/x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.test.ts +++ b/x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.test.ts @@ -5,20 +5,20 @@ * 2.0. */ -import { getAlertNotifyWhenType } from './get_alert_notify_when_type'; +import { getRuleNotifyWhenType } from './get_rule_notify_when_type'; test(`should return 'notifyWhen' value if value is set and throttle is null`, () => { - expect(getAlertNotifyWhenType('onActionGroupChange', null)).toEqual('onActionGroupChange'); + expect(getRuleNotifyWhenType('onActionGroupChange', null)).toEqual('onActionGroupChange'); }); test(`should return 'notifyWhen' value if value is set and throttle is defined`, () => { - expect(getAlertNotifyWhenType('onActionGroupChange', '10m')).toEqual('onActionGroupChange'); + expect(getRuleNotifyWhenType('onActionGroupChange', '10m')).toEqual('onActionGroupChange'); }); test(`should return 'onThrottleInterval' value if 'notifyWhen' is null and throttle is defined`, () => { - expect(getAlertNotifyWhenType(null, '10m')).toEqual('onThrottleInterval'); + expect(getRuleNotifyWhenType(null, '10m')).toEqual('onThrottleInterval'); }); test(`should return 'onActiveAlert' value if 'notifyWhen' is null and throttle is null`, () => { - expect(getAlertNotifyWhenType(null, null)).toEqual('onActiveAlert'); + expect(getRuleNotifyWhenType(null, null)).toEqual('onActiveAlert'); }); diff --git a/x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.ts b/x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.ts similarity index 77% rename from x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.ts rename to x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.ts index a4bb0fe68a25b..53ccacde75e5c 100644 --- a/x-pack/plugins/alerting/server/lib/get_alert_notify_when_type.ts +++ b/x-pack/plugins/alerting/server/lib/get_rule_notify_when_type.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { AlertNotifyWhenType } from '../types'; +import { RuleNotifyWhenType } from '../types'; -export function getAlertNotifyWhenType( - notifyWhen: AlertNotifyWhenType | null, +export function getRuleNotifyWhenType( + notifyWhen: RuleNotifyWhenType | null, throttle: string | null -): AlertNotifyWhenType { +): RuleNotifyWhenType { // We allow notifyWhen to be null for backwards compatibility. If it is null, determine its // value based on whether the throttle is set to a value or null return notifyWhen ? notifyWhen! : throttle ? 'onThrottleInterval' : 'onActiveAlert'; diff --git a/x-pack/plugins/alerting/server/lib/index.ts b/x-pack/plugins/alerting/server/lib/index.ts index 22dbeff82b2d1..57c9a92a8d915 100644 --- a/x-pack/plugins/alerting/server/lib/index.ts +++ b/x-pack/plugins/alerting/server/lib/index.ts @@ -9,15 +9,15 @@ export { parseDuration, validateDurationSchema } from '../../common/parse_durati export type { ILicenseState } from './license_state'; export { LicenseState } from './license_state'; export { validateRuleTypeParams } from './validate_rule_type_params'; -export { getAlertNotifyWhenType } from './get_alert_notify_when_type'; +export { getRuleNotifyWhenType } from './get_rule_notify_when_type'; export { verifyApiAccess } from './license_api_access'; export { ErrorWithReason, getReasonFromError, isErrorWithReason } from './error_with_reason'; export type { - AlertTypeDisabledReason, + RuleTypeDisabledReason, ErrorThatHandlesItsOwnResponse, ElasticsearchError, } from './errors'; -export { AlertTypeDisabledError, RuleMutedError, isErrorThatHandlesItsOwnResponse } from './errors'; +export { RuleTypeDisabledError, RuleMutedError, isErrorThatHandlesItsOwnResponse } from './errors'; export { executionStatusFromState, executionStatusFromError, 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 643ca9b3f752b..214b95c5ef50c 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 @@ -9,7 +9,7 @@ import { isAlertSavedObjectNotFoundError, isEsUnavailableError } from './is_aler import { ErrorWithReason } from './error_with_reason'; import { SavedObjectsErrorHelpers } from '../../../../../src/core/server'; import uuid from 'uuid'; -import { AlertExecutionStatusErrorReasons } from '../types'; +import { RuleExecutionStatusErrorReasons } from '../types'; describe('isAlertSavedObjectNotFoundError', () => { const id = uuid.v4(); @@ -27,7 +27,7 @@ describe('isAlertSavedObjectNotFoundError', () => { }); test('identifies SavedObjects Not Found errors wrapped in an ErrorWithReason', () => { - const error = new ErrorWithReason(AlertExecutionStatusErrorReasons.Read, errorSONF); + const error = new ErrorWithReason(RuleExecutionStatusErrorReasons.Read, errorSONF); expect(isAlertSavedObjectNotFoundError(error, id)).toBe(true); }); }); @@ -48,7 +48,7 @@ describe('isEsUnavailableError', () => { }); test('identifies es unavailable errors wrapped in an ErrorWithReason', () => { - const error = new ErrorWithReason(AlertExecutionStatusErrorReasons.Read, errorSONF); + const error = new ErrorWithReason(RuleExecutionStatusErrorReasons.Read, errorSONF); expect(isEsUnavailableError(error, id)).toBe(true); }); }); diff --git a/x-pack/plugins/alerting/server/lib/license_state.ts b/x-pack/plugins/alerting/server/lib/license_state.ts index 162823f8d5850..340d608002fc5 100644 --- a/x-pack/plugins/alerting/server/lib/license_state.ts +++ b/x-pack/plugins/alerting/server/lib/license_state.ts @@ -17,12 +17,12 @@ import { PLUGIN } from '../constants/plugin'; import { getRuleTypeFeatureUsageName } from './get_rule_type_feature_usage_name'; import { RuleType, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, } from '../types'; -import { AlertTypeDisabledError } from './errors/alert_type_disabled'; +import { RuleTypeDisabledError } from './errors/rule_type_disabled'; export type ILicenseState = PublicMethodsOf; @@ -148,9 +148,9 @@ export class LicenseState { } public ensureLicenseForRuleType< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, @@ -179,7 +179,7 @@ export class LicenseState { } switch (check.reason) { case 'unavailable': - throw new AlertTypeDisabledError( + throw new RuleTypeDisabledError( i18n.translate('xpack.alerting.serverSideErrors.unavailableLicenseErrorMessage', { defaultMessage: 'Rule type {ruleTypeId} is disabled because license information is not available at this time.', @@ -190,7 +190,7 @@ export class LicenseState { 'license_unavailable' ); case 'expired': - throw new AlertTypeDisabledError( + throw new RuleTypeDisabledError( i18n.translate('xpack.alerting.serverSideErrors.expirerdLicenseErrorMessage', { defaultMessage: 'Rule type {ruleTypeId} is disabled because your {licenseType} license has expired.', @@ -199,7 +199,7 @@ export class LicenseState { 'license_expired' ); case 'invalid': - throw new AlertTypeDisabledError( + throw new RuleTypeDisabledError( i18n.translate('xpack.alerting.serverSideErrors.invalidLicenseErrorMessage', { defaultMessage: 'Rule {ruleTypeId} is disabled because it requires a {licenseType} license. Go to License Management to view upgrade options.', diff --git a/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts b/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts index 44a9e41c89052..ff43f4ffac8a9 100644 --- a/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts +++ b/x-pack/plugins/alerting/server/lib/rule_execution_status.test.ts @@ -7,8 +7,8 @@ import { loggingSystemMock } from '../../../../../src/core/server/mocks'; import { - AlertExecutionStatusErrorReasons, - AlertExecutionStatusWarningReasons, + RuleExecutionStatusErrorReasons, + RuleExecutionStatusWarningReasons, RuleExecutionState, } from '../types'; import { @@ -115,7 +115,7 @@ describe('RuleExecutionStatus', () => { checkDateIsNearNow(status.lastExecutionDate); expect(status.warning).toEqual({ message: translations.taskRunner.warning.maxExecutableActions, - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, }); expect(status.status).toBe('warning'); expect(status.error).toBe(undefined); @@ -136,7 +136,7 @@ describe('RuleExecutionStatus', () => { test('error with a reason', () => { const status = executionStatusFromError( - new ErrorWithReason(AlertExecutionStatusErrorReasons.Execute, new Error('hoo!')) + new ErrorWithReason(RuleExecutionStatusErrorReasons.Execute, new Error('hoo!')) ); expect(status.status).toBe('error'); expect(status.error).toMatchInlineSnapshot(` @@ -151,7 +151,7 @@ describe('RuleExecutionStatus', () => { describe('ruleExecutionStatusToRaw()', () => { const date = new Date('2020-09-03T16:26:58Z'); const status = 'ok'; - const reason = AlertExecutionStatusErrorReasons.Decrypt; + const reason = RuleExecutionStatusErrorReasons.Decrypt; const error = { reason, message: 'wops' }; test('status without an error', () => { @@ -213,7 +213,7 @@ describe('RuleExecutionStatus', () => { describe('ruleExecutionStatusFromRaw()', () => { const date = new Date('2020-09-03T16:26:58Z').toISOString(); const status = 'active'; - const reason = AlertExecutionStatusErrorReasons.Execute; + const reason = RuleExecutionStatusErrorReasons.Execute; const error = { reason, message: 'wops' }; test('no input', () => { diff --git a/x-pack/plugins/alerting/server/lib/rule_execution_status.ts b/x-pack/plugins/alerting/server/lib/rule_execution_status.ts index 9a446d2383c66..a87aed321b16b 100644 --- a/x-pack/plugins/alerting/server/lib/rule_execution_status.ts +++ b/x-pack/plugins/alerting/server/lib/rule_execution_status.ts @@ -7,29 +7,29 @@ import { Logger } from 'src/core/server'; import { - AlertExecutionStatus, - AlertExecutionStatusValues, - AlertExecutionStatusWarningReasons, + RuleExecutionStatus, + RuleExecutionStatusValues, + RuleExecutionStatusWarningReasons, RawRuleExecutionStatus, RuleExecutionState, } from '../types'; import { getReasonFromError } from './error_with_reason'; import { getEsErrorMessage } from './errors'; -import { AlertExecutionStatuses } from '../../common'; +import { RuleExecutionStatuses } from '../../common'; import { translations } from '../constants/translations'; import { ActionsCompletion } from '../task_runner/types'; -export function executionStatusFromState(state: RuleExecutionState): AlertExecutionStatus { +export function executionStatusFromState(state: RuleExecutionState): RuleExecutionStatus { const alertIds = Object.keys(state.alertInstances ?? {}); const hasIncompleteAlertExecution = state.alertExecutionStore.triggeredActionsStatus === ActionsCompletion.PARTIAL; - let status: AlertExecutionStatuses = - alertIds.length === 0 ? AlertExecutionStatusValues[0] : AlertExecutionStatusValues[1]; + let status: RuleExecutionStatuses = + alertIds.length === 0 ? RuleExecutionStatusValues[0] : RuleExecutionStatusValues[1]; if (hasIncompleteAlertExecution) { - status = AlertExecutionStatusValues[5]; + status = RuleExecutionStatusValues[5]; } return { @@ -40,14 +40,14 @@ export function executionStatusFromState(state: RuleExecutionState): AlertExecut status, ...(hasIncompleteAlertExecution && { warning: { - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, message: translations.taskRunner.warning.maxExecutableActions, }, }), }; } -export function executionStatusFromError(error: Error): AlertExecutionStatus { +export function executionStatusFromError(error: Error): RuleExecutionStatus { return { lastExecutionDate: new Date(), status: 'error', @@ -64,7 +64,7 @@ export function ruleExecutionStatusToRaw({ status, error, warning, -}: AlertExecutionStatus): RawRuleExecutionStatus { +}: RuleExecutionStatus): RawRuleExecutionStatus { return { lastExecutionDate: lastExecutionDate.toISOString(), lastDuration: lastDuration ?? 0, @@ -79,7 +79,7 @@ export function ruleExecutionStatusFromRaw( logger: Logger, ruleId: string, rawRuleExecutionStatus?: Partial | null | undefined -): AlertExecutionStatus | undefined { +): RuleExecutionStatus | undefined { if (!rawRuleExecutionStatus) return undefined; const { @@ -98,7 +98,7 @@ export function ruleExecutionStatusFromRaw( parsedDateMillis = Date.now(); } - const executionStatus: AlertExecutionStatus = { + const executionStatus: RuleExecutionStatus = { status, lastExecutionDate: new Date(parsedDateMillis), }; @@ -119,7 +119,7 @@ export function ruleExecutionStatusFromRaw( } export const getRuleExecutionStatusPending = (lastExecutionDate: string) => ({ - status: 'pending' as AlertExecutionStatuses, + status: 'pending' as RuleExecutionStatuses, lastExecutionDate, error: null, warning: null, diff --git a/x-pack/plugins/alerting/server/lib/validate_rule_type_params.ts b/x-pack/plugins/alerting/server/lib/validate_rule_type_params.ts index eef6ecb32c1b1..b791b05499263 100644 --- a/x-pack/plugins/alerting/server/lib/validate_rule_type_params.ts +++ b/x-pack/plugins/alerting/server/lib/validate_rule_type_params.ts @@ -6,11 +6,11 @@ */ import Boom from '@hapi/boom'; -import { AlertTypeParams, AlertTypeParamsValidator } from '../types'; +import { RuleTypeParams, RuleTypeParamsValidator } from '../types'; -export function validateRuleTypeParams( +export function validateRuleTypeParams( params: Record, - validator?: AlertTypeParamsValidator + validator?: RuleTypeParamsValidator ): Params { if (!validator) { return params as Params; diff --git a/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.ts b/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.ts index 69d4817f21a4e..914d6f8c6da30 100644 --- a/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.ts +++ b/x-pack/plugins/alerting/server/lib/wrap_scoped_cluster_client.ts @@ -22,7 +22,7 @@ import type { } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { IScopedClusterClient, ElasticsearchClient, Logger } from 'src/core/server'; import { RuleExecutionMetrics } from '../types'; -import { Alert as Rule } from '../types'; +import { Rule } from '../types'; type RuleInfo = Pick & { spaceId: string }; interface WrapScopedClusterClientFactoryOpts { diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index c952e9182190c..d9951b4a79759 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -96,7 +96,7 @@ const createAbortableSearchServiceMock = () => { }; }; -const createAlertServicesMock = < +const createRuleExecutorServicesMock = < InstanceState extends AlertInstanceState = AlertInstanceState, InstanceContext extends AlertInstanceContext = AlertInstanceContext >() => { @@ -120,11 +120,11 @@ const createAlertServicesMock = < ), }; }; -export type AlertServicesMock = ReturnType; +export type RuleExecutorServicesMock = ReturnType; export const alertsMock = { createAlertFactory: createAlertFactoryMock, createSetup: createSetupMock, createStart: createStartMock, - createAlertServices: createAlertServicesMock, + createRuleExecutorServices: createRuleExecutorServicesMock, }; diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index 47e2450b7a85c..85279ec615331 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -45,8 +45,8 @@ import { AlertInstanceState, AlertsHealth, RuleType, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, } from './types'; import { registerAlertingUsageCollector } from './usage'; import { initializeAlertingTelemetry, scheduleAlertingTelemetry } from './usage/task'; @@ -85,9 +85,9 @@ export const LEGACY_EVENT_LOG_ACTIONS = { export interface PluginSetupContract { registerType< - Params extends AlertTypeParams = AlertTypeParams, - ExtractedParams extends AlertTypeParams = AlertTypeParams, - State extends AlertTypeState = AlertTypeState, + Params extends RuleTypeParams = RuleTypeParams, + ExtractedParams extends RuleTypeParams = RuleTypeParams, + State extends RuleTypeState = RuleTypeState, InstanceState extends AlertInstanceState = AlertInstanceState, InstanceContext extends AlertInstanceContext = AlertInstanceContext, ActionGroupIds extends string = never, @@ -287,9 +287,9 @@ export class AlertingPlugin { return { registerType: < - Params extends AlertTypeParams = never, - ExtractedParams extends AlertTypeParams = never, - State extends AlertTypeState = never, + Params extends RuleTypeParams = never, + ExtractedParams extends RuleTypeParams = never, + State extends RuleTypeState = never, InstanceState extends AlertInstanceState = never, InstanceContext extends AlertInstanceContext = never, ActionGroupIds extends string = never, diff --git a/x-pack/plugins/alerting/server/routes/create_rule.test.ts b/x-pack/plugins/alerting/server/routes/create_rule.test.ts index c878d8da218b1..62c7819fb5b05 100644 --- a/x-pack/plugins/alerting/server/routes/create_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/create_rule.test.ts @@ -13,9 +13,9 @@ import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { CreateOptions } from '../rules_client'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib'; +import { RuleTypeDisabledError } from '../lib'; import { AsApiContract } from './lib'; -import { SanitizedAlert } from '../types'; +import { SanitizedRule } from '../types'; import { encryptedSavedObjectsMock } from '../../../encrypted_saved_objects/server/mocks'; import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; @@ -33,7 +33,7 @@ describe('createRuleRoute', () => { const createdAt = new Date(); const updatedAt = new Date(); - const mockedAlert: SanitizedAlert<{ bar: boolean }> = { + const mockedAlert: SanitizedRule<{ bar: boolean }> = { alertTypeId: '1', consumer: 'bar', name: 'abc', @@ -82,7 +82,7 @@ describe('createRuleRoute', () => { ], }; - const createResult: AsApiContract> = { + const createResult: AsApiContract> = { ...ruleToCreate, mute_all: mockedAlert.muteAll, created_by: mockedAlert.createdBy, @@ -471,7 +471,7 @@ describe('createRuleRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.create.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.create.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { body: ruleToCreate }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/create_rule.ts b/x-pack/plugins/alerting/server/routes/create_rule.ts index ed124bfbd3a2d..5278f748f0ce4 100644 --- a/x-pack/plugins/alerting/server/routes/create_rule.ts +++ b/x-pack/plugins/alerting/server/routes/create_rule.ts @@ -6,7 +6,7 @@ */ import { schema } from '@kbn/config-schema'; -import { validateDurationSchema, AlertTypeDisabledError } from '../lib'; +import { validateDurationSchema, RuleTypeDisabledError } from '../lib'; import { CreateOptions } from '../rules_client'; import { RewriteRequestCase, @@ -16,11 +16,11 @@ import { countUsageOfPredefinedIds, } from './lib'; import { - SanitizedAlert, + SanitizedRule, validateNotifyWhenType, - AlertTypeParams, + RuleTypeParams, BASE_ALERTING_API_PATH, - AlertNotifyWhenType, + RuleNotifyWhenType, } from '../types'; import { RouteOptions } from '.'; @@ -46,7 +46,7 @@ export const bodySchema = schema.object({ notify_when: schema.string({ validate: validateNotifyWhenType }), }); -const rewriteBodyReq: RewriteRequestCase['data']> = ({ +const rewriteBodyReq: RewriteRequestCase['data']> = ({ rule_type_id: alertTypeId, notify_when: notifyWhen, ...rest @@ -55,7 +55,7 @@ const rewriteBodyReq: RewriteRequestCase['data']> alertTypeId, notifyWhen, }); -const rewriteBodyRes: RewriteResponseCase> = ({ +const rewriteBodyRes: RewriteResponseCase> = ({ actions, alertTypeId, scheduledTaskId, @@ -121,11 +121,11 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt }); try { - const createdRule: SanitizedAlert = - await rulesClient.create({ + const createdRule: SanitizedRule = + await rulesClient.create({ data: rewriteBodyReq({ ...rule, - notify_when: rule.notify_when as AlertNotifyWhenType, + notify_when: rule.notify_when as RuleNotifyWhenType, }), options: { id: params?.id }, }); @@ -133,7 +133,7 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt body: rewriteBodyRes(createdRule), }); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.test.ts b/x-pack/plugins/alerting/server/routes/disable_rule.test.ts index 173f1df7e1e73..baecc8f198fff 100644 --- a/x-pack/plugins/alerting/server/routes/disable_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/disable_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); @@ -67,7 +67,7 @@ describe('disableRuleRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.disable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.disable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/disable_rule.ts b/x-pack/plugins/alerting/server/routes/disable_rule.ts index 81f77cb130d50..74bf9d11166be 100644 --- a/x-pack/plugins/alerting/server/routes/disable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/disable_rule.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -34,7 +34,7 @@ export const disableRuleRoute = ( await rulesClient.disable({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.test.ts b/x-pack/plugins/alerting/server/routes/enable_rule.test.ts index 4c0bae2587924..9a8b3fe1b4226 100644 --- a/x-pack/plugins/alerting/server/routes/enable_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/enable_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); @@ -67,7 +67,7 @@ describe('enableRuleRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.enable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.enable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/enable_rule.ts b/x-pack/plugins/alerting/server/routes/enable_rule.ts index 5d77e375cfce6..e62e6aa30221f 100644 --- a/x-pack/plugins/alerting/server/routes/enable_rule.ts +++ b/x-pack/plugins/alerting/server/routes/enable_rule.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -34,7 +34,7 @@ export const enableRuleRoute = ( await rulesClient.enable({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/find_rules.ts b/x-pack/plugins/alerting/server/routes/find_rules.ts index 1202d56edb21c..7d7f878780ac3 100644 --- a/x-pack/plugins/alerting/server/routes/find_rules.ts +++ b/x-pack/plugins/alerting/server/routes/find_rules.ts @@ -13,7 +13,7 @@ import { ILicenseState } from '../lib'; import { FindOptions, FindResult } from '../rules_client'; import { RewriteRequestCase, RewriteResponseCase, verifyAccessAndContext } from './lib'; import { - AlertTypeParams, + RuleTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH, INTERNAL_BASE_ALERTING_API_PATH, @@ -62,7 +62,7 @@ const rewriteQueryReq: RewriteRequestCase = ({ ...(hasReference ? { hasReference } : {}), ...(searchFields ? { searchFields } : {}), }); -const rewriteBodyRes: RewriteResponseCase> = ({ +const rewriteBodyRes: RewriteResponseCase> = ({ perPage, data, ...restOfResult diff --git a/x-pack/plugins/alerting/server/routes/get_rule.test.ts b/x-pack/plugins/alerting/server/routes/get_rule.test.ts index 47503374394f8..4384e02352d95 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule.test.ts @@ -12,7 +12,7 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { SanitizedAlert } from '../types'; +import { SanitizedRule } from '../types'; import { AsApiContract } from './lib'; const rulesClient = rulesClientMock.create(); @@ -25,7 +25,7 @@ beforeEach(() => { }); describe('getRuleRoute', () => { - const mockedAlert: SanitizedAlert<{ + const mockedAlert: SanitizedRule<{ bar: boolean; }> = { id: '1', @@ -63,7 +63,7 @@ describe('getRuleRoute', () => { }, }; - const getResult: AsApiContract> = { + const getResult: AsApiContract> = { ...pick(mockedAlert, 'consumer', 'name', 'schedule', 'tags', 'params', 'throttle', 'enabled'), rule_type_id: mockedAlert.alertTypeId, notify_when: mockedAlert.notifyWhen, diff --git a/x-pack/plugins/alerting/server/routes/get_rule.ts b/x-pack/plugins/alerting/server/routes/get_rule.ts index 8e0e89c379fcc..52b73d22680f9 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule.ts @@ -11,18 +11,18 @@ import { IRouter } from 'kibana/server'; import { ILicenseState } from '../lib'; import { verifyAccessAndContext, RewriteResponseCase } from './lib'; import { - AlertTypeParams, + RuleTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH, INTERNAL_BASE_ALERTING_API_PATH, - SanitizedAlert, + SanitizedRule, } from '../types'; const paramSchema = schema.object({ id: schema.string(), }); -const rewriteBodyRes: RewriteResponseCase> = ({ +const rewriteBodyRes: RewriteResponseCase> = ({ alertTypeId, createdBy, updatedBy, diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts index f304c7be86131..2394e159a9f19 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts @@ -11,7 +11,7 @@ import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { SavedObjectsErrorHelpers } from 'src/core/server'; import { rulesClientMock } from '../rules_client.mock'; -import { IExecutionLogWithErrorsResult } from '../rules_client'; +import { IExecutionLogWithErrorsResult } from '../../common'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts index cfbef73ea58db..cd584543d57e0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -12,8 +12,8 @@ import { licenseStateMock } from '../../lib/license_state.mock'; import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { Alert } from '../../../common/alert'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { Rule } from '../../../common/rule'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { encryptedSavedObjectsMock } from '../../../../encrypted_saved_objects/server/mocks'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; @@ -57,7 +57,7 @@ describe('createAlertRoute', () => { ], }; - const createResult: Alert<{ bar: boolean }> = { + const createResult: Rule<{ bar: boolean }> = { ...mockedAlert, enabled: true, muteAll: false, @@ -436,7 +436,7 @@ describe('createAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.create.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.create.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok', 'forbidden']); diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.ts b/x-pack/plugins/alerting/server/routes/legacy/create.ts index 8deeb733fd3b5..b6669a605022d 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.ts @@ -10,13 +10,13 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { validateDurationSchema } from '../../lib'; import { handleDisabledApiKeysError } from './../lib/error_handler'; import { - SanitizedAlert, - AlertNotifyWhenType, - AlertTypeParams, + SanitizedRule, + RuleNotifyWhenType, + RuleTypeParams, LEGACY_BASE_ALERT_API_PATH, validateNotifyWhenType, } from '../../types'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { RouteOptions } from '..'; import { countUsageOfPredefinedIds } from '../lib'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; @@ -67,7 +67,7 @@ export const createAlertRoute = ({ router, licenseState, usageCounter }: RouteOp const rulesClient = context.alerting.getRulesClient(); const alert = req.body; const params = req.params; - const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as AlertNotifyWhenType) : null; + const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as RuleNotifyWhenType) : null; trackLegacyRouteUsage('create', usageCounter); @@ -78,16 +78,15 @@ export const createAlertRoute = ({ router, licenseState, usageCounter }: RouteOp }); try { - const alertRes: SanitizedAlert = - await rulesClient.create({ - data: { ...alert, notifyWhen }, - options: { id: params?.id }, - }); + const alertRes: SanitizedRule = await rulesClient.create({ + data: { ...alert, notifyWhen }, + options: { id: params?.id }, + }); return res.ok({ body: alertRes, }); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts index ac44ab37761bc..1e9f5531d19d2 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -72,7 +72,7 @@ describe('disableAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.disable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.disable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.ts index 1cba654e11a51..1345c4ae4428a 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.ts @@ -11,7 +11,7 @@ import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -42,7 +42,7 @@ export const disableAlertRoute = ( await rulesClient.disable({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts index c35fb191fae6f..eb839ba3e7b83 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -72,7 +72,7 @@ describe('enableAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.enable.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.enable.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.ts index 000d165ff169d..ec3b4b0a0fc20 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.ts @@ -12,7 +12,7 @@ import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { handleDisabledApiKeysError } from './../lib/error_handler'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -44,7 +44,7 @@ export const enableAlertRoute = ( await rulesClient.enable({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts index 40c7b224c7150..8c2233ae280b7 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts @@ -12,7 +12,7 @@ import { licenseStateMock } from '../../lib/license_state.mock'; import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { Alert } from '../../../common'; +import { Rule } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -29,7 +29,7 @@ beforeEach(() => { }); describe('getAlertRoute', () => { - const mockedAlert: Alert<{ + const mockedAlert: Rule<{ bar: true; }> = { id: '1', diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts index 131b5ed7960bd..9d84fd75a68c5 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts @@ -11,7 +11,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -72,7 +72,7 @@ describe('muteAllAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.muteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.muteAll.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts index 222abc806ede2..f35ffe93ccda4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts @@ -11,7 +11,7 @@ import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -42,7 +42,7 @@ export const muteAllAlertRoute = ( await rulesClient.muteAll({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts index 19ce9e1d2b107..5e17c42528e14 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts @@ -11,7 +11,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -77,7 +77,7 @@ describe('muteAlertInstanceRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.muteInstance.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts index be1c0876d5d2e..af6aea1e0f6c7 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts @@ -13,7 +13,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { renameKeys } from './../lib/rename_keys'; import { MuteOptions } from '../../rules_client'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -53,7 +53,7 @@ export const muteAlertInstanceRoute = ( await rulesClient.muteInstance(renamedQuery); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts index 8259d2305b941..f3530786667ff 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts @@ -11,7 +11,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -72,7 +72,7 @@ describe('unmuteAllAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.unmuteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.unmuteAll.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts index 40c303e5d7633..a6cd687271cc4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts @@ -11,7 +11,7 @@ import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -42,7 +42,7 @@ export const unmuteAllAlertRoute = ( await rulesClient.unmuteAll({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts index bbe61d715a525..fa109fa09f250 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts @@ -11,7 +11,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -77,7 +77,7 @@ describe('unmuteAlertInstanceRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.unmuteInstance.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts index 1c65af9961adc..d4684bda7f0fa 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts @@ -11,7 +11,7 @@ import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -43,7 +43,7 @@ export const unmuteAlertInstanceRoute = ( await rulesClient.unmuteInstance({ alertId, alertInstanceId }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts index 799672c3cf432..5396e267fa525 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts @@ -12,8 +12,8 @@ import { licenseStateMock } from '../../lib/license_state.mock'; import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; -import { AlertNotifyWhenType } from '../../../common'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; +import { RuleNotifyWhenType } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -50,7 +50,7 @@ describe('updateAlertRoute', () => { }, }, ], - notifyWhen: 'onActionGroupChange' as AlertNotifyWhenType, + notifyWhen: 'onActionGroupChange' as RuleNotifyWhenType, }; it('updates an alert with proper parameters', async () => { @@ -229,7 +229,7 @@ describe('updateAlertRoute', () => { const [, handler] = router.put.mock.calls[0]; - rulesClient.update.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.update.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.ts b/x-pack/plugins/alerting/server/routes/legacy/update.ts index d6e6a2b3c4ae8..b740be04829e8 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.ts @@ -12,10 +12,10 @@ import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { validateDurationSchema } from '../../lib'; import { handleDisabledApiKeysError } from './../lib/error_handler'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { - AlertNotifyWhenType, + RuleNotifyWhenType, LEGACY_BASE_ALERT_API_PATH, validateNotifyWhenType, } from '../../../common'; @@ -77,14 +77,14 @@ export const updateAlertRoute = ( schedule, tags, throttle, - notifyWhen: notifyWhen as AlertNotifyWhenType, + notifyWhen: notifyWhen as RuleNotifyWhenType, }, }); return res.ok({ body: alertRes, }); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts index 7c48f5fff357d..5ae3ec2f5387f 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts @@ -11,7 +11,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../../lib/license_state.mock'; import { mockHandlerArguments } from './../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const rulesClient = rulesClientMock.create(); @@ -73,7 +73,7 @@ describe('updateApiKeyRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.updateApiKey.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts index a45767851c5c1..ab5ff254fca86 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts @@ -12,7 +12,7 @@ import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; import { handleDisabledApiKeysError } from './../lib/error_handler'; -import { AlertTypeDisabledError } from '../../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; const paramSchema = schema.object({ @@ -44,7 +44,7 @@ export const updateApiKeyRoute = ( await rulesClient.updateApiKey({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/mute_alert.test.ts b/x-pack/plugins/alerting/server/routes/mute_alert.test.ts index 284a89ea8a677..0fc28412abc6f 100644 --- a/x-pack/plugins/alerting/server/routes/mute_alert.test.ts +++ b/x-pack/plugins/alerting/server/routes/mute_alert.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -71,7 +71,7 @@ describe('muteAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.muteInstance.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/mute_alert.ts b/x-pack/plugins/alerting/server/routes/mute_alert.ts index 301d04f362313..67e6f3b4002d7 100644 --- a/x-pack/plugins/alerting/server/routes/mute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/mute_alert.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { MuteOptions } from '../rules_client'; import { RewriteRequestCase, verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -44,7 +44,7 @@ export const muteAlertRoute = ( await rulesClient.muteInstance(params); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts index 56e46db082514..277add6ec1647 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -66,7 +66,7 @@ describe('muteAllRuleRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.muteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.muteAll.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts index f6d3870ef6744..ad3c93f415ea2 100644 --- a/x-pack/plugins/alerting/server/routes/mute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/mute_all_rule.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -34,7 +34,7 @@ export const muteAllRuleRoute = ( await rulesClient.muteAll({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/resolve_rule.ts b/x-pack/plugins/alerting/server/routes/resolve_rule.ts index a31cf5059b99f..e6cacb8231b5f 100644 --- a/x-pack/plugins/alerting/server/routes/resolve_rule.ts +++ b/x-pack/plugins/alerting/server/routes/resolve_rule.ts @@ -11,7 +11,7 @@ import { IRouter } from 'kibana/server'; import { ILicenseState } from '../lib'; import { verifyAccessAndContext, RewriteResponseCase } from './lib'; import { - AlertTypeParams, + RuleTypeParams, AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH, ResolvedSanitizedRule, @@ -21,7 +21,7 @@ const paramSchema = schema.object({ id: schema.string(), }); -const rewriteBodyRes: RewriteResponseCase> = ({ +const rewriteBodyRes: RewriteResponseCase> = ({ alertTypeId, createdBy, updatedBy, diff --git a/x-pack/plugins/alerting/server/routes/snooze_rule.test.ts b/x-pack/plugins/alerting/server/routes/snooze_rule.test.ts index dbcce10cc8e3e..f7e83301385ad 100644 --- a/x-pack/plugins/alerting/server/routes/snooze_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/snooze_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -113,7 +113,7 @@ describe('snoozeAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.snooze.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.snooze.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts index 09c0033542dbb..bfc281cb16b2f 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -71,7 +71,7 @@ describe('unmuteAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.unmuteInstance.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/unmute_alert.ts b/x-pack/plugins/alerting/server/routes/unmute_alert.ts index 58c3f59b836b1..0269f53fa8827 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_alert.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { MuteOptions } from '../rules_client'; import { RewriteRequestCase, verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -44,7 +44,7 @@ export const unmuteAlertRoute = ( await rulesClient.unmuteInstance(params); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts index 0f031c2d8cc80..ff97819506276 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -66,7 +66,7 @@ describe('unmuteAllRuleRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.unmuteAll.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.unmuteAll.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts index a0b562404b0b1..05ae9be2ba6e5 100644 --- a/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/unmute_all_rule.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, BASE_ALERTING_API_PATH } from '../types'; @@ -34,7 +34,7 @@ export const unmuteAllRuleRoute = ( await rulesClient.unmuteAll({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/unsnooze_rule.test.ts b/x-pack/plugins/alerting/server/routes/unsnooze_rule.test.ts index a0fbf9776240a..260e4b4150043 100644 --- a/x-pack/plugins/alerting/server/routes/unsnooze_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/unsnooze_rule.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -66,7 +66,7 @@ describe('unsnoozeAlertRoute', () => { const [, handler] = router.post.mock.calls[0]; - rulesClient.unsnooze.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.unsnooze.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/update_rule.test.ts b/x-pack/plugins/alerting/server/routes/update_rule.test.ts index 46f23641f70d9..f39ad53c8786d 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule.test.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule.test.ts @@ -13,10 +13,10 @@ import { verifyApiAccess } from '../lib/license_api_access'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { UpdateOptions } from '../rules_client'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; -import { AlertNotifyWhenType } from '../../common'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; +import { RuleNotifyWhenType } from '../../common'; import { AsApiContract } from './lib'; -import { PartialAlert } from '../types'; +import { PartialRule } from '../types'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -50,7 +50,7 @@ describe('updateRuleRoute', () => { }, }, ], - notifyWhen: 'onActionGroupChange' as AlertNotifyWhenType, + notifyWhen: 'onActionGroupChange' as RuleNotifyWhenType, }; const updateRequest: AsApiContract['data']> = { @@ -65,7 +65,7 @@ describe('updateRuleRoute', () => { ], }; - const updateResult: AsApiContract> = { + const updateResult: AsApiContract> = { ...updateRequest, id: mockedAlert.id, updated_at: mockedAlert.updatedAt, @@ -201,7 +201,7 @@ describe('updateRuleRoute', () => { const [, handler] = router.put.mock.calls[0]; - rulesClient.update.mockRejectedValue(new AlertTypeDisabledError('Fail', 'license_invalid')); + rulesClient.update.mockRejectedValue(new RuleTypeDisabledError('Fail', 'license_invalid')); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', diff --git a/x-pack/plugins/alerting/server/routes/update_rule.ts b/x-pack/plugins/alerting/server/routes/update_rule.ts index 007d24bb8251b..5c416e50b4ff2 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule.ts @@ -7,8 +7,8 @@ import { schema } from '@kbn/config-schema'; import { IRouter } from 'kibana/server'; -import { ILicenseState, AlertTypeDisabledError, validateDurationSchema } from '../lib'; -import { AlertNotifyWhenType } from '../../common'; +import { ILicenseState, RuleTypeDisabledError, validateDurationSchema } from '../lib'; +import { RuleNotifyWhenType } from '../../common'; import { UpdateOptions } from '../rules_client'; import { verifyAccessAndContext, @@ -17,11 +17,11 @@ import { handleDisabledApiKeysError, } from './lib'; import { - AlertTypeParams, + RuleTypeParams, AlertingRequestHandlerContext, BASE_ALERTING_API_PATH, validateNotifyWhenType, - PartialAlert, + PartialRule, } from '../types'; const paramSchema = schema.object({ @@ -47,7 +47,7 @@ const bodySchema = schema.object({ notify_when: schema.string({ validate: validateNotifyWhenType }), }); -const rewriteBodyReq: RewriteRequestCase> = (result) => { +const rewriteBodyReq: RewriteRequestCase> = (result) => { const { notify_when: notifyWhen, ...rest } = result.data; return { ...result, @@ -57,7 +57,7 @@ const rewriteBodyReq: RewriteRequestCase> = (resu }, }; }; -const rewriteBodyRes: RewriteResponseCase> = ({ +const rewriteBodyRes: RewriteResponseCase> = ({ actions, alertTypeId, scheduledTaskId, @@ -128,7 +128,7 @@ export const updateRuleRoute = ( id, data: { ...rule, - notify_when: rule.notify_when as AlertNotifyWhenType, + notify_when: rule.notify_when as RuleNotifyWhenType, }, }) ); @@ -136,7 +136,7 @@ export const updateRuleRoute = ( body: rewriteBodyRes(alertRes), }); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts index b4fb7602bf034..2622c260d7938 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.test.ts @@ -10,7 +10,7 @@ import { httpServiceMock } from 'src/core/server/mocks'; import { licenseStateMock } from '../lib/license_state.mock'; import { mockHandlerArguments } from './_mock_handler_arguments'; import { rulesClientMock } from '../rules_client.mock'; -import { AlertTypeDisabledError } from '../lib/errors/alert_type_disabled'; +import { RuleTypeDisabledError } from '../lib/errors/rule_type_disabled'; const rulesClient = rulesClientMock.create(); jest.mock('../lib/license_api_access.ts', () => ({ @@ -67,7 +67,7 @@ describe('updateRuleApiKeyRoute', () => { const [, handler] = router.post.mock.calls[0]; rulesClient.updateApiKey.mockRejectedValue( - new AlertTypeDisabledError('Fail', 'license_invalid') + new RuleTypeDisabledError('Fail', 'license_invalid') ); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ diff --git a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts index 11d76f3992efd..a6644e455a9be 100644 --- a/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/update_rule_api_key.ts @@ -7,7 +7,7 @@ import { IRouter } from 'kibana/server'; import { schema } from '@kbn/config-schema'; -import { ILicenseState, AlertTypeDisabledError } from '../lib'; +import { ILicenseState, RuleTypeDisabledError } from '../lib'; import { verifyAccessAndContext } from './lib'; import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; @@ -34,7 +34,7 @@ export const updateRuleApiKeyRoute = ( await rulesClient.updateApiKey({ id }); return res.noContent(); } catch (e) { - if (e instanceof AlertTypeDisabledError) { + if (e instanceof RuleTypeDisabledError) { return e.sendResponse(res); } throw e; diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 35e9e312e9a1a..bc548b8ae2286 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -16,8 +16,8 @@ import { RunContext, TaskManagerSetupContract } from '../../task_manager/server' import { TaskRunnerFactory } from './task_runner'; import { RuleType, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, } from './types'; @@ -84,9 +84,9 @@ const ruleTypeIdSchema = schema.string({ }); export type NormalizedRuleType< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, @@ -121,9 +121,9 @@ export type NormalizedRuleType< >; export type UntypedNormalizedRuleType = NormalizedRuleType< - AlertTypeParams, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string, @@ -167,9 +167,9 @@ export class RuleTypeRegistry { } public register< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, @@ -287,9 +287,9 @@ export class RuleTypeRegistry { } public get< - Params extends AlertTypeParams = AlertTypeParams, - ExtractedParams extends AlertTypeParams = AlertTypeParams, - State extends AlertTypeState = AlertTypeState, + Params extends RuleTypeParams = RuleTypeParams, + ExtractedParams extends RuleTypeParams = RuleTypeParams, + State extends RuleTypeState = RuleTypeState, InstanceState extends AlertInstanceState = AlertInstanceState, InstanceContext extends AlertInstanceContext = AlertInstanceContext, ActionGroupIds extends string = string, @@ -382,9 +382,9 @@ function normalizedActionVariables(actionVariables: RuleType['actionVariables']) } function augmentActionGroupsWithReserved< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, diff --git a/x-pack/plugins/alerting/server/rules_client/lib/mapped_params_utils.ts b/x-pack/plugins/alerting/server/rules_client/lib/mapped_params_utils.ts index e9624d4604c46..26385cfac3f78 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/mapped_params_utils.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/mapped_params_utils.ts @@ -6,7 +6,7 @@ */ import { snakeCase } from 'lodash'; -import { AlertTypeParams, MappedParams, MappedParamsProperties } from '../../types'; +import { RuleTypeParams, MappedParams, MappedParamsProperties } from '../../types'; import { SavedObjectAttribute } from '../../../../../../src/core/server'; import { iterateFilterKureyNode, @@ -32,7 +32,7 @@ const SEVERITY_MAP: Record = { * The function will match params present in MAPPED_PARAMS_PROPERTIES and * return an empty object if nothing is matched. */ -export const getMappedParams = (params: AlertTypeParams) => { +export const getMappedParams = (params: RuleTypeParams) => { return Object.entries(params).reduce((result, [key, value]) => { const snakeCaseKey = snakeCase(key); diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 901d7102f40c6..ac53486d279fd 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -22,25 +22,25 @@ import { } from '../../../../../src/core/server'; import { ActionsClient, ActionsAuthorization } from '../../../actions/server'; import { - Alert as Rule, - PartialAlert as PartialRule, + Rule, + PartialRule, RawRule, RuleTypeRegistry, - AlertAction as RuleAction, + RuleAction, IntervalSchedule, - SanitizedAlert as SanitizedRule, + SanitizedRule, RuleTaskState, AlertSummary, - AlertExecutionStatusValues as RuleExecutionStatusValues, - AlertNotifyWhenType as RuleNotifyWhenType, - AlertTypeParams as RuleTypeParams, + RuleExecutionStatusValues, + RuleNotifyWhenType, + RuleTypeParams, ResolvedSanitizedRule, - AlertWithLegacyId as RuleWithLegacyId, + RuleWithLegacyId, SanitizedRuleWithLegacyId, - PartialAlertWithLegacyId as PartialRuleWithLegacyId, + PartialRuleWithLegacyId, RawAlertInstance as RawAlert, } from '../types'; -import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getAlertNotifyWhenType } from '../lib'; +import { validateRuleTypeParams, ruleExecutionStatusFromRaw, getRuleNotifyWhenType } from '../lib'; import { GrantAPIKeyResult as SecurityPluginGrantAPIKeyResult, InvalidateAPIKeyResult as SecurityPluginInvalidateAPIKeyResult, @@ -89,13 +89,10 @@ import { formatExecutionLogResult, getExecutionLogAggregation, } from '../lib/get_execution_log_aggregation'; -import { IExecutionLogResult } from '../../common'; +import { IExecutionLogWithErrorsResult } from '../../common'; import { validateSnoozeDate } from '../lib/validate_snooze_date'; import { RuleMutedError } from '../lib/errors/rule_muted'; -import { - formatExecutionErrorsResult, - IExecutionErrorsResult, -} from '../lib/format_execution_log_errors'; +import { formatExecutionErrorsResult } from '../lib/format_execution_log_errors'; export interface RegistryAlertTypeWithAuth extends RegistryRuleType { authorizedConsumers: string[]; @@ -263,7 +260,6 @@ export interface GetExecutionLogByIdParams { sort: estypes.Sort; } -export type IExecutionLogWithErrorsResult = IExecutionLogResult & IExecutionErrorsResult; interface ScheduleRuleOptions { id: string; consumer: string; @@ -406,7 +402,7 @@ export class RulesClient { const createTime = Date.now(); const legacyId = Semver.lt(this.kibanaVersion, '8.0.0') ? id : null; - const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle); + const notifyWhen = getRuleNotifyWhenType(data.notifyWhen, data.throttle); const rawRule: RawRule = { ...data, @@ -1204,7 +1200,7 @@ export class RulesClient { } const apiKeyAttributes = this.apiKeyAsAlertAttributes(createdAPIKey, username); - const notifyWhen = getAlertNotifyWhenType(data.notifyWhen, data.throttle); + const notifyWhen = getRuleNotifyWhenType(data.notifyWhen, data.throttle); let updatedObject: SavedObject; const createAttributes = this.updateMeta({ 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 8a16bcb2d2fd7..df5f9252a98a0 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 @@ -96,185 +96,189 @@ const BaseRuleSavedObject: SavedObject = { const aggregateResults = { aggregations: { - executionUuid: { + excludeExecuteStart: { meta: {}, - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', - doc_count: 27, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + doc_count: 875, + executionUuid: { + meta: {}, + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '6705da7d-2635-499d-a6a8-1aee1ae1eac9', + doc_count: 27, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { + doc_count: 0, + }, }, - newAlerts: { - doc_count: 5, + }, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, }, - recoveredAlerts: { - doc_count: 0, + numScheduledActions: { + value: 5.0, }, - }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ - { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'S4wIZX8B8TGQpG7XQZns', - _score: 1.0, - _source: { - event: { - outcome: 'success', + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'S4wIZX8B8TGQpG7XQZns', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", }, + ], + }, + }, + scheduleDelay: { + value: 3.126e9, + }, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.056e9, + }, + executeStartTime: { + value: 1.646667512617e12, + value_as_string: '2022-03-07T15:38:32.617Z', + }, + }, + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.126e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.056e9, - }, - executeStartTime: { - value: 1.646667512617e12, - value_as_string: '2022-03-07T15:38:32.617Z', - }, }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', + { + key: '41b2755e-765a-4044-9745-b03875d5e79a', + doc_count: 32, + timeoutMessage: { + meta: {}, + doc_count: 0, + }, + alertCounts: { + meta: {}, + buckets: { + activeAlerts: { + doc_count: 5, + }, + newAlerts: { + doc_count: 5, + }, + recoveredAlerts: { doc_count: 5, }, - ], + }, }, - }, - }, - { - key: '41b2755e-765a-4044-9745-b03875d5e79a', - doc_count: 32, - timeoutMessage: { - meta: {}, - doc_count: 0, - }, - alertCounts: { - meta: {}, - buckets: { - activeAlerts: { - doc_count: 5, + ruleExecution: { + meta: {}, + doc_count: 1, + numTriggeredActions: { + value: 5.0, + }, + numScheduledActions: { + value: 5.0, + }, + outcomeAndMessage: { + hits: { + total: { + value: 1, + relation: 'eq', + }, + max_score: 1.0, + hits: [ + { + _index: '.kibana-event-log-8.2.0-000001', + _id: 'a4wIZX8B8TGQpG7Xwpnz', + _score: 1.0, + _source: { + event: { + outcome: 'success', + }, + message: + "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", + }, + }, + ], + }, }, - newAlerts: { - doc_count: 5, + scheduleDelay: { + value: 3.345e9, }, - recoveredAlerts: { - doc_count: 5, + totalSearchDuration: { + value: 0.0, + }, + esSearchDuration: { + value: 0.0, + }, + executionDuration: { + value: 1.165e9, + }, + executeStartTime: { + value: 1.646667545604e12, + value_as_string: '2022-03-07T15:39:05.604Z', }, }, - }, - ruleExecution: { - meta: {}, - doc_count: 1, - numTriggeredActions: { - value: 5.0, - }, - numScheduledActions: { - value: 5.0, - }, - outcomeAndMessage: { - hits: { - total: { - value: 1, - relation: 'eq', - }, - max_score: 1.0, - hits: [ + actionExecution: { + meta: {}, + doc_count: 5, + actionOutcomes: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ { - _index: '.kibana-event-log-8.2.0-000001', - _id: 'a4wIZX8B8TGQpG7Xwpnz', - _score: 1.0, - _source: { - event: { - outcome: 'success', - }, - message: - "rule executed: example.always-firing:a348a740-9e2c-11ec-bd64-774ed95c43ef: 'test rule'", - }, + key: 'success', + doc_count: 5, }, ], }, }, - scheduleDelay: { - value: 3.345e9, - }, - totalSearchDuration: { - value: 0.0, - }, - esSearchDuration: { - value: 0.0, - }, - executionDuration: { - value: 1.165e9, - }, - executeStartTime: { - value: 1.646667545604e12, - value_as_string: '2022-03-07T15:39:05.604Z', - }, - }, - actionExecution: { - meta: {}, - doc_count: 5, - actionOutcomes: { - doc_count_error_upper_bound: 0, - sum_other_doc_count: 0, - buckets: [ - { - key: 'success', - doc_count: 5, - }, - ], - }, }, - }, - ], - }, - executionUuidCardinality: { - value: 374, + ], + }, + executionUuidCardinality: { + value: 374, + }, }, }, }; diff --git a/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts b/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts index 50e6979d6ee72..ffed0e0b5efbc 100644 --- a/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts +++ b/x-pack/plugins/alerting/server/saved_objects/geo_containment/migrations.ts @@ -10,14 +10,14 @@ import { SavedObjectReference, SavedObjectUnsanitizedDoc, } from 'kibana/server'; -import { AlertTypeParams } from '../../index'; +import { RuleTypeParams } from '../../index'; import { Query } from '../../../../../../src/plugins/data/common/query'; import { RawRule } from '../../types'; // These definitions are dupes of the SO-types in stack_alerts/geo_containment // There are not exported to avoid deep imports from stack_alerts plugins into here const GEO_CONTAINMENT_ID = '.geo-containment'; -interface GeoContainmentParams extends AlertTypeParams { +interface GeoContainmentParams extends RuleTypeParams { index: string; indexId: string; geoField: string; diff --git a/x-pack/plugins/alerting/server/saved_objects/migrations.ts b/x-pack/plugins/alerting/server/saved_objects/migrations.ts index 0e3dc072366c2..91e03eb4da6c2 100644 --- a/x-pack/plugins/alerting/server/saved_objects/migrations.ts +++ b/x-pack/plugins/alerting/server/saved_objects/migrations.ts @@ -17,7 +17,7 @@ import { SavedObjectAttribute, SavedObjectReference, } from '../../../../../src/core/server'; -import { RawRule, RawAlertAction, RawRuleExecutionStatus } from '../types'; +import { RawRule, RawRuleAction, RawRuleExecutionStatus } from '../types'; import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server'; import type { IsMigrationNeededPredicate } from '../../../encrypted_saved_objects/server'; import { extractRefsFromGeoContainmentAlert } from './geo_containment/migrations'; @@ -353,7 +353,7 @@ function restructureConnectorsThatSupportIncident( }, }, }, - ] as RawAlertAction[]; + ] as RawRuleAction[]; } else if (action.actionTypeId === '.jira') { const { title, comments, description, issueType, priority, labels, parent, summary } = action.params.subActionParams as { @@ -385,7 +385,7 @@ function restructureConnectorsThatSupportIncident( }, }, }, - ] as RawAlertAction[]; + ] as RawRuleAction[]; } else if (action.actionTypeId === '.resilient') { const { title, comments, description, incidentTypes, severityCode, name } = action.params .subActionParams as { @@ -413,12 +413,12 @@ function restructureConnectorsThatSupportIncident( }, }, }, - ] as RawAlertAction[]; + ] as RawRuleAction[]; } } return [...acc, action]; - }, [] as RawAlertAction[]); + }, [] as RawRuleAction[]); return { ...doc, @@ -855,13 +855,13 @@ function addMappedParams( function getCorrespondingAction( actions: SavedObjectAttribute, connectorRef: string -): RawAlertAction | null { +): RawRuleAction | null { if (!Array.isArray(actions)) { return null; } else { return actions.find( - (action) => (action as RawAlertAction)?.actionRef === connectorRef - ) as RawAlertAction; + (action) => (action as RawRuleAction)?.actionRef === connectorRef + ) as RawRuleAction; } } diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts index ef48a701d0315..f5183e9e19dcc 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.test.ts @@ -8,9 +8,9 @@ import { ConcreteTaskInstance, TaskStatus } from '../../../task_manager/server'; import { AlertTaskInstance, taskInstanceToAlertTaskInstance } from './alert_task_instance'; import uuid from 'uuid'; -import { SanitizedAlert } from '../types'; +import { SanitizedRule } from '../types'; -const alert: SanitizedAlert<{ +const alert: SanitizedRule<{ bar: boolean; }> = { id: 'alert-123', diff --git a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts index a6bb6a68ceae8..fd61b37a277de 100644 --- a/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts +++ b/x-pack/plugins/alerting/server/task_runner/alert_task_instance.ts @@ -10,12 +10,12 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { fold } from 'fp-ts/lib/Either'; import { ConcreteTaskInstance } from '../../../task_manager/server'; import { - SanitizedAlert, + SanitizedRule, RuleTaskState, ruleParamsSchema, ruleStateSchema, RuleTaskParams, - AlertTypeParams, + RuleTypeParams, } from '../../common'; export interface AlertTaskInstance extends ConcreteTaskInstance { @@ -26,9 +26,9 @@ export interface AlertTaskInstance extends ConcreteTaskInstance { const enumerateErrorFields = (e: t.Errors) => `${e.map(({ context }) => context.map(({ key }) => key).join('.'))}`; -export function taskInstanceToAlertTaskInstance( +export function taskInstanceToAlertTaskInstance( taskInstance: ConcreteTaskInstance, - alert?: SanitizedAlert + alert?: SanitizedRule ): AlertTaskInstance { return { ...taskInstance, diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts index 8b97bf9266e9a..af0220ccba987 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.test.ts @@ -18,21 +18,16 @@ import { KibanaRequest } from 'kibana/server'; import { asSavedObjectExecutionSource } from '../../../actions/server'; import { InjectActionParamsOpts } from './inject_action_params'; import { NormalizedRuleType } from '../rule_type_registry'; -import { - AlertInstanceContext, - AlertInstanceState, - AlertTypeParams, - AlertTypeState, -} from '../types'; +import { AlertInstanceContext, AlertInstanceState, RuleTypeParams, RuleTypeState } from '../types'; jest.mock('./inject_action_params', () => ({ injectActionParams: jest.fn(), })); const ruleType: NormalizedRuleType< - AlertTypeParams, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, 'default' | 'other-group', @@ -66,9 +61,9 @@ const mockActionsPlugin = actionsMock.createStart(); const mockEventLogger = eventLoggerMock.create(); const createExecutionHandlerParams: jest.Mocked< CreateExecutionHandlerOptions< - AlertTypeParams, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, 'default' | 'other-group', diff --git a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts index 56e1a25cb0655..7752817f17c85 100644 --- a/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts +++ b/x-pack/plugins/alerting/server/task_runner/create_execution_handler.ts @@ -9,12 +9,7 @@ import { asSavedObjectExecutionSource } from '../../../actions/server'; import { SAVED_OBJECT_REL_PRIMARY } from '../../../event_log/server'; import { EVENT_LOG_ACTIONS } from '../plugin'; import { injectActionParams } from './inject_action_params'; -import { - AlertInstanceContext, - AlertInstanceState, - AlertTypeParams, - AlertTypeState, -} from '../types'; +import { AlertInstanceContext, AlertInstanceState, RuleTypeParams, RuleTypeState } from '../types'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { isEphemeralTaskRejectedDueToCapacityError } from '../../../task_manager/server'; @@ -26,9 +21,9 @@ export type ExecutionHandler = ( ) => Promise; export function createExecutionHandler< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, diff --git a/x-pack/plugins/alerting/server/task_runner/fixtures.ts b/x-pack/plugins/alerting/server/task_runner/fixtures.ts index 1c8e1776a523f..613f3ed9e1645 100644 --- a/x-pack/plugins/alerting/server/task_runner/fixtures.ts +++ b/x-pack/plugins/alerting/server/task_runner/fixtures.ts @@ -7,9 +7,9 @@ import { isNil } from 'lodash'; import { - Alert, - AlertExecutionStatusWarningReasons, - AlertTypeParams, + Rule, + RuleExecutionStatusWarningReasons, + RuleTypeParams, RecoveredActionGroup, } from '../../common'; import { getDefaultRuleMonitoring } from './task_runner'; @@ -121,7 +121,7 @@ export const mockRunNowResponse = { export const mockDate = new Date('2019-02-12T21:01:22.479Z'); -export const mockedRuleTypeSavedObject: Alert = { +export const mockedRuleTypeSavedObject: Rule = { id: '1', consumer: 'bar', createdAt: mockDate, @@ -335,7 +335,7 @@ const generateMessage = ({ } if ( status === 'warning' && - reason === AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS + reason === RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS ) { return `The maximum number of actions for this rule type was reached; excess actions were not triggered.`; } diff --git a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts index 11ac3f92d1071..f2a41038e257e 100644 --- a/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts +++ b/x-pack/plugins/alerting/server/task_runner/inject_action_params.ts @@ -6,13 +6,13 @@ */ import { i18n } from '@kbn/i18n'; -import { AlertActionParams } from '../types'; +import { RuleActionParams } from '../types'; export interface InjectActionParamsOpts { ruleId: string; spaceId: string | undefined; actionTypeId: string; - actionParams: AlertActionParams; + actionParams: RuleActionParams; } export function injectActionParams({ 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 c261b4ddbba25..21109b60e012d 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 @@ -9,12 +9,12 @@ import sinon from 'sinon'; import { schema } from '@kbn/config-schema'; import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; import { - AlertExecutorOptions, - AlertTypeParams, - AlertTypeState, + RuleExecutorOptions, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, - AlertExecutionStatusWarningReasons, + RuleExecutionStatusWarningReasons, } from '../types'; import { ConcreteTaskInstance, @@ -96,7 +96,7 @@ describe('Task Runner', () => { afterAll(() => fakeTimer.restore()); const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); - const services = alertsMock.createAlertServices(); + const services = alertsMock.createRuleExecutorServices(); const actionsClient = actionsClientMock.create(); const rulesClient = rulesClientMock.create(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -282,9 +282,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -386,9 +386,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -499,9 +499,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -550,9 +550,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -607,9 +607,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -667,9 +667,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -707,9 +707,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -797,9 +797,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -865,9 +865,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -940,9 +940,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1057,9 +1057,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1210,9 +1210,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1294,9 +1294,9 @@ describe('Task Runner', () => { ruleTypeWithCustomRecovery.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1356,9 +1356,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1567,9 +1567,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1806,9 +1806,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -1957,9 +1957,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2065,9 +2065,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2169,9 +2169,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2349,9 +2349,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2578,9 +2578,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2608,9 +2608,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2652,7 +2652,7 @@ describe('Task Runner', () => { }; const warning = { - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, message: translations.taskRunner.warning.maxExecutableActions, }; @@ -2662,9 +2662,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -2820,7 +2820,7 @@ describe('Task Runner', () => { status: 'warning', numberOfTriggeredActions: ruleTypeWithConfig.config.execution.actions.max, numberOfScheduledActions: mockActions.length, - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, task: true, consumer: 'bar', }) @@ -2852,9 +2852,9 @@ describe('Task Runner', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string 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 0e69131711067..36c8bddb1ff82 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -14,7 +14,7 @@ import { KibanaRequest, Logger } from '../../../../../src/core/server'; import { TaskRunnerContext } from './task_runner_factory'; import { ConcreteTaskInstance, throwUnrecoverableError } from '../../../task_manager/server'; import { createExecutionHandler, ExecutionHandler } from './create_execution_handler'; -import { Alert as CreatedAlert, createAlertFactory } from '../alert'; +import { Alert, createAlertFactory } from '../alert'; import { createWrappedScopedClusterClientFactory, ElasticsearchError, @@ -26,9 +26,9 @@ import { validateRuleTypeParams, } from '../lib'; import { - Alert, - AlertExecutionStatus, - AlertExecutionStatusErrorReasons, + Rule, + RuleExecutionStatus, + RuleExecutionStatusErrorReasons, IntervalSchedule, RawAlertInstance, RawRule, @@ -39,7 +39,7 @@ import { RuleMonitoringHistory, RuleTaskState, RuleTypeRegistry, - SanitizedAlert, + SanitizedRule, } from '../types'; import { asErr, asOk, map, promiseResult, resolveErr, Resultable } from '../lib/result_type'; import { getExecutionDurationPercentiles, getExecutionSuccessRatio } from '../lib/monitoring'; @@ -51,8 +51,8 @@ import { partiallyUpdateAlert } from '../saved_objects'; import { AlertInstanceContext, AlertInstanceState, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, MONITORING_HISTORY_LIMIT, parseDuration, WithoutReservedActionGroups, @@ -91,9 +91,9 @@ export const getDefaultRuleMonitoring = (): RuleMonitoring => ({ }); export class TaskRunner< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, @@ -201,7 +201,7 @@ export class TaskRunner< spaceId: string, apiKey: RawRule['apiKey'], kibanaBaseUrl: string | undefined, - actions: Alert['actions'], + actions: Rule['actions'], ruleParams: Params, request: KibanaRequest ) { @@ -252,7 +252,7 @@ export class TaskRunner< } } - private isRuleSnoozed(rule: SanitizedAlert): boolean { + private isRuleSnoozed(rule: SanitizedRule): boolean { if (rule.muteAll) { return true; } @@ -288,7 +288,7 @@ export class TaskRunner< private async executeAlert( alertId: string, - alert: CreatedAlert, + alert: Alert, executionHandler: ExecutionHandler, alertExecutionStore: AlertExecutionStore ) { @@ -312,7 +312,7 @@ export class TaskRunner< private async executeAlerts( fakeRequest: KibanaRequest, - rule: SanitizedAlert, + rule: SanitizedRule, params: Params, executionHandler: ExecutionHandler, spaceId: string, @@ -343,10 +343,10 @@ export class TaskRunner< const alerts = mapValues< Record, - CreatedAlert + Alert >( alertRawInstances, - (rawAlert, alertId) => new CreatedAlert(alertId, rawAlert) + (rawAlert, alertId) => new Alert(alertId, rawAlert) ); const originalAlerts = cloneDeep(alerts); @@ -440,7 +440,7 @@ export class TaskRunner< event.event = event.event || {}; event.event.outcome = 'failure'; - throw new ErrorWithReason(AlertExecutionStatusErrorReasons.Execute, err); + throw new ErrorWithReason(RuleExecutionStatusErrorReasons.Execute, err); } event.message = `rule executed: ${ruleLabel}`; @@ -456,7 +456,7 @@ export class TaskRunner< // Cleanup alerts that are no longer scheduling actions to avoid over populating the alertInstances object const alertsWithScheduledActions = pickBy( alerts, - (alert: CreatedAlert) => alert.hasScheduledActions() + (alert: Alert) => alert.hasScheduledActions() ); const recoveredAlerts = getRecoveredAlerts(alerts, originalAlertIds); @@ -502,7 +502,7 @@ export class TaskRunner< const mutedAlertIdsSet = new Set(mutedInstanceIds); const alertsWithExecutableActions = Object.entries(alertsWithScheduledActions).filter( - ([alertName, alert]: [string, CreatedAlert]) => { + ([alertName, alert]: [string, Alert]) => { const throttled = alert.isThrottled(throttle); const muted = mutedAlertIdsSet.has(alertName); let shouldExecuteAction = true; @@ -530,7 +530,7 @@ export class TaskRunner< await Promise.all( alertsWithExecutableActions.map( - ([alertId, alert]: [string, CreatedAlert]) => + ([alertId, alert]: [string, Alert]) => this.executeAlert(alertId, alert, executionHandler, alertExecutionStore) ) ); @@ -570,7 +570,7 @@ export class TaskRunner< alertExecutionStore, alertTypeState: updatedRuleTypeState || undefined, alertInstances: mapValues< - Record>, + Record>, RawAlertInstance >(alertsWithScheduledActions, (alert) => alert.toRaw()), }; @@ -579,7 +579,7 @@ export class TaskRunner< private async validateAndExecuteRule( fakeRequest: KibanaRequest, apiKey: RawRule['apiKey'], - rule: SanitizedAlert, + rule: SanitizedRule, event: Event ) { const { @@ -617,14 +617,14 @@ export class TaskRunner< enabled = decryptedAttributes.enabled; consumer = decryptedAttributes.consumer; } catch (err) { - throw new ErrorWithReason(AlertExecutionStatusErrorReasons.Decrypt, err); + throw new ErrorWithReason(RuleExecutionStatusErrorReasons.Decrypt, err); } this.ruleConsumer = consumer; if (!enabled) { throw new ErrorWithReason( - AlertExecutionStatusErrorReasons.Disabled, + RuleExecutionStatusErrorReasons.Disabled, new Error(`Rule failed to execute because rule ran after it was disabled.`) ); } @@ -634,7 +634,7 @@ export class TaskRunner< // Get rules client with space level permissions const rulesClient = this.context.getRulesClientWithRequest(fakeRequest); - let rule: SanitizedAlert; + let rule: SanitizedRule; // Ensure API key is still valid and user has access try { @@ -651,7 +651,7 @@ export class TaskRunner< }); } } catch (err) { - throw new ErrorWithReason(AlertExecutionStatusErrorReasons.Read, err); + throw new ErrorWithReason(RuleExecutionStatusErrorReasons.Read, err); } this.ruleName = rule.name; @@ -659,7 +659,7 @@ export class TaskRunner< try { this.ruleTypeRegistry.ensureRuleTypeEnabled(rule.alertTypeId); } catch (err) { - throw new ErrorWithReason(AlertExecutionStatusErrorReasons.License, err); + throw new ErrorWithReason(RuleExecutionStatusErrorReasons.License, err); } if (rule.monitoring) { @@ -760,7 +760,7 @@ export class TaskRunner< return getDefaultRuleMonitoring(); }) ?? getDefaultRuleMonitoring(); - const executionStatus = map( + const executionStatus = map( state, (ruleExecutionState) => executionStatusFromState(ruleExecutionState), (err: ElasticsearchError) => executionStatusFromError(err) @@ -992,11 +992,11 @@ export class TaskRunner< this.inMemoryMetrics.increment(IN_MEMORY_METRICS.RULE_TIMEOUTS); // Update the rule saved object with execution status - const executionStatus: AlertExecutionStatus = { + const executionStatus: RuleExecutionStatus = { lastExecutionDate: new Date(), status: 'error', error: { - reason: AlertExecutionStatusErrorReasons.Timeout, + reason: RuleExecutionStatusErrorReasons.Timeout, message: `${this.ruleType.id}:${ruleId}: execution cancelled due to timeout - exceeded rule type timeout of ${this.ruleType.ruleTaskTimeout}`, }, }; 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 68c005cc4b765..1e24ac986f015 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 @@ -8,9 +8,9 @@ import sinon from 'sinon'; import { usageCountersServiceMock } from 'src/plugins/usage_collection/server/usage_counters/usage_counters_service.mock'; import { - AlertExecutorOptions, - AlertTypeParams, - AlertTypeState, + RuleExecutorOptions, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, } from '../types'; @@ -32,7 +32,7 @@ import { actionsMock, actionsClientMock } from '../../../actions/server/mocks'; import { alertsMock, rulesClientMock } from '../mocks'; import { eventLoggerMock } from '../../../event_log/server/event_logger.mock'; import { IEventLogger } from '../../../event_log/server'; -import { Alert, RecoveredActionGroup } from '../../common'; +import { Rule, RecoveredActionGroup } from '../../common'; import { UntypedNormalizedRuleType } from '../rule_type_registry'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { dataPluginMock } from '../../../../../src/plugins/data/server/mocks'; @@ -98,7 +98,7 @@ describe('Task Runner Cancel', () => { afterAll(() => fakeTimer.restore()); const encryptedSavedObjectsClient = encryptedSavedObjectsMock.createClient(); - const services = alertsMock.createAlertServices(); + const services = alertsMock.createRuleExecutorServices(); const actionsClient = actionsClientMock.create(); const rulesClient = rulesClientMock.create(); const ruleTypeRegistry = ruleTypeRegistryMock.create(); @@ -138,7 +138,7 @@ describe('Task Runner Cancel', () => { const mockDate = new Date('2019-02-12T21:01:22.479Z'); - const mockedRuleSavedObject: Alert = { + const mockedRuleSavedObject: Rule = { id: '1', consumer: 'bar', createdAt: mockDate, @@ -402,9 +402,9 @@ describe('Task Runner Cancel', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -441,9 +441,9 @@ describe('Task Runner Cancel', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string @@ -476,9 +476,9 @@ describe('Task Runner Cancel', () => { ruleType.executor.mockImplementation( async ({ services: executorServices, - }: AlertExecutorOptions< - AlertTypeParams, - AlertTypeState, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, string diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts index 0ceced10e799b..2cba16152e198 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.ts @@ -21,10 +21,10 @@ import { RunContext } from '../../../task_manager/server'; import { EncryptedSavedObjectsClient } from '../../../encrypted_saved_objects/server'; import { PluginStartContract as ActionsPluginStartContract } from '../../../actions/server'; import { - AlertTypeParams, + RuleTypeParams, RuleTypeRegistry, SpaceIdToNamespaceFunction, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, } from '../types'; @@ -70,9 +70,9 @@ export class TaskRunnerFactory { } public create< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, diff --git a/x-pack/plugins/alerting/server/task_runner/transform_action_params.ts b/x-pack/plugins/alerting/server/task_runner/transform_action_params.ts index 3f9fe9e9c59e0..387bdc00125f0 100644 --- a/x-pack/plugins/alerting/server/task_runner/transform_action_params.ts +++ b/x-pack/plugins/alerting/server/task_runner/transform_action_params.ts @@ -6,10 +6,10 @@ */ import { - AlertActionParams, + RuleActionParams, AlertInstanceState, AlertInstanceContext, - AlertTypeParams, + RuleTypeParams, } from '../types'; import { PluginStartContract as ActionsPluginStartContract } from '../../../actions/server'; @@ -26,8 +26,8 @@ interface TransformActionParamsOptions { alertActionGroup: string; alertActionGroupName: string; alertActionSubgroup?: string; - actionParams: AlertActionParams; - alertParams: AlertTypeParams; + actionParams: RuleActionParams; + alertParams: RuleTypeParams; state: AlertInstanceState; kibanaBaseUrl?: string; context: AlertInstanceContext; @@ -51,7 +51,7 @@ export function transformActionParams({ state, kibanaBaseUrl, alertParams, -}: TransformActionParamsOptions): AlertActionParams { +}: TransformActionParamsOptions): RuleActionParams { // when the list of variables we pass in here changes, // the UI will need to be updated as well; see: // x-pack/plugins/triggers_actions_ui/public/application/lib/action_variables.ts diff --git a/x-pack/plugins/alerting/server/task_runner/types.ts b/x-pack/plugins/alerting/server/task_runner/types.ts index d8483139a92b9..d5ad11f246c49 100644 --- a/x-pack/plugins/alerting/server/task_runner/types.ts +++ b/x-pack/plugins/alerting/server/task_runner/types.ts @@ -9,19 +9,19 @@ import { Dictionary } from 'lodash'; import { KibanaRequest, Logger } from 'kibana/server'; import { ActionGroup, - AlertAction, + RuleAction, AlertInstanceContext, AlertInstanceState, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, IntervalSchedule, RuleExecutionState, RuleMonitoring, RuleTaskState, - SanitizedAlert, + SanitizedRule, } from '../../common'; import { ConcreteTaskInstance } from '../../../task_manager/server'; -import { Alert as CreatedAlert } from '../alert'; +import { Alert } from '../alert'; import { IEventLogger } from '../../../event_log/server'; import { NormalizedRuleType } from '../rule_type_registry'; import { ExecutionHandler } from './create_execution_handler'; @@ -48,9 +48,9 @@ export interface TrackAlertDurationsParams< InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext > { - originalAlerts: Dictionary>; - currentAlerts: Dictionary>; - recoveredAlerts: Dictionary>; + originalAlerts: Dictionary>; + currentAlerts: Dictionary>; + recoveredAlerts: Dictionary>; } export interface GenerateNewAndRecoveredAlertEventsParams< @@ -59,16 +59,16 @@ export interface GenerateNewAndRecoveredAlertEventsParams< > { eventLogger: IEventLogger; executionId: string; - originalAlerts: Dictionary>; - currentAlerts: Dictionary>; - recoveredAlerts: Dictionary>; + originalAlerts: Dictionary>; + currentAlerts: Dictionary>; + recoveredAlerts: Dictionary>; ruleId: string; ruleLabel: string; namespace: string | undefined; ruleType: NormalizedRuleType< - AlertTypeParams, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeParams, + RuleTypeState, { [x: string]: unknown; }, @@ -78,7 +78,7 @@ export interface GenerateNewAndRecoveredAlertEventsParams< string, string >; - rule: SanitizedAlert; + rule: SanitizedRule; spaceId: string; } @@ -89,7 +89,7 @@ export interface ScheduleActionsForRecoveredAlertsParams< > { logger: Logger; recoveryActionGroup: ActionGroup; - recoveredAlerts: Dictionary>; + recoveredAlerts: Dictionary>; executionHandler: ExecutionHandler; mutedAlertIdsSet: Set; ruleLabel: string; @@ -103,8 +103,8 @@ export interface LogActiveAndRecoveredAlertsParams< RecoveryActionGroupId extends string > { logger: Logger; - activeAlerts: Dictionary>; - recoveredAlerts: Dictionary>; + activeAlerts: Dictionary>; + recoveredAlerts: Dictionary>; ruleLabel: string; canSetRecoveryContext: boolean; } @@ -112,9 +112,9 @@ export interface LogActiveAndRecoveredAlertsParams< // / ExecutionHandler export interface CreateExecutionHandlerOptions< - Params extends AlertTypeParams, - ExtractedParams extends AlertTypeParams, - State extends AlertTypeState, + Params extends RuleTypeParams, + ExtractedParams extends RuleTypeParams, + State extends RuleTypeState, InstanceState extends AlertInstanceState, InstanceContext extends AlertInstanceContext, ActionGroupIds extends string, @@ -126,7 +126,7 @@ export interface CreateExecutionHandlerOptions< executionId: string; tags?: string[]; actionsPlugin: ActionsPluginStartContract; - actions: AlertAction[]; + actions: RuleAction[]; spaceId: string; apiKey: RawRule['apiKey']; kibanaBaseUrl: string | undefined; @@ -142,7 +142,7 @@ export interface CreateExecutionHandlerOptions< logger: Logger; eventLogger: IEventLogger; request: KibanaRequest; - ruleParams: AlertTypeParams; + ruleParams: RuleTypeParams; supportsEphemeralTasks: boolean; maxEphemeralActionsPerRule: number; } diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index 10d191d9b43e4..cfd03f4edf184 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -23,23 +23,23 @@ import { SavedObjectsClientContract, } from '../../../../src/core/server'; import { - Alert, - AlertActionParams, + Rule, + RuleTypeParams, + RuleTypeState, + RuleActionParams, + RuleExecutionStatuses, + RuleExecutionStatusErrorReasons, + RuleExecutionStatusWarningReasons, + RuleNotifyWhenType, ActionGroup, - AlertTypeParams, - AlertTypeState, AlertInstanceContext, AlertInstanceState, - AlertExecutionStatuses, - AlertExecutionStatusErrorReasons, AlertsHealth, - AlertNotifyWhenType, WithoutReservedActionGroups, ActionVariable, SanitizedRuleConfig, RuleMonitoring, MappedParams, - AlertExecutionStatusWarningReasons, } from '../common'; import { LicenseType } from '../../licensing/server'; import { ISearchStartSearchSource } from '../../../../src/plugins/data/common'; @@ -69,7 +69,7 @@ export interface AlertingRequestHandlerContext extends RequestHandlerContext { */ export type AlertingRouter = IRouter; -export interface AlertServices< +export interface RuleExecutorServices< InstanceState extends AlertInstanceState = AlertInstanceState, InstanceContext extends AlertInstanceContext = AlertInstanceContext, ActionGroupIds extends string = never @@ -86,9 +86,9 @@ export interface AlertServices< shouldStopExecution: () => boolean; } -export interface AlertExecutorOptions< - Params extends AlertTypeParams = never, - State extends AlertTypeState = never, +export interface RuleExecutorOptions< + Params extends RuleTypeParams = never, + State extends RuleTypeState = never, InstanceState extends AlertInstanceState = never, InstanceContext extends AlertInstanceContext = never, ActionGroupIds extends string = never @@ -97,7 +97,7 @@ export interface AlertExecutorOptions< executionId: string; startedAt: Date; previousStartedAt: Date | null; - services: AlertServices; + services: RuleExecutorServices; params: Params; state: State; rule: SanitizedRuleConfig; @@ -109,29 +109,29 @@ export interface AlertExecutorOptions< updatedBy: string | null; } -export interface RuleParamsAndRefs { +export interface RuleParamsAndRefs { references: SavedObjectReference[]; params: Params; } export type ExecutorType< - Params extends AlertTypeParams = never, - State extends AlertTypeState = never, + Params extends RuleTypeParams = never, + State extends RuleTypeState = never, InstanceState extends AlertInstanceState = never, InstanceContext extends AlertInstanceContext = never, ActionGroupIds extends string = never > = ( - options: AlertExecutorOptions + options: RuleExecutorOptions ) => Promise; -export interface AlertTypeParamsValidator { +export interface RuleTypeParamsValidator { validate: (object: unknown) => Params; } export interface RuleType< - Params extends AlertTypeParams = never, - ExtractedParams extends AlertTypeParams = never, - State extends AlertTypeState = never, + Params extends RuleTypeParams = never, + ExtractedParams extends RuleTypeParams = never, + State extends RuleTypeState = never, InstanceState extends AlertInstanceState = never, InstanceContext extends AlertInstanceContext = never, ActionGroupIds extends string = never, @@ -140,7 +140,7 @@ export interface RuleType< id: string; name: string; validate?: { - params?: AlertTypeParamsValidator; + params?: RuleTypeParamsValidator; }; actionGroups: Array>; defaultActionGroupId: ActionGroup['id']; @@ -175,57 +175,57 @@ export interface RuleType< config?: RuleTypeConfig; } export type UntypedRuleType = RuleType< - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext >; -export interface RawAlertAction extends SavedObjectAttributes { +export interface RawRuleAction extends SavedObjectAttributes { group: string; actionRef: string; actionTypeId: string; - params: AlertActionParams; + params: RuleActionParams; } -export interface AlertMeta extends SavedObjectAttributes { +export interface RuleMeta extends SavedObjectAttributes { versionApiKeyLastmodified?: string; } // note that the `error` property is "null-able", as we're doing a partial -// update on the alert when we update this data, but need to ensure we +// update on the rule when we update this data, but need to ensure we // delete any previous error if the current status has no error export interface RawRuleExecutionStatus extends SavedObjectAttributes { - status: AlertExecutionStatuses; + status: RuleExecutionStatuses; lastExecutionDate: string; lastDuration?: number; error: null | { - reason: AlertExecutionStatusErrorReasons; + reason: RuleExecutionStatusErrorReasons; message: string; }; warning: null | { - reason: AlertExecutionStatusWarningReasons; + reason: RuleExecutionStatusWarningReasons; message: string; }; } -export type PartialAlert = Pick, 'id'> & - Partial, 'id'>>; +export type PartialRule = Pick, 'id'> & + Partial, 'id'>>; -export interface AlertWithLegacyId extends Alert { +export interface RuleWithLegacyId extends Rule { legacyId: string | null; } -export type SanitizedRuleWithLegacyId = Omit< - AlertWithLegacyId, +export type SanitizedRuleWithLegacyId = Omit< + RuleWithLegacyId, 'apiKey' >; -export type PartialAlertWithLegacyId = Pick< - AlertWithLegacyId, +export type PartialRuleWithLegacyId = Pick< + RuleWithLegacyId, 'id' > & - Partial, 'id'>>; + Partial, 'id'>>; export interface RawRule extends SavedObjectAttributes { enabled: boolean; @@ -235,7 +235,7 @@ export interface RawRule extends SavedObjectAttributes { consumer: string; legacyId: string | null; schedule: SavedObjectAttributes; - actions: RawAlertAction[]; + actions: RawRuleAction[]; params: SavedObjectAttributes; mapped_params?: MappedParams; scheduledTaskId?: string | null; @@ -246,28 +246,15 @@ export interface RawRule extends SavedObjectAttributes { apiKey: string | null; apiKeyOwner: string | null; throttle: string | null; - notifyWhen: AlertNotifyWhenType | null; + notifyWhen: RuleNotifyWhenType | null; muteAll: boolean; mutedInstanceIds: string[]; - meta?: AlertMeta; + meta?: RuleMeta; executionStatus: RawRuleExecutionStatus; monitoring?: RuleMonitoring; snoozeEndTime?: string | null; // Remove ? when this parameter is made available in the public API } -export type AlertInfoParams = Pick< - RawRule, - | 'params' - | 'throttle' - | 'notifyWhen' - | 'muteAll' - | 'mutedInstanceIds' - | 'name' - | 'tags' - | 'createdBy' - | 'updatedBy' ->; - export interface AlertingPlugin { setup: PluginSetupContract; start: PluginStartContract; diff --git a/x-pack/plugins/alerting/server/usage/alerting_telemetry.test.ts b/x-pack/plugins/alerting/server/usage/alerting_telemetry.test.ts index 3bb64ad00a194..61383656e67d5 100644 --- a/x-pack/plugins/alerting/server/usage/alerting_telemetry.test.ts +++ b/x-pack/plugins/alerting/server/usage/alerting_telemetry.test.ts @@ -15,6 +15,7 @@ import { getExecutionsPerDayCount, getExecutionTimeoutsPerDayCount, getFailedAndUnrecognizedTasksPerDay, + parsePercentileAggsByRuleType, } from './alerting_telemetry'; describe('alerting telemetry', () => { @@ -181,6 +182,41 @@ Object { avgTotalSearchDuration: { value: 30.642857142857142, }, + percentileScheduledActions: { + values: { + '50.0': 4.0, + '90.0': 26.0, + '99.0': 26.0, + }, + }, + aggsByType: { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.index-threshold', + doc_count: 149, + percentileScheduledActions: { + values: { + '50.0': 4.0, + '90.0': 26.0, + '99.0': 26.0, + }, + }, + }, + { + key: 'logs.alert.document.count', + doc_count: 1, + percentileScheduledActions: { + values: { + '50.0': 10.0, + '90.0': 10.0, + '99.0': 10.0, + }, + }, + }, + ], + }, }, hits: { hits: [], @@ -228,6 +264,25 @@ Object { }, countTotal: 4, countTotalFailures: 4, + scheduledActionsPercentiles: { + p50: 4, + p90: 26, + p99: 26, + }, + scheduledActionsPercentilesByType: { + p50: { + '__index-threshold': 4, + logs__alert__document__count: 10, + }, + p90: { + '__index-threshold': 26, + logs__alert__document__count: 10, + }, + p99: { + '__index-threshold': 26, + logs__alert__document__count: 10, + }, + }, }); }); @@ -316,4 +371,150 @@ Object { countTotal: 5, }); }); + + test('parsePercentileAggsByRuleType', () => { + const aggsByType = { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.index-threshold', + doc_count: 149, + percentileScheduledActions: { + values: { + '50.0': 4.0, + '90.0': 26.0, + '99.0': 26.0, + }, + }, + }, + { + key: 'logs.alert.document.count', + doc_count: 1, + percentileScheduledActions: { + values: { + '50.0': 10.0, + '90.0': 10.0, + '99.0': 10.0, + }, + }, + }, + { + key: 'document.test.', + doc_count: 1, + percentileScheduledActions: { + values: { + '50.0': null, + '90.0': null, + '99.0': null, + }, + }, + }, + ], + }; + expect( + parsePercentileAggsByRuleType(aggsByType.buckets, 'percentileScheduledActions.values') + ).toEqual({ + p50: { + '__index-threshold': 4, + document__test__: 0, + logs__alert__document__count: 10, + }, + p90: { + '__index-threshold': 26, + document__test__: 0, + logs__alert__document__count: 10, + }, + p99: { + '__index-threshold': 26, + document__test__: 0, + logs__alert__document__count: 10, + }, + }); + }); + + test('parsePercentileAggsByRuleType handles unknown path', () => { + const aggsByType = { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.index-threshold', + doc_count: 149, + percentileScheduledActions: { + values: { + '50.0': 4.0, + '90.0': 26.0, + '99.0': 26.0, + }, + }, + }, + { + key: 'logs.alert.document.count', + doc_count: 1, + percentileScheduledActions: { + values: { + '50.0': 10.0, + '90.0': 10.0, + '99.0': 10.0, + }, + }, + }, + ], + }; + expect(parsePercentileAggsByRuleType(aggsByType.buckets, 'foo.values')).toEqual({ + p50: {}, + p90: {}, + p99: {}, + }); + }); + + test('parsePercentileAggsByRuleType handles unrecognized percentiles', () => { + const aggsByType = { + doc_count_error_upper_bound: 0, + sum_other_doc_count: 0, + buckets: [ + { + key: '.index-threshold', + doc_count: 149, + percentileScheduledActions: { + values: { + '50.0': 4.0, + '75.0': 8.0, + '90.0': 26.0, + '99.0': 26.0, + }, + }, + }, + { + key: 'logs.alert.document.count', + doc_count: 1, + percentileScheduledActions: { + values: { + '50.0': 10.0, + '75.0': 10.0, + '90.0': 10.0, + '99.0': 10.0, + }, + }, + }, + ], + }; + expect( + parsePercentileAggsByRuleType(aggsByType.buckets, 'percentileScheduledActions.values') + ).toEqual({ + p50: { + '__index-threshold': 4, + logs__alert__document__count: 10, + }, + p90: { + '__index-threshold': 26, + logs__alert__document__count: 10, + }, + p99: { + '__index-threshold': 26, + logs__alert__document__count: 10, + }, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/usage/alerting_telemetry.ts b/x-pack/plugins/alerting/server/usage/alerting_telemetry.ts index 4fbad593d1600..2e360374faa42 100644 --- a/x-pack/plugins/alerting/server/usage/alerting_telemetry.ts +++ b/x-pack/plugins/alerting/server/usage/alerting_telemetry.ts @@ -5,8 +5,17 @@ * 2.0. */ +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ElasticsearchClient } from 'kibana/server'; +import { get, merge } from 'lodash'; import { AlertingUsage } from './types'; +import { NUM_ALERTING_RULE_TYPES } from './alerting_usage_collector'; + +const percentileFieldNameMapping: Record = { + '50.0': 'p50', + '90.0': 'p90', + '99.0': 'p99', +}; const ruleTypeMetric = { scripted_metric: { @@ -38,6 +47,13 @@ const ruleTypeMetric = { }, }; +const scheduledActionsPercentilesAgg = { + percentiles: { + field: 'kibana.alert.rule.execution.metrics.number_of_scheduled_actions', + percents: [50, 90, 99], + }, +}; + const ruleTypeExecutionsWithDurationMetric = { scripted_metric: { init_script: @@ -409,6 +425,16 @@ export async function getExecutionsPerDayCount( avgTotalSearchDuration: { avg: { field: 'kibana.alert.rule.execution.metrics.total_search_duration_ms' }, }, + percentileScheduledActions: scheduledActionsPercentilesAgg, + aggsByType: { + terms: { + field: 'rule.category', + size: NUM_ALERTING_RULE_TYPES, + }, + aggs: { + percentileScheduledActions: scheduledActionsPercentilesAgg, + }, + }, }, }, }); @@ -439,6 +465,14 @@ export async function getExecutionsPerDayCount( searchResult.aggregations.avgTotalSearchDuration.value ); + const aggsScheduledActionsPercentiles = + // @ts-expect-error aggegation type is not specified + searchResult.aggregations.percentileScheduledActions.values; + + const aggsByTypeBuckets = + // @ts-expect-error aggegation type is not specified + searchResult.aggregations.aggsByType.buckets; + const executionFailuresAggregations = searchResult.aggregations as { failuresByReason: { value: { reasons: Record> } }; }; @@ -537,6 +571,21 @@ export async function getExecutionsPerDayCount( }), {} ), + scheduledActionsPercentiles: Object.keys(aggsScheduledActionsPercentiles).reduce( + // ES DSL aggregations are returned as `any` by esClient.search + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (acc: any, curr: string) => ({ + ...acc, + ...(percentileFieldNameMapping[curr] + ? { [percentileFieldNameMapping[curr]]: aggsScheduledActionsPercentiles[curr] } + : {}), + }), + {} + ), + scheduledActionsPercentilesByType: parsePercentileAggsByRuleType( + aggsByTypeBuckets, + 'percentileScheduledActions.values' + ), }; } @@ -701,3 +750,30 @@ function replaceDotSymbolsInRuleTypeIds(ruleTypeIdObj: Record) { {} ); } + +export function parsePercentileAggsByRuleType( + aggsByType: estypes.AggregationsStringTermsBucketKeys[], + path: string +) { + return (aggsByType ?? []).reduce( + (acc, curr) => { + const percentiles = get(curr, path, {}); + return merge( + acc, + Object.keys(percentiles).reduce((pacc, pcurr) => { + return { + ...pacc, + ...(percentileFieldNameMapping[pcurr] + ? { + [percentileFieldNameMapping[pcurr]]: { + [replaceDotSymbols(curr.key)]: percentiles[pcurr] ?? 0, + }, + } + : {}), + }; + }, {}) + ); + }, + { p50: {}, p90: {}, p99: {} } + ); +} diff --git a/x-pack/plugins/alerting/server/usage/alerting_usage_collector.ts b/x-pack/plugins/alerting/server/usage/alerting_usage_collector.ts index f375e758a8c9b..b0990bab9491d 100644 --- a/x-pack/plugins/alerting/server/usage/alerting_usage_collector.ts +++ b/x-pack/plugins/alerting/server/usage/alerting_usage_collector.ts @@ -56,6 +56,8 @@ const byTypeSchema: MakeSchemaFrom['count_by_type'] = { xpack__ml__anomaly_detection_jobs_health: { type: 'long' }, // eslint-disable-line @typescript-eslint/naming-convention }; +export const NUM_ALERTING_RULE_TYPES = Object.keys(byTypeSchema).length; + const byReasonSchema: MakeSchemaFrom['count_rules_executions_failured_by_reason_per_day'] = { // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) @@ -66,6 +68,20 @@ const byReasonSchema: MakeSchemaFrom['count_rules_executions_fail unknown: { type: 'long' }, }; +const byPercentileSchema: MakeSchemaFrom['percentile_num_scheduled_actions_per_day'] = + { + p50: { type: 'long' }, + p90: { type: 'long' }, + p99: { type: 'long' }, + }; + +const byPercentileSchemaByType: MakeSchemaFrom['percentile_num_scheduled_actions_by_type_per_day'] = + { + p50: byTypeSchema, + p90: byTypeSchema, + p99: byTypeSchema, + }; + const byReasonSchemaByType: MakeSchemaFrom['count_rules_executions_failured_by_reason_by_type_per_day'] = { // TODO: Find out an automated way to populate the keys or reformat these into an array (and change the Remote Telemetry indexer accordingly) @@ -160,6 +176,16 @@ export function createAlertingUsageCollector( avg_es_search_duration_by_type_per_day: {}, avg_total_search_duration_per_day: 0, avg_total_search_duration_by_type_per_day: {}, + percentile_num_scheduled_actions_per_day: { + p50: 0, + p90: 0, + p99: 0, + }, + percentile_num_scheduled_actions_by_type_per_day: { + p50: {}, + p90: {}, + p99: {}, + }, }; } }, @@ -211,6 +237,8 @@ export function createAlertingUsageCollector( avg_es_search_duration_by_type_per_day: byTypeSchema, avg_total_search_duration_per_day: { type: 'long' }, avg_total_search_duration_by_type_per_day: byTypeSchema, + percentile_num_scheduled_actions_per_day: byPercentileSchema, + percentile_num_scheduled_actions_by_type_per_day: byPercentileSchemaByType, }, }); } diff --git a/x-pack/plugins/alerting/server/usage/task.ts b/x-pack/plugins/alerting/server/usage/task.ts index 7aee043653806..0d0d2d802a3fb 100644 --- a/x-pack/plugins/alerting/server/usage/task.ts +++ b/x-pack/plugins/alerting/server/usage/task.ts @@ -144,6 +144,10 @@ export function telemetryTaskRunner( avg_total_search_duration_per_day: dailyExecutionCounts.avgTotalSearchDuration, avg_total_search_duration_by_type_per_day: dailyExecutionCounts.avgTotalSearchDurationByType, + percentile_num_scheduled_actions_per_day: + dailyExecutionCounts.scheduledActionsPercentiles, + percentile_num_scheduled_actions_by_type_per_day: + dailyExecutionCounts.scheduledActionsPercentilesByType, }, runAt: getNextMidnight(), }; diff --git a/x-pack/plugins/alerting/server/usage/types.ts b/x-pack/plugins/alerting/server/usage/types.ts index a03483bd54007..00bd3b46f91b1 100644 --- a/x-pack/plugins/alerting/server/usage/types.ts +++ b/x-pack/plugins/alerting/server/usage/types.ts @@ -25,6 +25,16 @@ export interface AlertingUsage { string, Record >; + percentile_num_scheduled_actions_per_day: { + p50: number; + p90: number; + p99: number; + }; + percentile_num_scheduled_actions_by_type_per_day: { + p50: Record; + p90: Record; + p99: Record; + }; avg_execution_time_per_day: number; avg_execution_time_by_type_per_day: Record; avg_es_search_duration_per_day: number; diff --git a/x-pack/plugins/apm/server/routes/alerts/alerting_es_client.ts b/x-pack/plugins/apm/server/routes/alerts/alerting_es_client.ts index 876d02137c3f8..ebab01464de6b 100644 --- a/x-pack/plugins/apm/server/routes/alerts/alerting_es_client.ts +++ b/x-pack/plugins/apm/server/routes/alerts/alerting_es_client.ts @@ -9,13 +9,13 @@ import { ESSearchRequest, ESSearchResponse, } from '../../../../../../src/core/types/elasticsearch'; -import { AlertServices } from '../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../alerting/server'; export async function alertingEsClient({ scopedClusterClient, params, }: { - scopedClusterClient: AlertServices< + scopedClusterClient: RuleExecutorServices< never, never, never diff --git a/x-pack/plugins/cases/public/client/ui/get_all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/client/ui/get_all_cases_selector_modal.tsx index 18821d24e3053..1666557ec2648 100644 --- a/x-pack/plugins/cases/public/client/ui/get_all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/client/ui/get_all_cases_selector_modal.tsx @@ -18,19 +18,15 @@ const AllCasesSelectorModalLazy: React.FC = lazy( export const getAllCasesSelectorModalLazy = ({ owner, userCanCrud, - alertData, hiddenStatuses, onRowClick, - updateCase, onClose, }: GetAllCasesSelectorModalProps) => ( }> @@ -42,20 +38,14 @@ export const getAllCasesSelectorModalLazy = ({ * cases provider. to be further refactored https://github.com/elastic/kibana/issues/123183 */ export const getAllCasesSelectorModalNoProviderLazy = ({ - alertData, - attachments, hiddenStatuses, onRowClick, - updateCase, onClose, }: AllCasesSelectorModalProps) => ( }> diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx index 88aad5fb64408..c8e656b8117eb 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.test.tsx @@ -17,7 +17,7 @@ import { TestProviders } from '../../common/mock'; import { casesStatus, useGetCasesMockState, mockCase, connectorsMock } from '../../containers/mock'; import { StatusAll } from '../../../common/ui/types'; -import { CaseStatuses, CommentType } from '../../../common/api'; +import { CaseStatuses } from '../../../common/api'; import { SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { getEmptyTagValue } from '../empty_value'; import { useDeleteCases } from '../../containers/use_delete_cases'; @@ -515,46 +515,6 @@ describe('AllCasesListGeneric', () => { }); }); - it('should call postComment when a case is selected in isSelectorView=true and has attachments', async () => { - const postCommentMockedValue = { status: { isLoading: false }, postComment: jest.fn() }; - usePostCommentMock.mockReturnValueOnce(postCommentMockedValue); - const wrapper = mount( - - - - ); - wrapper.find('[data-test-subj="cases-table-row-select-1"]').first().simulate('click'); - await waitFor(() => { - expect(postCommentMockedValue.postComment).toHaveBeenCalledWith({ - caseId: '1', - data: { - alertId: 'alert-id-201', - index: 'index-id-1', - owner: 'test', - rule: { - id: 'rule-id-1', - name: 'Awesome myrule', - }, - type: 'alert', - }, - }); - }); - }); - it('should call onRowClick with no cases and isSelectorView=true', async () => { useGetCasesMock.mockReturnValue({ ...defaultGetCases, diff --git a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx index ffcb7a1abe416..5eac485e24c7b 100644 --- a/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/all_cases_list.tsx @@ -16,14 +16,8 @@ import { FilterOptions, SortFieldCase, } from '../../../common/ui/types'; -import { - CaseStatuses, - CommentRequestAlertType, - caseStatuses, - CommentType, -} from '../../../common/api'; +import { CaseStatuses, caseStatuses } from '../../../common/api'; import { useGetCases } from '../../containers/use_get_cases'; -import { usePostComment } from '../../containers/use_post_comment'; import { useAvailableCasesOwners } from '../app/use_available_owners'; import { useCasesColumns } from './columns'; @@ -33,7 +27,6 @@ import { EuiBasicTableOnChange } from './types'; import { CasesTable } from './table'; import { useConnectors } from '../../containers/configure/use_connectors'; import { useCasesContext } from '../cases_context/use_cases_context'; -import { CaseAttachments } from '../../types'; const ProgressLoader = styled(EuiProgress)` ${({ $isShow }: { $isShow: boolean }) => @@ -52,28 +45,14 @@ const getSortField = (field: string): SortFieldCase => field === SortFieldCase.closedAt ? SortFieldCase.closedAt : SortFieldCase.createdAt; export interface AllCasesListProps { - /** - * @deprecated Use the attachments prop instead - */ - alertData?: Omit; hiddenStatuses?: CaseStatusWithAllStatus[]; isSelectorView?: boolean; onRowClick?: (theCase?: Case) => void; - updateCase?: (newCase: Case) => void; doRefresh?: () => void; - attachments?: CaseAttachments; } export const AllCasesList = React.memo( - ({ - alertData, - attachments, - hiddenStatuses = [], - isSelectorView = false, - onRowClick, - updateCase, - doRefresh, - }) => { + ({ hiddenStatuses = [], isSelectorView = false, onRowClick, doRefresh }) => { const { owner, userCanCrud } = useCasesContext(); const hasOwner = !!owner.length; const availableSolutions = useAvailableCasesOwners(); @@ -97,8 +76,6 @@ export const AllCasesList = React.memo( setSelectedCases, } = useGetCases({ initialFilterOptions }); - // Post Comment to Case - const { postComment, isLoading: isCommentUpdating } = usePostComment(); const { connectors } = useConnectors(); const sorting = useMemo( @@ -181,19 +158,6 @@ export const AllCasesList = React.memo( const showActions = userCanCrud && !isSelectorView; - // TODO remove the deprecated alertData field when cleaning up - // code https://github.com/elastic/kibana/issues/123183 - // This code is to support the deprecated alertData prop - const toAttach = useMemo((): CaseAttachments | undefined => { - if (attachments !== undefined || alertData !== undefined) { - const _toAttach = attachments ?? []; - if (alertData !== undefined) { - _toAttach.push({ ...alertData, type: CommentType.alert }); - } - return _toAttach; - } - }, [alertData, attachments]); - const columns = useCasesColumns({ dispatchUpdateCaseProperty, filterStatus: filterOptions.status, @@ -204,9 +168,6 @@ export const AllCasesList = React.memo( userCanCrud, connectors, onRowClick, - attachments: toAttach, - postComment, - updateCase, showSolutionColumn: !hasOwner && availableSolutions.length > 1, }); @@ -243,7 +204,7 @@ export const AllCasesList = React.memo( size="xs" color="accent" className="essentialAnimation" - $isShow={(isCasesLoading || isLoading || isCommentUpdating) && !isDataEmpty} + $isShow={(isCasesLoading || isLoading) && !isDataEmpty} /> ( goToCreateCase={onRowClick} handleIsLoading={handleIsLoading} isCasesLoading={isCasesLoading} - isCommentUpdating={isCommentUpdating} + isCommentUpdating={isCasesLoading} isDataEmpty={isDataEmpty} isSelectorView={isSelectorView} onChange={tableOnChangeCallback} diff --git a/x-pack/plugins/cases/public/components/all_cases/columns.tsx b/x-pack/plugins/cases/public/components/all_cases/columns.tsx index a05673d3e095a..543e6ef6f4871 100644 --- a/x-pack/plugins/cases/public/components/all_cases/columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/columns.tsx @@ -38,8 +38,6 @@ import { useApplicationCapabilities, useKibana } from '../../common/lib/kibana'; import { StatusContextMenu } from '../case_action_bar/status_context_menu'; import { TruncatedText } from '../truncated_text'; import { getConnectorIcon } from '../utils'; -import { PostComment } from '../../containers/use_post_comment'; -import { CaseAttachments } from '../../types'; import type { CasesOwners } from '../../client/helpers/can_use_cases'; import { useCasesFeatures } from '../cases_context/use_cases_features'; @@ -73,9 +71,6 @@ export interface GetCasesColumn { userCanCrud: boolean; connectors?: ActionConnector[]; onRowClick?: (theCase: Case) => void; - attachments?: CaseAttachments; - postComment?: (args: PostComment) => Promise; - updateCase?: (newCase: Case) => void; showSolutionColumn?: boolean; } @@ -89,9 +84,6 @@ export const useCasesColumns = ({ userCanCrud, connectors = [], onRowClick, - attachments, - postComment, - updateCase, showSolutionColumn, }: GetCasesColumn): CasesColumns[] => { // Delete case @@ -141,24 +133,11 @@ export const useCasesColumns = ({ const assignCaseAction = useCallback( async (theCase: Case) => { - // TODO currently the API only supports to add a comment at the time - // once the API is updated we should use bulk post comment #124814 - // this operation is intentionally made in sequence - if (attachments !== undefined && attachments.length > 0) { - for (const attachment of attachments) { - await postComment?.({ - caseId: theCase.id, - data: attachment, - }); - } - updateCase?.(theCase); - } - if (onRowClick) { onRowClick(theCase); } }, - [attachments, onRowClick, postComment, updateCase] + [onRowClick] ); useEffect(() => { diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx index ef01ead1cb07d..eba8888f3367a 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.test.tsx @@ -11,7 +11,6 @@ import { mount } from 'enzyme'; import { AllCasesSelectorModal } from '.'; import { TestProviders } from '../../../common/mock'; import { AllCasesList } from '../all_cases_list'; -import { SECURITY_SOLUTION_OWNER } from '../../../../common/constants'; jest.mock('../all_cases_list'); @@ -19,7 +18,6 @@ const onRowClick = jest.fn(); const defaultProps = { onRowClick, }; -const updateCase = jest.fn(); describe('AllCasesSelectorModal', () => { beforeEach(() => { @@ -50,17 +48,7 @@ describe('AllCasesSelectorModal', () => { it('pass the correct props to getAllCases method', () => { const fullProps = { ...defaultProps, - alertData: { - rule: { - id: 'rule-id', - name: 'rule', - }, - index: 'index-id', - alertId: 'alert-id', - owner: SECURITY_SOLUTION_OWNER, - }, hiddenStatuses: [], - updateCase, }; mount( @@ -72,10 +60,8 @@ describe('AllCasesSelectorModal', () => { // @ts-ignore idk what this mock style is but it works ¯\_(ツ)_/¯ expect(AllCasesList.type.mock.calls[0][0]).toEqual( expect.objectContaining({ - alertData: fullProps.alertData, hiddenStatuses: fullProps.hiddenStatuses, isSelectorView: true, - updateCase, }) ); }); diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx index ba553b28a34e0..581ecef47ad88 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/all_cases_selector_modal.tsx @@ -16,20 +16,13 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { Case, CaseStatusWithAllStatus } from '../../../../common/ui/types'; -import { CommentRequestAlertType } from '../../../../common/api'; import * as i18n from '../../../common/translations'; import { AllCasesList } from '../all_cases_list'; -import { CaseAttachments } from '../../../types'; + export interface AllCasesSelectorModalProps { - /** - * @deprecated Use the attachments prop instead - */ - alertData?: Omit; hiddenStatuses?: CaseStatusWithAllStatus[]; onRowClick?: (theCase?: Case) => void; - updateCase?: (newCase: Case) => void; onClose?: () => void; - attachments?: CaseAttachments; } const Modal = styled(EuiModal)` @@ -40,7 +33,7 @@ const Modal = styled(EuiModal)` `; export const AllCasesSelectorModal = React.memo( - ({ alertData, attachments, hiddenStatuses, onRowClick, updateCase, onClose }) => { + ({ hiddenStatuses, onRowClick, onClose }) => { const [isModalOpen, setIsModalOpen] = useState(true); const closeModal = useCallback(() => { if (onClose) { @@ -66,12 +59,9 @@ export const AllCasesSelectorModal = React.memo( diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx index b0e316e891744..25360800554b2 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx @@ -5,42 +5,82 @@ * 2.0. */ -/* eslint-disable react/display-name */ - -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor } from '@testing-library/dom'; +import { act, renderHook } from '@testing-library/react-hooks'; +import userEvent from '@testing-library/user-event'; import React from 'react'; -import { CaseStatuses, StatusAll } from '../../../../common'; +import AllCasesSelectorModal from '.'; +import { Case, CaseStatuses, StatusAll } from '../../../../common'; +import { AppMockRenderer, createAppMockRenderer } from '../../../common/mock'; +import { useCasesToast } from '../../../common/use_cases_toast'; +import { alertComment } from '../../../containers/mock'; +import { usePostComment } from '../../../containers/use_post_comment'; +import { SupportedCaseAttachment } from '../../../types'; import { CasesContext } from '../../cases_context'; import { CasesContextStoreActionsList } from '../../cases_context/cases_context_reducer'; import { useCasesAddToExistingCaseModal } from './use_cases_add_to_existing_case_modal'; + jest.mock('../../../common/use_cases_toast'); +jest.mock('../../../containers/use_post_comment'); +// dummy mock, will call onRowclick when rendering +jest.mock('./all_cases_selector_modal', () => { + return { + AllCasesSelectorModal: jest.fn(), + }; +}); + +const useCasesToastMock = useCasesToast as jest.Mock; + +const AllCasesSelectorModalMock = AllCasesSelectorModal as unknown as jest.Mock; + +// test component to test the hook integration +const TestComponent: React.FC = () => { + const hook = useCasesAddToExistingCaseModal({ + attachments: [alertComment as SupportedCaseAttachment], + }); + + const onClick = () => { + hook.open(); + }; + + return +
+
+

+ + Authentications + +

+
+
+
+

+ Showing: 0 users +

+
+ +
+ +
+ + + + +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + User + + + + + + Successes + + + + + + Failures + + + + + + Last success + + + + + + Last successful source + + + + + + Last successful destination + + + + + + Last failure + + + + + + Last failed source + + + + + + Last failed destination + + +
+
+ + No items found + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+`; diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap new file mode 100644 index 0000000000000..0796eebbe95fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/__snapshots__/authentications_user_table.test.tsx.snap @@ -0,0 +1,538 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Authentication User Table Component rendering it renders the user authentication table 1`] = ` +.c2 { + margin-top: 8px; +} + +.c2 .siemSubtitle__item { + color: #7a7f89; + font-size: 12px; + line-height: 1.5; +} + +.c1 { + margin-bottom: 24px; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; +} + +.c0 { + position: relative; +} + +.c3 tbody th, +.c3 tbody td { + vertical-align: top; +} + +.c3 tbody .euiTableCellContent { + display: block; +} + +.c4 { + margin-top: 4px; +} + +@media only screen and (min-width:575px) { + .c2 .siemSubtitle__item { + display: inline-block; + margin-right: 16px; + } + + .c2 .siemSubtitle__item:last-child { + margin-right: 0; + } +} + +
+
+
+
+
+
+
+
+ +
+
+

+ + Authentications + +

+
+
+
+

+ Showing: 0 users +

+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + User + + + + + + Successes + + + + + + Failures + + + + + + Last success + + + + + + Last successful source + + + + + + Last successful destination + + + + + + Last failure + + + + + + Last failed source + + + + + + Last failed destination + + +
+
+ + No items found + +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+`; diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.test.tsx b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.test.tsx new file mode 100644 index 0000000000000..9138e35252597 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.test.tsx @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import '../../mock/match_media'; + +import * as i18n from './translations'; +import { AuthenticationsHostTable } from './authentications_host_table'; +import { hostsModel } from '../../../hosts/store'; +import { TestProviders } from '../../../common/mock'; +import { useAuthentications } from '../../../common/containers/authentications'; +import { useQueryToggle } from '../../../common/containers/query_toggle'; + +jest.mock('../../../common/containers/query_toggle', () => ({ + useQueryToggle: jest.fn().mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() }), +})); +jest.mock('../../containers/authentications', () => ({ + useAuthentications: jest.fn().mockReturnValue([ + false, + { + authentications: [], + totalCount: 0, + pageInfo: {}, + loadPage: jest.fn(), + inspect: {}, + isInspected: false, + refetch: jest.fn(), + }, + ]), +})); + +describe('Authentication Host Table Component', () => { + const mockUseAuthentications = useAuthentications as jest.Mock; + const mockUseQueryToggle = useQueryToggle as jest.Mock; + + const startDate = '2020-07-07T08:20:18.966Z'; + const endDate = '3000-01-01T00:00:00.000Z'; + const defaultProps = { + type: hostsModel.HostsType.page, + startDate, + endDate, + skip: false, + setQuery: jest.fn(), + indexNames: [], + }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('rendering', () => { + test('it renders the host authentication table', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('authentications-host-table-loading-false')).toMatchSnapshot(); + }); + }); + + describe('columns', () => { + test('on hosts page, we expect to get all 9 columns', () => { + const { queryAllByRole, queryByText } = render( + + + + ); + + expect(queryAllByRole('columnheader').length).toEqual(9); + + // it should have Last Successful Destination column + expect(queryByText(i18n.LAST_SUCCESSFUL_DESTINATION)).toBeInTheDocument(); + // it should have Last Failed Destination column + expect(queryByText(i18n.LAST_FAILED_DESTINATION)).toBeInTheDocument(); + }); + + test('on hosts page, we expect to get 7 user details columns', () => { + const { queryAllByRole, queryByText } = render( + + + + ); + + expect(queryAllByRole('columnheader').length).toEqual(7); + + // it should not have Successful Destination column + expect(queryByText(i18n.LAST_SUCCESSFUL_DESTINATION)).not.toBeInTheDocument(); + // it should not have Failed Destination column + expect(queryByText(i18n.LAST_FAILED_DESTINATION)).not.toBeInTheDocument(); + }); + }); + + it('toggleStatus=true, do not skip', () => { + render( + + + + ); + expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(false); + }); + + it('toggleStatus=false, skip', () => { + mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() }); + render( + + + + ); + expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(true); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.tsx b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.tsx new file mode 100644 index 0000000000000..710b862570086 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_host_table.tsx @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useState } from 'react'; + +import { getOr } from 'lodash/fp'; +import { useDispatch } from 'react-redux'; +import { PaginatedTable } from '../paginated_table'; + +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; + +import * as i18n from './translations'; +import { + getHostDetailsAuthenticationColumns, + getHostsPageAuthenticationColumns, + rowItems, +} from './helpers'; +import { useAuthentications } from '../../containers/authentications'; +import { useQueryInspector } from '../page/manage_query'; +import { HostsComponentsQueryProps } from '../../../hosts/pages/navigation/types'; +import { hostsActions, hostsModel, hostsSelectors } from '../../../hosts/store'; +import { useQueryToggle } from '../../containers/query_toggle'; +import { useDeepEqualSelector } from '../../hooks/use_selector'; +import { AuthStackByField } from '../../../../common/search_strategy'; + +const TABLE_QUERY_ID = 'authenticationsHostsTableQuery'; + +const tableType = hostsModel.HostsTableType.authentications; + +const AuthenticationsHostTableComponent: React.FC = ({ + docValueFields, + endDate, + filterQuery, + indexNames, + skip, + startDate, + type, + setQuery, + deleteQuery, +}) => { + const usersEnabled = useIsExperimentalFeatureEnabled('usersEnabled'); + const dispatch = useDispatch(); + const { toggleStatus } = useQueryToggle(TABLE_QUERY_ID); + const [querySkip, setQuerySkip] = useState(skip || !toggleStatus); + useEffect(() => { + setQuerySkip(skip || !toggleStatus); + }, [skip, toggleStatus]); + + const getAuthenticationsSelector = hostsSelectors.authenticationsSelector(); + const { activePage, limit } = useDeepEqualSelector((state) => + getAuthenticationsSelector(state, type) + ); + + const [ + loading, + { authentications, totalCount, pageInfo, loadPage, inspect, isInspected, refetch }, + ] = useAuthentications({ + docValueFields, + endDate, + filterQuery, + indexNames, + skip: querySkip, + startDate, + stackByField: AuthStackByField.userName, + activePage, + limit, + }); + + const columns = + type === hostsModel.HostsType.details + ? getHostDetailsAuthenticationColumns(usersEnabled) + : getHostsPageAuthenticationColumns(usersEnabled); + + const updateLimitPagination = useCallback( + (newLimit) => + dispatch( + hostsActions.updateTableLimit({ + hostsType: type, + limit: newLimit, + tableType, + }) + ), + [type, dispatch] + ); + + const updateActivePage = useCallback( + (newPage) => + dispatch( + hostsActions.updateTableActivePage({ + activePage: newPage, + hostsType: type, + tableType, + }) + ), + [type, dispatch] + ); + + useQueryInspector({ + queryId: TABLE_QUERY_ID, + loading, + refetch, + setQuery, + deleteQuery, + inspect, + }); + + return ( + + ); +}; + +AuthenticationsHostTableComponent.displayName = 'AuthenticationsHostTableComponent'; + +export const AuthenticationsHostTable = React.memo(AuthenticationsHostTableComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.test.tsx b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.test.tsx new file mode 100644 index 0000000000000..6be9c630a20bf --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.test.tsx @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import '../../mock/match_media'; + +import { TestProviders } from '../../../common/mock'; +import { useAuthentications } from '../../../common/containers/authentications'; +import { useQueryToggle } from '../../../common/containers/query_toggle'; +import { AuthenticationsUserTable } from './authentications_user_table'; +import { usersModel } from '../../../users/store'; + +jest.mock('../../../common/containers/query_toggle', () => ({ + useQueryToggle: jest.fn().mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() }), +})); +jest.mock('../../containers/authentications', () => ({ + useAuthentications: jest.fn().mockReturnValue([ + false, + { + authentications: [], + totalCount: 0, + pageInfo: {}, + loadPage: jest.fn(), + inspect: {}, + isInspected: false, + refetch: jest.fn(), + }, + ]), +})); + +describe('Authentication User Table Component', () => { + const mockUseAuthentications = useAuthentications as jest.Mock; + const mockUseQueryToggle = useQueryToggle as jest.Mock; + + const startDate = '2020-07-07T08:20:18.966Z'; + const endDate = '3000-01-01T00:00:00.000Z'; + const defaultProps = { + type: usersModel.UsersType.page, + startDate, + endDate, + skip: false, + setQuery: jest.fn(), + indexNames: [], + }; + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('rendering', () => { + test('it renders the user authentication table', () => { + const { getByTestId } = render( + + + + ); + + expect(getByTestId('table-users-authentications-loading-false')).toMatchSnapshot(); + }); + }); + + it('toggleStatus=true, do not skip', () => { + render( + + + + ); + expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(false); + }); + + it('toggleStatus=false, skip', () => { + mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() }); + render( + + + + ); + expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(true); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.tsx b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.tsx new file mode 100644 index 0000000000000..572c06ef4da90 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/authentications_user_table.tsx @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useMemo, useState } from 'react'; + +import { getOr } from 'lodash/fp'; +import { useDispatch } from 'react-redux'; +import { AuthStackByField } from '../../../../common/search_strategy/security_solution/users/authentications'; +import { PaginatedTable } from '../paginated_table'; + +import { useIsExperimentalFeatureEnabled } from '../../hooks/use_experimental_features'; + +import * as i18n from './translations'; +import { getHostsPageAuthenticationColumns, rowItems } from './helpers'; +import { useAuthentications } from '../../containers/authentications'; +import { useQueryInspector } from '../page/manage_query'; +import { useQueryToggle } from '../../containers/query_toggle'; +import { useDeepEqualSelector } from '../../hooks/use_selector'; +import { usersActions, usersModel, usersSelectors } from '../../../users/store'; +import { UsersComponentsQueryProps } from '../../../users/pages/navigation/types'; + +const TABLE_QUERY_ID = 'authenticationsUsersTableQuery'; + +const AuthenticationsUserTableComponent: React.FC = ({ + docValueFields, + endDate, + filterQuery, + indexNames, + skip, + startDate, + type, + setQuery, + deleteQuery, +}) => { + const usersEnabled = useIsExperimentalFeatureEnabled('usersEnabled'); + + const dispatch = useDispatch(); + const { toggleStatus } = useQueryToggle(TABLE_QUERY_ID); + const [querySkip, setQuerySkip] = useState(skip || !toggleStatus); + useEffect(() => { + setQuerySkip(skip || !toggleStatus); + }, [skip, toggleStatus]); + + const getAuthenticationsSelector = useMemo(() => usersSelectors.authenticationsSelector(), []); + const { activePage, limit } = useDeepEqualSelector((state) => getAuthenticationsSelector(state)); + + const [ + loading, + { authentications, totalCount, pageInfo, loadPage, inspect, isInspected, refetch }, + ] = useAuthentications({ + docValueFields, + endDate, + filterQuery, + indexNames, + skip: querySkip, + startDate, + activePage, + limit, + stackByField: AuthStackByField.userName, + }); + + const columns = getHostsPageAuthenticationColumns(usersEnabled); + + const updateLimitPagination = useCallback( + (newLimit) => + dispatch( + usersActions.updateTableLimit({ + usersType: type, + limit: newLimit, + tableType: usersModel.UsersTableType.authentications, + }) + ), + [type, dispatch] + ); + + const updateActivePage = useCallback( + (newPage) => + dispatch( + usersActions.updateTableActivePage({ + activePage: newPage, + usersType: type, + tableType: usersModel.UsersTableType.authentications, + }) + ), + [type, dispatch] + ); + + useQueryInspector({ + queryId: TABLE_QUERY_ID, + loading, + refetch, + setQuery, + deleteQuery, + inspect, + }); + + return ( + + ); +}; + +AuthenticationsUserTableComponent.displayName = 'AuthenticationsUserTableComponent'; + +export const AuthenticationsUserTable = React.memo(AuthenticationsUserTableComponent); diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/helpers.tsx b/x-pack/plugins/security_solution/public/common/components/authentication/helpers.tsx new file mode 100644 index 0000000000000..d541e0e452943 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/helpers.tsx @@ -0,0 +1,217 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { has } from 'lodash/fp'; +import React from 'react'; + +import { DragEffects, DraggableWrapper } from '../drag_and_drop/draggable_wrapper'; +import { escapeDataProviderId } from '../drag_and_drop/helpers'; +import { getEmptyTagValue } from '../empty_value'; +import { FormattedRelativePreferenceDate } from '../formatted_date'; +import { Columns, ItemsPerRow } from '../paginated_table'; +import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider'; +import { Provider } from '../../../timelines/components/timeline/data_providers/provider'; +import { getRowItemDraggables } from '../tables/helpers'; + +import * as i18n from './translations'; +import { HostDetailsLink, NetworkDetailsLink, UserDetailsLink } from '../links'; +import { AuthenticationsEdges } from '../../../../common/search_strategy'; +import { AuthTableColumns } from './types'; + +export const getHostDetailsAuthenticationColumns = (usersEnabled: boolean): AuthTableColumns => [ + getUserColumn(usersEnabled), + SUCCESS_COLUMN, + FAILURES_COLUMN, + LAST_SUCCESSFUL_TIME_COLUMN, + LAST_SUCCESSFUL_SOURCE_COLUMN, + LAST_FAILED_TIME_COLUMN, + LAST_FAILED_SOURCE_COLUMN, +]; + +export const getHostsPageAuthenticationColumns = (usersEnabled: boolean): AuthTableColumns => [ + getUserColumn(usersEnabled), + SUCCESS_COLUMN, + FAILURES_COLUMN, + LAST_SUCCESSFUL_TIME_COLUMN, + LAST_SUCCESSFUL_SOURCE_COLUMN, + LAST_SUCCESSFUL_DESTINATION_COLUMN, + LAST_FAILED_TIME_COLUMN, + LAST_FAILED_SOURCE_COLUMN, + LAST_FAILED_DESTINATION_COLUMN, +]; + +export const rowItems: ItemsPerRow[] = [ + { + text: i18n.ROWS_5, + numberOfRow: 5, + }, + { + text: i18n.ROWS_10, + numberOfRow: 10, + }, +]; + +const FAILURES_COLUMN: Columns = { + name: i18n.FAILURES, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => { + const id = escapeDataProviderId(`authentications-table-${node._id}-failures-${node.failures}`); + return ( + + snapshot.isDragging ? ( + + + + ) : ( + node.failures + ) + } + /> + ); + }, + width: '8%', +}; +const LAST_SUCCESSFUL_TIME_COLUMN: Columns = { + name: i18n.LAST_SUCCESSFUL_TIME, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + has('lastSuccess.timestamp', node) && node.lastSuccess?.timestamp != null ? ( + + ) : ( + getEmptyTagValue() + ), +}; +const LAST_SUCCESSFUL_SOURCE_COLUMN: Columns = { + name: i18n.LAST_SUCCESSFUL_SOURCE, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + getRowItemDraggables({ + rowItems: node.lastSuccess?.source?.ip || null, + attrName: 'source.ip', + idPrefix: `authentications-table-${node._id}-lastSuccessSource`, + render: (item) => , + }), +}; +const LAST_SUCCESSFUL_DESTINATION_COLUMN: Columns = { + name: i18n.LAST_SUCCESSFUL_DESTINATION, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + getRowItemDraggables({ + rowItems: node.lastSuccess?.host?.name ?? null, + attrName: 'host.name', + idPrefix: `authentications-table-${node._id}-lastSuccessfulDestination`, + render: (item) => , + }), +}; +const LAST_FAILED_TIME_COLUMN: Columns = { + name: i18n.LAST_FAILED_TIME, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + has('lastFailure.timestamp', node) && node.lastFailure?.timestamp != null ? ( + + ) : ( + getEmptyTagValue() + ), +}; +const LAST_FAILED_SOURCE_COLUMN: Columns = { + name: i18n.LAST_FAILED_SOURCE, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + getRowItemDraggables({ + rowItems: node.lastFailure?.source?.ip || null, + attrName: 'source.ip', + idPrefix: `authentications-table-${node._id}-lastFailureSource`, + render: (item) => , + }), +}; +const LAST_FAILED_DESTINATION_COLUMN: Columns = { + name: i18n.LAST_FAILED_DESTINATION, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + getRowItemDraggables({ + rowItems: node.lastFailure?.host?.name || null, + attrName: 'host.name', + idPrefix: `authentications-table-${node._id}-lastFailureDestination`, + render: (item) => , + }), +}; + +const getUserColumn = ( + usersEnabled: boolean +): Columns => ({ + name: i18n.USER, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => + getRowItemDraggables({ + rowItems: node.stackedValue, + attrName: 'user.name', + idPrefix: `authentications-table-${node._id}-userName`, + render: (item) => (usersEnabled ? : <>{item}), + }), +}); + +const SUCCESS_COLUMN: Columns = { + name: i18n.SUCCESSES, + truncateText: false, + mobileOptions: { show: true }, + render: ({ node }) => { + const id = escapeDataProviderId( + `authentications-table-${node._id}-node-successes-${node.successes}` + ); + return ( + + snapshot.isDragging ? ( + + + + ) : ( + node.successes + ) + } + /> + ); + }, + width: '8%', +}; diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/translations.ts b/x-pack/plugins/security_solution/public/common/components/authentication/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/hosts/components/authentications_table/translations.ts rename to x-pack/plugins/security_solution/public/common/components/authentication/translations.ts diff --git a/x-pack/plugins/security_solution/public/common/components/authentication/types.ts b/x-pack/plugins/security_solution/public/common/components/authentication/types.ts new file mode 100644 index 0000000000000..c686263fa8d12 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/authentication/types.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AuthenticationsEdges } from '../../../../common/search_strategy'; +import { Columns } from '../paginated_table'; + +export type AuthTableColumns = + | [ + Columns, + Columns, + Columns, + Columns, + Columns, + Columns, + Columns, + Columns, + Columns + ] + | [ + Columns, + Columns, + Columns, + Columns, + Columns, + Columns, + Columns + ]; diff --git a/x-pack/plugins/security_solution/public/overview/components/landing_cards/index.tsx b/x-pack/plugins/security_solution/public/common/components/landing_cards/index.tsx similarity index 98% rename from x-pack/plugins/security_solution/public/overview/components/landing_cards/index.tsx rename to x-pack/plugins/security_solution/public/common/components/landing_cards/index.tsx index d8852d8603518..20ad45da680ec 100644 --- a/x-pack/plugins/security_solution/public/overview/components/landing_cards/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/landing_cards/index.tsx @@ -22,7 +22,7 @@ import endpointPng from '../../images/endpoint.png'; import siemPng from '../../images/siem.png'; import videoSvg from '../../images/video.svg'; import { ADD_DATA_PATH } from '../../../../common/constants'; -import { useKibana } from '../../../common/lib/kibana'; +import { useKibana } from '../../lib/kibana'; const imgUrls = { siem: siemPng, diff --git a/x-pack/plugins/security_solution/public/overview/components/landing_cards/translations.tsx b/x-pack/plugins/security_solution/public/common/components/landing_cards/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/overview/components/landing_cards/translations.tsx rename to x-pack/plugins/security_solution/public/common/components/landing_cards/translations.tsx diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/landing_page/__snapshots__/index.test.tsx.snap new file mode 100644 index 0000000000000..d55ce293d69df --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/__snapshots__/index.test.tsx.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LandingPageComponent component renders page properly 1`] = ` + + + +`; diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx new file mode 100644 index 0000000000000..0e27280cc2c4f --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/index.test.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { shallow } from 'enzyme'; +import React from 'react'; + +import { LandingPageComponent } from './index'; + +describe('LandingPageComponent component', () => { + it('renders page properly', () => { + const EmptyComponent = shallow(); + expect(EmptyComponent).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx b/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx new file mode 100644 index 0000000000000..310420524040d --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/components/landing_page/index.tsx @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { LandingCards } from '../landing_cards'; +import { SecuritySolutionPageWrapper } from '../page_wrapper'; + +export const LandingPageComponent = memo(() => { + return ( + + + + ); +}); + +LandingPageComponent.displayName = 'LandingPageComponent'; diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts b/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts index baf4965467b51..15ac66ffddfd1 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/link_to/__mocks__/index.ts @@ -8,7 +8,7 @@ import { SecurityPageName } from '../../../../app/types'; export { getDetectionEngineUrl } from '../redirect_to_detection_engine'; -export { getAppOverviewUrl } from '../redirect_to_overview'; +export { getAppLandingUrl } from '../redirect_to_landing'; export { getHostDetailsUrl, getHostsUrl } from '../redirect_to_hosts'; export { getNetworkUrl, getNetworkDetailsUrl } from '../redirect_to_network'; export { getTimelineTabsUrl, getTimelineUrl } from '../redirect_to_timelines'; diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/index.ts b/x-pack/plugins/security_solution/public/common/components/link_to/index.ts index 2f7f876bda9bc..2f9b3542d765b 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/link_to/index.ts @@ -14,7 +14,6 @@ import { SecurityNavKey } from '../navigation/types'; import { SecurityPageName } from '../../../app/types'; export { getDetectionEngineUrl, getRuleDetailsUrl } from './redirect_to_detection_engine'; -export { getAppOverviewUrl } from './redirect_to_overview'; export { getHostDetailsUrl, getTabsOnHostDetailsUrl, getHostsUrl } from './redirect_to_hosts'; export { getNetworkUrl, getNetworkDetailsUrl } from './redirect_to_network'; export { getTimelineTabsUrl, getTimelineUrl } from './redirect_to_timelines'; diff --git a/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_overview.tsx b/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_landing.tsx similarity index 51% rename from x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_overview.tsx rename to x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_landing.tsx index 6a83edd7442de..10ef61da0b814 100644 --- a/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_overview.tsx +++ b/x-pack/plugins/security_solution/public/common/components/link_to/redirect_to_landing.tsx @@ -6,9 +6,5 @@ */ import { appendSearch } from './helpers'; -import { LANDING_PATH } from '../../../../common/constants'; -export const getAppOverviewUrl = (overviewPath: string, search?: string) => - `${overviewPath}${appendSearch(search)}`; - -export const getAppLandingUrl = (search?: string) => `${LANDING_PATH}${appendSearch(search)}`; +export const getAppLandingUrl = (path: string, search?: string) => `${path}${appendSearch(search)}`; diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts index 5639721403cbd..7d2bfaa405cb2 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.test.ts @@ -158,7 +158,7 @@ describe('Navigation Breadcrumbs', () => { ); expect(breadcrumbs).toEqual([ { - href: 'securitySolutionUI/overview', + href: 'securitySolutionUI/get_started', text: 'Security', }, { @@ -178,7 +178,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Network', href: "securitySolutionUI/network?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -196,7 +196,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Timelines', href: "securitySolutionUI/timelines?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -210,7 +210,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Hosts', href: "securitySolutionUI/hosts?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -229,7 +229,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Network', href: "securitySolutionUI/network?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -248,7 +248,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Network', href: "securitySolutionUI/network?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -267,7 +267,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Alerts', href: '', @@ -281,7 +281,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Exceptions', href: '', @@ -295,7 +295,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Rules', href: "securitySolutionUI/rules?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -309,7 +309,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Rules', href: "securitySolutionUI/rules?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -335,7 +335,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Rules', href: "securitySolutionUI/rules?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -361,7 +361,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Rules', href: "securitySolutionUI/rules?sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2019-05-16T23:10:43.696Z',fromStr:now-24h,kind:relative,to:'2019-05-17T23:10:43.697Z',toStr:now)))", @@ -406,7 +406,7 @@ describe('Navigation Breadcrumbs', () => { getUrlForAppMock ); expect(breadcrumbs).toEqual([ - { text: 'Security', href: 'securitySolutionUI/overview' }, + { text: 'Security', href: 'securitySolutionUI/get_started' }, { text: 'Endpoints', href: '', @@ -428,7 +428,7 @@ describe('Navigation Breadcrumbs', () => { expect(setBreadcrumbsMock).toBeCalledWith([ expect.objectContaining({ text: 'Security', - href: 'securitySolutionUI/overview', + href: 'securitySolutionUI/get_started', onClick: expect.any(Function), }), expect.objectContaining({ diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts index 83ee6ce481250..fead76ff1b2eb 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts +++ b/x-pack/plugins/security_solution/public/common/components/navigation/breadcrumbs/index.ts @@ -26,7 +26,7 @@ import { AdministrationRouteSpyState, UsersRouteSpyState, } from '../../../utils/route/types'; -import { getAppOverviewUrl } from '../../link_to'; +import { getAppLandingUrl } from '../../link_to/redirect_to_landing'; import { timelineActions } from '../../../../../public/timelines/store/timeline'; import { TimelineId } from '../../../../../common/types/timeline'; import { TabNavigationProps } from '../tab_navigation/types'; @@ -91,10 +91,11 @@ export const getBreadcrumbsForRoute = ( getUrlForApp: GetUrlForApp ): ChromeBreadcrumb[] | null => { const spyState: RouteSpyState = omit('navTabs', object); - const overviewPath = getUrlForApp(APP_UI_ID, { deepLinkId: SecurityPageName.overview }); + const landingPath = getUrlForApp(APP_UI_ID, { deepLinkId: SecurityPageName.landing }); + const siemRootBreadcrumb: ChromeBreadcrumb = { text: APP_NAME, - href: getAppOverviewUrl(overviewPath), + href: getAppLandingUrl(landingPath), }; if (isHostsRoutes(spyState) && object.navTabs) { const tempNav: SearchNavTab = { urlKey: 'host', isDetailPage: false }; diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/index.test.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/index.test.tsx index 601794dd25917..c76ba7a43cb30 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/index.test.tsx @@ -115,16 +115,6 @@ describe('useSecuritySolutionNavigation', () => { Object { "id": "main", "items": Array [ - Object { - "data-href": "securitySolutionUI/overview?query=(language:kuery,query:'host.name:%22security-solution-es%22')&sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)))", - "data-test-subj": "navigation-overview", - "disabled": false, - "href": "securitySolutionUI/overview?query=(language:kuery,query:'host.name:%22security-solution-es%22')&sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)))", - "id": "overview", - "isSelected": false, - "name": "Overview", - "onClick": [Function], - }, Object { "data-href": "securitySolutionUI/get_started?query=(language:kuery,query:'host.name:%22security-solution-es%22')&sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)))", "data-test-subj": "navigation-get_started", @@ -135,6 +125,16 @@ describe('useSecuritySolutionNavigation', () => { "name": "Getting started", "onClick": [Function], }, + Object { + "data-href": "securitySolutionUI/overview?query=(language:kuery,query:'host.name:%22security-solution-es%22')&sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)))", + "data-test-subj": "navigation-overview", + "disabled": false, + "href": "securitySolutionUI/overview?query=(language:kuery,query:'host.name:%22security-solution-es%22')&sourcerer=()&timerange=(global:(linkTo:!(timeline),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)),timeline:(linkTo:!(global),timerange:(from:'2020-07-07T08:20:18.966Z',fromStr:now-24h,kind:relative,to:'2020-07-08T08:20:18.966Z',toStr:now)))", + "id": "overview", + "isSelected": false, + "name": "Overview", + "onClick": [Function], + }, ], "name": "", }, diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx index 14b007be4764d..7985f5244e84f 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_navigation_items.tsx @@ -77,8 +77,8 @@ function usePrimaryNavigationItemsToDisplay(navTabs: Record) { id: 'main', name: '', items: [ - navTabs[SecurityPageName.overview], navTabs[SecurityPageName.landing], + navTabs[SecurityPageName.overview], // Temporary check for detectionAndResponse while page is feature flagged ...(navTabs[SecurityPageName.detectionAndResponse] != null ? [navTabs[SecurityPageName.detectionAndResponse]] diff --git a/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx b/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx index 3b27dc0fcfac6..fc2fe1ac5b361 100644 --- a/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/paginated_table/index.tsx @@ -25,7 +25,6 @@ import styled from 'styled-components'; import { Direction } from '../../../../common/search_strategy'; import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../common/constants'; -import { AuthTableColumns } from '../../../hosts/components/authentications_table'; import { HostsTableColumns } from '../../../hosts/components/hosts_table'; import { NetworkDnsColumns } from '../../../network/components/network_dns_table/columns'; import { NetworkHttpColumns } from '../../../network/components/network_http_table/columns'; @@ -51,6 +50,7 @@ import { Panel } from '../panel'; import { InspectButtonContainer } from '../inspect'; import { useQueryToggle } from '../../containers/query_toggle'; import { UsersTableColumns } from '../../../users/components/all_users'; +import { AuthTableColumns } from '../authentication/types'; const DEFAULT_DATA_TEST_SUBJ = 'paginated-table'; diff --git a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.test.tsx b/x-pack/plugins/security_solution/public/common/containers/authentications/index.test.tsx similarity index 82% rename from x-pack/plugins/security_solution/public/hosts/containers/authentications/index.test.tsx rename to x-pack/plugins/security_solution/public/common/containers/authentications/index.test.tsx index 1f6ee4cb276ec..cf7953bb8922c 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.test.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/authentications/index.test.tsx @@ -6,9 +6,10 @@ */ import { act, renderHook } from '@testing-library/react-hooks'; +import { AuthStackByField } from '../../../../common/search_strategy'; import { TestProviders } from '../../../common/mock'; +import { HostsType } from '../../../hosts/store/model'; import { useAuthentications } from './index'; -import { HostsType } from '../../store/model'; describe('authentications', () => { it('skip = true will cancel any running request', () => { @@ -19,6 +20,9 @@ describe('authentications', () => { indexNames: ['cool'], type: HostsType.page, skip: false, + stackByField: AuthStackByField.hostName, + activePage: 0, + limit: 10, }; const { rerender } = renderHook(() => useAuthentications(localProps), { wrapper: TestProviders, diff --git a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx b/x-pack/plugins/security_solution/public/common/containers/authentications/index.tsx similarity index 85% rename from x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx rename to x-pack/plugins/security_solution/public/common/containers/authentications/index.tsx index 1ff27e4b29917..593d5e4186e29 100644 --- a/x-pack/plugins/security_solution/public/hosts/containers/authentications/index.tsx +++ b/x-pack/plugins/security_solution/public/common/containers/authentications/index.tsx @@ -5,24 +5,22 @@ * 2.0. */ -import { noop, pick } from 'lodash/fp'; +import { noop } from 'lodash/fp'; import { useCallback, useEffect, useRef, useState } from 'react'; import deepEqual from 'fast-deep-equal'; import { Subscription } from 'rxjs'; import { isCompleteResponse, isErrorResponse } from '../../../../../../../src/plugins/data/common'; -import { HostsQueries } from '../../../../common/search_strategy/security_solution'; import { - HostAuthenticationsRequestOptions, - HostAuthenticationsStrategyResponse, AuthenticationsEdges, - PageInfoPaginated, - DocValueFields, - SortField, -} from '../../../../common/search_strategy'; + AuthStackByField, + UserAuthenticationsRequestOptions, + UserAuthenticationsStrategyResponse, + UsersQueries, +} from '../../../../common/search_strategy/security_solution'; +import { PageInfoPaginated, DocValueFields, SortField } from '../../../../common/search_strategy'; import { ESTermQuery } from '../../../../common/typed_json'; -import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; import { inputsModel } from '../../../common/store'; import { createFilter } from '../../../common/containers/helpers'; import { generateTablePaginationOptions } from '../../../common/components/paginated_table/helpers'; @@ -30,17 +28,12 @@ import { useKibana } from '../../../common/lib/kibana'; import { getInspectResponse } from '../../../helpers'; import { InspectResponse } from '../../../types'; -import { hostsModel, hostsSelectors } from '../../store'; - import * as i18n from './translations'; import { useTransforms } from '../../../transforms/containers/use_transforms'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; -export const ID = 'hostsAuthenticationsQuery'; - export interface AuthenticationArgs { authentications: AuthenticationsEdges[]; - id: string; inspect: InspectResponse; isInspected: boolean; loading: boolean; @@ -56,8 +49,10 @@ interface UseAuthentications { endDate: string; indexNames: string[]; startDate: string; - type: hostsModel.HostsType; skip: boolean; + stackByField: AuthStackByField; + activePage: number; + limit: number; } export const useAuthentications = ({ @@ -66,20 +61,18 @@ export const useAuthentications = ({ endDate, indexNames, startDate, - type, + activePage, + limit, skip, + stackByField, }: UseAuthentications): [boolean, AuthenticationArgs] => { - const getAuthenticationsSelector = hostsSelectors.authenticationsSelector(); - const { activePage, limit } = useDeepEqualSelector((state) => - pick(['activePage', 'limit'], getAuthenticationsSelector(state, type)) - ); const { data } = useKibana().services; const refetch = useRef(noop); const abortCtrl = useRef(new AbortController()); const searchSubscription$ = useRef(new Subscription()); const [loading, setLoading] = useState(false); const [authenticationsRequest, setAuthenticationsRequest] = - useState(null); + useState(null); const { getTransformChangesIfTheyExist } = useTransforms(); const { addError, addWarning } = useAppToasts(); @@ -101,7 +94,6 @@ export const useAuthentications = ({ const [authenticationsResponse, setAuthenticationsResponse] = useState({ authentications: [], - id: ID, inspect: { dsl: [], response: [], @@ -119,7 +111,7 @@ export const useAuthentications = ({ }); const authenticationsSearch = useCallback( - (request: HostAuthenticationsRequestOptions | null) => { + (request: UserAuthenticationsRequestOptions | null) => { if (request == null || skip) { return; } @@ -128,7 +120,7 @@ export const useAuthentications = ({ setLoading(true); searchSubscription$.current = data.search - .search(request, { + .search(request, { strategy: 'securitySolutionSearchStrategy', abortSignal: abortCtrl.current.signal, }) @@ -171,7 +163,7 @@ export const useAuthentications = ({ useEffect(() => { setAuthenticationsRequest((prevRequest) => { const { indices, factoryQueryType, timerange } = getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: UsersQueries.authentications, indices: indexNames, filterQuery, timerange: { @@ -187,6 +179,7 @@ export const useAuthentications = ({ docValueFields: docValueFields ?? [], factoryQueryType, filterQuery: createFilter(filterQuery), + stackByField, pagination: generateTablePaginationOptions(activePage, limit), timerange, sort: {} as SortField, @@ -202,6 +195,7 @@ export const useAuthentications = ({ endDate, filterQuery, indexNames, + stackByField, limit, startDate, getTransformChangesIfTheyExist, diff --git a/x-pack/plugins/security_solution/public/hosts/containers/authentications/translations.ts b/x-pack/plugins/security_solution/public/common/containers/authentications/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/hosts/containers/authentications/translations.ts rename to x-pack/plugins/security_solution/public/common/containers/authentications/translations.ts diff --git a/x-pack/plugins/security_solution/public/overview/images/endpoint.png b/x-pack/plugins/security_solution/public/common/images/endpoint.png similarity index 100% rename from x-pack/plugins/security_solution/public/overview/images/endpoint.png rename to x-pack/plugins/security_solution/public/common/images/endpoint.png diff --git a/x-pack/plugins/security_solution/public/overview/images/siem.png b/x-pack/plugins/security_solution/public/common/images/siem.png similarity index 100% rename from x-pack/plugins/security_solution/public/overview/images/siem.png rename to x-pack/plugins/security_solution/public/common/images/siem.png diff --git a/x-pack/plugins/security_solution/public/overview/images/video.svg b/x-pack/plugins/security_solution/public/common/images/video.svg similarity index 100% rename from x-pack/plugins/security_solution/public/overview/images/video.svg rename to x-pack/plugins/security_solution/public/common/images/video.svg diff --git a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx index 01dbfbed6a0c2..b46b3b4177239 100644 --- a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx +++ b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.test.tsx @@ -13,13 +13,17 @@ jest.mock('../route/use_route_spy', () => ({ .fn() .mockImplementationOnce(() => [{ pageName: 'hosts' }]) .mockImplementationOnce(() => [{ pageName: 'rules' }]) - .mockImplementationOnce(() => [{ pageName: 'network' }]), + .mockImplementationOnce(() => [{ pageName: 'network' }]) + .mockImplementationOnce(() => [{ pageName: 'get_started' }]) + .mockImplementationOnce(() => [{ pageName: 'get_started' }]), })); jest.mock('../../../common/containers/sourcerer', () => ({ useSourcererDataView: jest .fn() .mockImplementationOnce(() => [{ indicesExist: false }]) .mockImplementationOnce(() => [{ indicesExist: false }]) + .mockImplementationOnce(() => [{ indicesExist: true }]) + .mockImplementationOnce(() => [{ indicesExist: false }]) .mockImplementationOnce(() => [{ indicesExist: true }]), })); @@ -48,4 +52,22 @@ describe('use show pages with empty view', () => { expect(emptyResult).toEqual(true); }); }); + + it('apply empty view for the landing page if indices do not exist', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook(() => useShowPagesWithEmptyView()); + await waitForNextUpdate(); + const emptyResult = result.current; + expect(emptyResult).toEqual(true); + }); + }); + + it('apply empty view for the landing page if indices exist', async () => { + await act(async () => { + const { result, waitForNextUpdate } = renderHook(() => useShowPagesWithEmptyView()); + await waitForNextUpdate(); + const emptyResult = result.current; + expect(emptyResult).toEqual(true); + }); + }); }); diff --git a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx index f863cecffe3d6..3ef27addb8efe 100644 --- a/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx +++ b/x-pack/plugins/security_solution/public/common/utils/empty_view/use_show_pages_with_empty_view.tsx @@ -25,7 +25,8 @@ export const useShowPagesWithEmptyView = () => { const [{ pageName }] = useRouteSpy(); const { indicesExist } = useSourcererDataView(); - const shouldShowEmptyState = isPageNameWithEmptyView(pageName) && !indicesExist; + const shouldShowEmptyState = + (isPageNameWithEmptyView(pageName) && !indicesExist) || pageName === SecurityPageName.landing; const [showEmptyState, setShowEmptyState] = useState(shouldShowEmptyState); diff --git a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx index 3262fc36abf75..0001c2966c1bc 100644 --- a/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/osquery/osquery_flyout.tsx @@ -45,7 +45,7 @@ export const OsqueryFlyout: React.FC = ({ agentId, onClose } - + diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/actions_description.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/actions_description.tsx index 43b703512d6e6..8618575a7a4c9 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/actions_description.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/actions_description.tsx @@ -7,9 +7,9 @@ import React from 'react'; import { startCase } from 'lodash/fp'; -import { AlertAction } from '../../../../../../alerting/common'; +import { RuleAction } from '../../../../../../alerting/common'; -const ActionsDescription = ({ actions }: { actions: AlertAction[] }) => { +const ActionsDescription = ({ actions }: { actions: RuleAction[] }) => { if (!actions.length) return null; return ( @@ -21,12 +21,12 @@ const ActionsDescription = ({ actions }: { actions: AlertAction[] }) => { ); }; -export const buildActionsDescription = (actions: AlertAction[], title: string) => ({ +export const buildActionsDescription = (actions: RuleAction[], title: string) => ({ title: actions.length ? title : '', description: , }); -const getActionTypeName = (actionTypeId: AlertAction['actionTypeId']) => { +const getActionTypeName = (actionTypeId: RuleAction['actionTypeId']) => { if (!actionTypeId) return ''; const actionType = actionTypeId.split('.')[1]; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx index 55154def55b50..5fb7266e228a5 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/rule_actions_field/index.tsx @@ -20,7 +20,7 @@ import { loadActionTypes, ActionVariables, } from '../../../../../../triggers_actions_ui/public'; -import { AlertAction } from '../../../../../../alerting/common'; +import { RuleAction } from '../../../../../../alerting/common'; import { convertArrayToCamelCase, useKibana } from '../../../../common/lib/kibana'; import { FORM_ERRORS_TITLE } from './translations'; @@ -87,8 +87,8 @@ export const RuleActionsField: React.FC = ({ triggersActionsUi: { actionTypeRegistry }, } = useKibana().services; - const actions: AlertAction[] = useMemo( - () => (!isEmpty(field.value) ? (field.value as AlertAction[]) : []), + const actions: RuleAction[] = useMemo( + () => (!isEmpty(field.value) ? (field.value as RuleAction[]) : []), [field.value] ); @@ -105,7 +105,7 @@ export const RuleActionsField: React.FC = ({ const setActionIdByIndex = useCallback( (id: string, index: number) => { - const updatedActions = [...(actions as Array>)]; + const updatedActions = [...(actions as Array>)]; updatedActions[index] = deepMerge(updatedActions[index], { id }); field.setValue(updatedActions); }, @@ -114,7 +114,7 @@ export const RuleActionsField: React.FC = ({ ); const setAlertActionsProperty = useCallback( - (updatedActions: AlertAction[]) => field.setValue(updatedActions), + (updatedActions: RuleAction[]) => field.setValue(updatedActions), [field] ); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index 797f67e1fbae5..9438d409f0914 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -43,8 +43,8 @@ import { } from '../../../../../common/detection_engine/schemas/request'; /** - * Params is an "record", since it is a type of AlertActionParams which is action templates. - * @see x-pack/plugins/alerting/common/alert.ts + * Params is an "record", since it is a type of RuleActionParams which is action templates. + * @see x-pack/plugins/alerting/common/rule.ts * @deprecated Use the one from @kbn/security-io-ts-alerting-types */ export const action = t.exact( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx index 5bd6875032e03..3fc05c0ef428f 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @@ -40,7 +40,6 @@ import { AlertsTable } from '../../components/alerts_table'; import { NoApiIntegrationKeyCallOut } from '../../components/callouts/no_api_integration_callout'; import { AlertsHistogramPanel } from '../../components/alerts_kpis/alerts_histogram_panel'; import { useUserData } from '../../components/user_info'; -import { OverviewEmpty } from '../../../overview/components/overview_empty'; import { DetectionEngineNoIndex } from './detection_engine_no_index'; import { useListsConfig } from '../../containers/detection_engine/lists/use_lists_config'; import { DetectionEngineUserUnauthenticated } from './detection_engine_user_unauthenticated'; @@ -77,6 +76,7 @@ import { } from '../../components/alerts_table/alerts_filter_group'; import { EmptyPage } from '../../../common/components/empty_page'; import { HeaderPage } from '../../../common/components/header_page'; +import { LandingPageComponent } from '../../../common/components/landing_page'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. */ @@ -389,10 +389,7 @@ const DetectionEnginePageComponent: React.FC = ({ ) : ( - - - - + )} ); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts index c1141ba527dbd..567e408089883 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts @@ -17,7 +17,7 @@ import { } from '@kbn/securitysolution-io-ts-alerting-types'; import type { Filter } from '@kbn/es-query'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; -import { AlertAction } from '../../../../../../alerting/common'; +import { RuleAction } from '../../../../../../alerting/common'; import { FieldValueQueryBar } from '../../../components/rules/query_bar'; import { FieldValueTimeline } from '../../../components/rules/pick_timeline'; import { FieldValueThreshold } from '../../../components/rules/threshold_input'; @@ -143,7 +143,7 @@ export interface ScheduleStepRule { } export interface ActionsStepRule { - actions: AlertAction[]; + actions: RuleAction[]; enabled: boolean; kibanaSiemAppUrl?: string; throttle?: string | null; diff --git a/x-pack/plugins/security_solution/public/helpers.test.tsx b/x-pack/plugins/security_solution/public/helpers.test.tsx index dd380fc3ccd39..4f39ea32c6d5d 100644 --- a/x-pack/plugins/security_solution/public/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/helpers.test.tsx @@ -193,7 +193,7 @@ describe('RedirectRoute', () => { } as unknown as Capabilities; expect(shallow()).toMatchInlineSnapshot(` `); }); @@ -205,7 +205,7 @@ describe('RedirectRoute', () => { } as unknown as Capabilities; expect(shallow()).toMatchInlineSnapshot(` `); }); @@ -217,7 +217,7 @@ describe('RedirectRoute', () => { } as unknown as Capabilities; expect(shallow()).toMatchInlineSnapshot(` `); }); @@ -229,7 +229,7 @@ describe('RedirectRoute', () => { } as unknown as Capabilities; expect(shallow()).toMatchInlineSnapshot(` `); }); @@ -241,7 +241,7 @@ describe('RedirectRoute', () => { } as unknown as Capabilities; expect(shallow()).toMatchInlineSnapshot(` `); }); diff --git a/x-pack/plugins/security_solution/public/helpers.tsx b/x-pack/plugins/security_solution/public/helpers.tsx index fa0b8d115ea40..adc22b96d2050 100644 --- a/x-pack/plugins/security_solution/public/helpers.tsx +++ b/x-pack/plugins/security_solution/public/helpers.tsx @@ -18,7 +18,7 @@ import { RULES_PATH, SERVER_APP_ID, CASES_FEATURE_ID, - OVERVIEW_PATH, + LANDING_PATH, CASES_PATH, } from '../common/constants'; import { Ecs } from '../common/ecs'; @@ -138,7 +138,7 @@ export const manageOldSiemRoutes = async (coreStart: CoreStart) => { break; default: application.navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.overview, + deepLinkId: SecurityPageName.landing, replace: true, path, }); @@ -197,12 +197,12 @@ export const RedirectRoute = React.memo<{ capabilities: Capabilities }>(({ capab const overviewAvailable = isSubPluginAvailable('overview', capabilities); const casesAvailable = isSubPluginAvailable(CASES_SUB_PLUGIN_KEY, capabilities); if (overviewAvailable) { - return ; + return ; } if (casesAvailable) { return ; } - return ; + return ; }); RedirectRoute.displayName = 'RedirectRoute'; diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/__snapshots__/index.test.tsx.snap deleted file mode 100644 index bffd5e2261ad9..0000000000000 --- a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/__snapshots__/index.test.tsx.snap +++ /dev/null @@ -1,113 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Authentication Table Component rendering it renders the authentication table 1`] = ` - -`; diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.test.tsx b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.test.tsx deleted file mode 100644 index 2ec333e335639..0000000000000 --- a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.test.tsx +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { shallow } from 'enzyme'; -import { getOr } from 'lodash/fp'; -import React from 'react'; -import { Provider as ReduxStoreProvider } from 'react-redux'; - -import '../../../common/mock/match_media'; -import { - mockGlobalState, - SUB_PLUGINS_REDUCER, - kibanaObservable, - createSecuritySolutionStorageMock, -} from '../../../common/mock'; -import { createStore, State } from '../../../common/store'; -import { hostsModel } from '../../store'; -import { mockData } from './mock'; -import * as i18n from './translations'; -import { AuthenticationTable, getAuthenticationColumnsCurated } from '.'; - -describe('Authentication Table Component', () => { - const loadPage = jest.fn(); - const state: State = mockGlobalState; - - const { storage } = createSecuritySolutionStorageMock(); - let store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - - beforeEach(() => { - store = createStore(state, SUB_PLUGINS_REDUCER, kibanaObservable, storage); - }); - - describe('rendering', () => { - test('it renders the authentication table', () => { - const wrapper = shallow( - - - - ); - - expect(wrapper.find('Memo(AuthenticationTableComponent)')).toMatchSnapshot(); - }); - }); - - describe('columns', () => { - test('on hosts page, we expect to get all columns', () => { - expect(getAuthenticationColumnsCurated(hostsModel.HostsType.page, false).length).toEqual(9); - }); - - test('on host details page, we expect to remove two columns', () => { - const columns = getAuthenticationColumnsCurated(hostsModel.HostsType.details, false); - expect(columns.length).toEqual(7); - }); - - test('on host details page, we should have Last Failed Destination column', () => { - const columns = getAuthenticationColumnsCurated(hostsModel.HostsType.page, false); - expect(columns.some((col) => col.name === i18n.LAST_FAILED_DESTINATION)).toEqual(true); - }); - - test('on host details page, we should not have Last Failed Destination column', () => { - const columns = getAuthenticationColumnsCurated(hostsModel.HostsType.details, false); - expect(columns.some((col) => col.name === i18n.LAST_FAILED_DESTINATION)).toEqual(false); - }); - - test('on host page, we should have Last Successful Destination column', () => { - const columns = getAuthenticationColumnsCurated(hostsModel.HostsType.page, false); - expect(columns.some((col) => col.name === i18n.LAST_SUCCESSFUL_DESTINATION)).toEqual(true); - }); - - test('on host details page, we should not have Last Successful Destination column', () => { - const columns = getAuthenticationColumnsCurated(hostsModel.HostsType.details, false); - expect(columns.some((col) => col.name === i18n.LAST_SUCCESSFUL_DESTINATION)).toEqual(false); - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx deleted file mode 100644 index 2bbda82e15315..0000000000000 --- a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/index.tsx +++ /dev/null @@ -1,330 +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 { has } from 'lodash/fp'; -import React, { useCallback, useMemo } from 'react'; -import { useDispatch } from 'react-redux'; - -import { AuthenticationsEdges } from '../../../../common/search_strategy/security_solution/hosts/authentications'; - -import { - DragEffects, - DraggableWrapper, -} from '../../../common/components/drag_and_drop/draggable_wrapper'; -import { escapeDataProviderId } from '../../../common/components/drag_and_drop/helpers'; -import { getEmptyTagValue } from '../../../common/components/empty_value'; -import { FormattedRelativePreferenceDate } from '../../../common/components/formatted_date'; -import { - HostDetailsLink, - NetworkDetailsLink, - UserDetailsLink, -} from '../../../common/components/links'; -import { Columns, ItemsPerRow, PaginatedTable } from '../../../common/components/paginated_table'; -import { IS_OPERATOR } from '../../../timelines/components/timeline/data_providers/data_provider'; -import { Provider } from '../../../timelines/components/timeline/data_providers/provider'; -import { getRowItemDraggables } from '../../../common/components/tables/helpers'; -import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; -import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; - -import { hostsActions, hostsModel, hostsSelectors } from '../../store'; - -import * as i18n from './translations'; - -const tableType = hostsModel.HostsTableType.authentications; - -interface AuthenticationTableProps { - data: AuthenticationsEdges[]; - fakeTotalCount: number; - loading: boolean; - loadPage: (newActivePage: number) => void; - id: string; - isInspect: boolean; - setQuerySkip: (skip: boolean) => void; - showMorePagesIndicator: boolean; - totalCount: number; - type: hostsModel.HostsType; -} - -export type AuthTableColumns = [ - Columns, - Columns, - Columns, - Columns, - Columns, - Columns, - Columns, - Columns, - Columns -]; - -const rowItems: ItemsPerRow[] = [ - { - text: i18n.ROWS_5, - numberOfRow: 5, - }, - { - text: i18n.ROWS_10, - numberOfRow: 10, - }, -]; - -const AuthenticationTableComponent: React.FC = ({ - data, - fakeTotalCount, - id, - isInspect, - loading, - loadPage, - setQuerySkip, - showMorePagesIndicator, - totalCount, - type, -}) => { - const dispatch = useDispatch(); - const getAuthenticationsSelector = useMemo(() => hostsSelectors.authenticationsSelector(), []); - const { activePage, limit } = useDeepEqualSelector((state) => - getAuthenticationsSelector(state, type) - ); - - const updateLimitPagination = useCallback( - (newLimit) => - dispatch( - hostsActions.updateTableLimit({ - hostsType: type, - limit: newLimit, - tableType, - }) - ), - [type, dispatch] - ); - - const updateActivePage = useCallback( - (newPage) => - dispatch( - hostsActions.updateTableActivePage({ - activePage: newPage, - hostsType: type, - tableType, - }) - ), - [type, dispatch] - ); - - const usersEnabled = useIsExperimentalFeatureEnabled('usersEnabled'); - const columns = useMemo( - () => getAuthenticationColumnsCurated(type, usersEnabled), - [type, usersEnabled] - ); - - return ( - - ); -}; - -AuthenticationTableComponent.displayName = 'AuthenticationTableComponent'; - -export const AuthenticationTable = React.memo(AuthenticationTableComponent); - -const getAuthenticationColumns = (usersEnabled: boolean): AuthTableColumns => [ - { - name: i18n.USER, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - getRowItemDraggables({ - rowItems: node.user.name, - attrName: 'user.name', - idPrefix: `authentications-table-${node._id}-userName`, - render: (item) => (usersEnabled ? : <>{item}), - }), - }, - { - name: i18n.SUCCESSES, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => { - const id = escapeDataProviderId( - `authentications-table-${node._id}-node-successes-${node.successes}` - ); - return ( - - snapshot.isDragging ? ( - - - - ) : ( - node.successes - ) - } - /> - ); - }, - width: '8%', - }, - { - name: i18n.FAILURES, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => { - const id = escapeDataProviderId( - `authentications-table-${node._id}-failures-${node.failures}` - ); - return ( - - snapshot.isDragging ? ( - - - - ) : ( - node.failures - ) - } - /> - ); - }, - width: '8%', - }, - { - name: i18n.LAST_SUCCESSFUL_TIME, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - has('lastSuccess.timestamp', node) && node.lastSuccess?.timestamp != null ? ( - - ) : ( - getEmptyTagValue() - ), - }, - { - name: i18n.LAST_SUCCESSFUL_SOURCE, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - getRowItemDraggables({ - rowItems: node.lastSuccess?.source?.ip || null, - attrName: 'source.ip', - idPrefix: `authentications-table-${node._id}-lastSuccessSource`, - render: (item) => , - }), - }, - { - name: i18n.LAST_SUCCESSFUL_DESTINATION, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - getRowItemDraggables({ - rowItems: node.lastSuccess?.host?.name ?? null, - attrName: 'host.name', - idPrefix: `authentications-table-${node._id}-lastSuccessfulDestination`, - render: (item) => , - }), - }, - { - name: i18n.LAST_FAILED_TIME, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - has('lastFailure.timestamp', node) && node.lastFailure?.timestamp != null ? ( - - ) : ( - getEmptyTagValue() - ), - }, - { - name: i18n.LAST_FAILED_SOURCE, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - getRowItemDraggables({ - rowItems: node.lastFailure?.source?.ip || null, - attrName: 'source.ip', - idPrefix: `authentications-table-${node._id}-lastFailureSource`, - render: (item) => , - }), - }, - { - name: i18n.LAST_FAILED_DESTINATION, - truncateText: false, - mobileOptions: { show: true }, - render: ({ node }) => - getRowItemDraggables({ - rowItems: node.lastFailure?.host?.name || null, - attrName: 'host.name', - idPrefix: `authentications-table-${node._id}-lastFailureDestination`, - render: (item) => , - }), - }, -]; - -export const getAuthenticationColumnsCurated = ( - pageType: hostsModel.HostsType, - usersEnabled: boolean -): AuthTableColumns => { - const columns = getAuthenticationColumns(usersEnabled); - - // Columns to exclude from host details pages - if (pageType === hostsModel.HostsType.details) { - return [i18n.LAST_FAILED_DESTINATION, i18n.LAST_SUCCESSFUL_DESTINATION].reduce((acc, name) => { - acc.splice( - acc.findIndex((column) => column.name === name), - 1 - ); - return acc; - }, columns); - } - - return columns; -}; diff --git a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/mock.ts b/x-pack/plugins/security_solution/public/hosts/components/authentications_table/mock.ts deleted file mode 100644 index caf441b34ca90..0000000000000 --- a/x-pack/plugins/security_solution/public/hosts/components/authentications_table/mock.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { HostAuthenticationsStrategyResponse } from '../../../../common/search_strategy/security_solution/hosts/authentications'; - -export const mockData: { Authentications: HostAuthenticationsStrategyResponse } = { - Authentications: { - rawResponse: { - took: 880, - timed_out: false, - _shards: { - total: 26, - successful: 26, - skipped: 0, - failed: 0, - }, - hits: { - total: 2, - hits: [], - }, - aggregations: { - group_by_users: { - buckets: [ - { - key: 'SYSTEM', - doc_count: 4, - failures: { - doc_count: 0, - lastFailure: { hits: { total: 0, max_score: null, hits: [] } }, - hits: { total: 0, max_score: null, hits: [] }, - }, - successes: { - doc_count: 4, - lastSuccess: { hits: { total: 4, max_score: null } }, - }, - }, - ], - doc_count_error_upper_bound: -1, - sum_other_doc_count: 566, - }, - }, - } as estypes.SearchResponse, - totalCount: 54, - edges: [ - { - node: { - _id: 'cPsuhGcB0WOhS6qyTKC0', - failures: 10, - successes: 0, - user: { name: ['Evan Hassanabad'] }, - lastSuccess: { - timestamp: '2019-01-23T22:35:32.222Z', - source: { - ip: ['127.0.0.1'], - }, - host: { - id: ['host-id-1'], - name: ['host-1'], - }, - }, - lastFailure: { - timestamp: '2019-01-23T22:35:32.222Z', - source: { - ip: ['8.8.8.8'], - }, - host: { - id: ['host-id-1'], - name: ['host-2'], - }, - }, - }, - cursor: { - value: '98966fa2013c396155c460d35c0902be', - }, - }, - { - node: { - _id: 'KwQDiWcB0WOhS6qyXmrW', - failures: 10, - successes: 0, - user: { name: ['Braden Hassanabad'] }, - lastSuccess: { - timestamp: '2019-01-23T22:35:32.222Z', - source: { - ip: ['127.0.0.1'], - }, - host: { - id: ['host-id-1'], - name: ['host-1'], - }, - }, - lastFailure: { - timestamp: '2019-01-23T22:35:32.222Z', - source: { - ip: ['8.8.8.8'], - }, - host: { - id: ['host-id-1'], - name: ['host-2'], - }, - }, - }, - cursor: { - value: 'aa7ca589f1b8220002f2fc61c64cfbf1', - }, - }, - ], - pageInfo: { - activePage: 1, - fakeTotalCount: 50, - showMorePagesIndicator: true, - }, - }, -}; diff --git a/x-pack/plugins/security_solution/public/hosts/components/hosts_table/index.tsx b/x-pack/plugins/security_solution/public/hosts/components/hosts_table/index.tsx index 42c8254ffd183..1326f24b5335f 100644 --- a/x-pack/plugins/security_solution/public/hosts/components/hosts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/components/hosts_table/index.tsx @@ -8,7 +8,6 @@ import React, { useMemo, useCallback } from 'react'; import { useDispatch } from 'react-redux'; -import { assertUnreachable } from '../../../../common/utility_types'; import { Columns, Criteria, @@ -204,7 +203,6 @@ const getNodeField = (field: HostsFields): string => { case HostsFields.lastSeen: return 'node.lastSeen'; } - assertUnreachable(field); }; export const HostsTable = React.memo(HostsTableComponent); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx index 45daa31a4ec37..f1b03c7a3c4c4 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/details/index.tsx @@ -36,7 +36,6 @@ import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { getEsQueryConfig } from '../../../../../../../src/plugins/data/common'; -import { OverviewEmpty } from '../../../overview/components/overview_empty'; import { HostDetailsTabs } from './details_tabs'; import { navTabsHostDetails } from './nav_tabs'; import { HostDetailsProps } from './types'; @@ -54,6 +53,7 @@ import { manageQuery } from '../../../common/components/page/manage_query'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; +import { LandingPageComponent } from '../../../common/components/landing_page'; const HostOverviewManage = manageQuery(HostOverview); @@ -227,9 +227,7 @@ const HostDetailsComponent: React.FC = ({ detailName, hostDeta ) : ( - - - + )} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx index d82189ab1e3bb..bdf249dc07526 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.test.tsx @@ -25,8 +25,7 @@ import { Hosts } from './hosts'; import { HostsTabs } from './hosts_tabs'; import { useSourcererDataView } from '../../common/containers/sourcerer'; import { mockCasesContract } from '../../../../cases/public/mocks'; -import { APP_UI_ID, SecurityPageName } from '../../../common/constants'; -import { getAppLandingUrl } from '../../common/components/link_to/redirect_to_overview'; +import { LandingPageComponent } from '../../common/components/landing_page'; jest.mock('../../common/containers/sourcerer'); @@ -93,17 +92,15 @@ describe('Hosts - rendering', () => { indicesExist: false, }); - mount( + const wrapper = mount( ); - expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); + + expect(wrapper.find(LandingPageComponent).exists()).toBe(true); }); test('it DOES NOT render the Setup Instructions text when an index is available', async () => { diff --git a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx index 3b57a22d15a6a..8d2255655b685 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/hosts.tsx @@ -35,7 +35,6 @@ import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { getEsQueryConfig } from '../../../../../../src/plugins/data/common'; import { useMlCapabilities } from '../../common/components/ml/hooks/use_ml_capabilities'; -import { OverviewEmpty } from '../../overview/components/overview_empty'; import { Display } from './display'; import { HostsTabs } from './hosts_tabs'; import { navTabsHosts } from './nav_tabs'; @@ -56,6 +55,8 @@ import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_que import { ID } from '../containers/hosts'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { filterHostExternalAlertData } from '../../common/components/visualization_actions/utils'; +import { LandingPageComponent } from '../../common/components/landing_page'; +import { Loader } from '../../common/components/loader'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. @@ -128,7 +129,8 @@ const HostsComponent = () => { }, [dispatch] ); - const { docValueFields, indicesExist, indexPattern, selectedPatterns } = useSourcererDataView(); + const { docValueFields, indicesExist, indexPattern, selectedPatterns, loading } = + useSourcererDataView(); const [filterQuery, kqlError] = useMemo( () => convertToBuildEsQuery({ @@ -179,6 +181,10 @@ const HostsComponent = () => { [containerElement, onSkipFocusBeforeEventsTable, onSkipFocusAfterEventsTable] ); + if (loading) { + return ; + } + return ( <> {indicesExist ? ( @@ -240,9 +246,7 @@ const HostsComponent = () => { ) : ( - - - + )} diff --git a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx index e42be25941ea7..00afec5da3756 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/index.tsx @@ -50,7 +50,12 @@ export const HostsContainer = React.memo(() => ( match: { params: { detailName }, }, - }) => } + }) => ( + + )} /> { - const mockUseAuthentications = useAuthentications as jest.Mock; - const mockUseQueryToggle = useQueryToggle as jest.Mock; - const defaultProps = { - indexNames: [], - setQuery: jest.fn(), - skip: false, - startDate: '2019-06-25T04:31:59.345Z', - endDate: '2019-06-25T06:31:59.345Z', - type: HostsType.page, - }; - beforeEach(() => { - jest.clearAllMocks(); - mockUseQueryToggle.mockReturnValue({ toggleStatus: true, setToggleStatus: jest.fn() }); - mockUseAuthentications.mockReturnValue([ - false, - { - authentications: [], - id: '123', - inspect: { - dsl: [], - response: [], - }, - isInspected: false, - totalCount: 0, - pageInfo: { activePage: 1, fakeTotalCount: 100, showMorePagesIndicator: false }, - loadPage: jest.fn(), - refetch: jest.fn(), - }, - ]); - }); - it('toggleStatus=true, do not skip', () => { - render( - - - - ); - expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(false); - }); - it('toggleStatus=false, skip', () => { - mockUseQueryToggle.mockReturnValue({ toggleStatus: false, setToggleStatus: jest.fn() }); - render( - - - - ); - expect(mockUseAuthentications.mock.calls[0][0].skip).toEqual(true); - }); -}); diff --git a/x-pack/plugins/security_solution/public/hosts/pages/navigation/authentications_query_tab_body.tsx b/x-pack/plugins/security_solution/public/hosts/pages/navigation/authentications_query_tab_body.tsx index 1096085b93016..0f6de80343b11 100644 --- a/x-pack/plugins/security_solution/public/hosts/pages/navigation/authentications_query_tab_body.tsx +++ b/x-pack/plugins/security_solution/public/hosts/pages/navigation/authentications_query_tab_body.tsx @@ -5,11 +5,7 @@ * 2.0. */ -import { getOr } from 'lodash/fp'; -import React, { useEffect, useState } from 'react'; -import { AuthenticationTable } from '../../components/authentications_table'; -import { manageQuery } from '../../../common/components/page/manage_query'; -import { useAuthentications } from '../../containers/authentications'; +import React from 'react'; import { HostsComponentsQueryProps } from './types'; import { MatrixHistogramOption, @@ -22,11 +18,9 @@ import * as i18n from '../translations'; import { MatrixHistogramType } from '../../../../common/search_strategy/security_solution'; import { authenticationLensAttributes } from '../../../common/components/visualization_actions/lens_attributes/hosts/authentication'; import { LensAttributes } from '../../../common/components/visualization_actions/types'; -import { useQueryToggle } from '../../../common/containers/query_toggle'; +import { AuthenticationsHostTable } from '../../../common/components/authentication/authentications_host_table'; -const AuthenticationTableManage = manageQuery(AuthenticationTable); - -const ID = 'authenticationsHistogramQuery'; +const HISTOGRAM_QUERY_ID = 'authenticationsHistogramQuery'; const authenticationsStackByOptions: MatrixHistogramOption[] = [ { @@ -77,59 +71,28 @@ const AuthenticationsQueryTabBodyComponent: React.FC startDate, type, }) => { - const { toggleStatus } = useQueryToggle(ID); - const [querySkip, setQuerySkip] = useState(skip || !toggleStatus); - useEffect(() => { - setQuerySkip(skip || !toggleStatus); - }, [skip, toggleStatus]); - const [ - loading, - { authentications, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch }, - ] = useAuthentications({ - docValueFields, - endDate, - filterQuery, - indexNames, - skip: querySkip, - startDate, - type, - }); - - useEffect(() => { - return () => { - if (deleteQuery) { - deleteQuery({ id: ID }); - } - }; - }, [deleteQuery]); - return ( <> - ); diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/text_value_display.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/text_value_display.tsx index dedb2c0ada87e..327eb963bbb7d 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/text_value_display.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_entry_card/components/text_value_display.tsx @@ -43,7 +43,7 @@ export const TextValueDisplay = memo( }, [bold, children]); return ( - + {withTooltip && 'string' === typeof children && children.length > 0 && diff --git a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap index 9ec4b93c7c8af..665122574de70 100644 --- a/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap +++ b/x-pack/plugins/security_solution/public/management/pages/trusted_apps/view/components/trusted_apps_grid/__snapshots__/index.test.tsx.snap @@ -513,7 +513,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -523,7 +523,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -559,7 +559,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -569,7 +569,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -678,7 +678,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -743,7 +743,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -773,7 +773,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -785,7 +785,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 0 @@ -895,7 +895,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -905,7 +905,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -941,7 +941,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -951,7 +951,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -1060,7 +1060,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -1125,7 +1125,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -1155,7 +1155,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -1167,7 +1167,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 1 @@ -1277,7 +1277,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -1287,7 +1287,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -1323,7 +1323,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -1333,7 +1333,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -1442,7 +1442,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -1507,7 +1507,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -1537,7 +1537,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -1549,7 +1549,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 2 @@ -1659,7 +1659,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -1669,7 +1669,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -1705,7 +1705,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -1715,7 +1715,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -1824,7 +1824,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -1889,7 +1889,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -1919,7 +1919,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -1931,7 +1931,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 3 @@ -2041,7 +2041,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -2051,7 +2051,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -2087,7 +2087,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -2097,7 +2097,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -2206,7 +2206,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -2271,7 +2271,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -2301,7 +2301,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -2313,7 +2313,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 4 @@ -2423,7 +2423,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -2433,7 +2433,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -2469,7 +2469,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -2479,7 +2479,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -2588,7 +2588,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -2653,7 +2653,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -2683,7 +2683,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -2695,7 +2695,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 5 @@ -2805,7 +2805,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -2815,7 +2815,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -2851,7 +2851,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -2861,7 +2861,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -2970,7 +2970,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -3035,7 +3035,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -3065,7 +3065,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -3077,7 +3077,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 6 @@ -3187,7 +3187,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -3197,7 +3197,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -3233,7 +3233,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -3243,7 +3243,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -3352,7 +3352,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -3417,7 +3417,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -3447,7 +3447,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -3459,7 +3459,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 7 @@ -3569,7 +3569,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -3579,7 +3579,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -3615,7 +3615,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -3625,7 +3625,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -3734,7 +3734,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -3799,7 +3799,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -3829,7 +3829,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -3841,7 +3841,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 8 @@ -3951,7 +3951,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -3961,7 +3961,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -3997,7 +3997,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -4007,7 +4007,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -4116,7 +4116,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -4181,7 +4181,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -4211,7 +4211,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -4223,7 +4223,7 @@ exports[`TrustedAppsGrid renders correctly when loaded data 1`] = ` class="euiSpacer euiSpacer--l" />
Trusted App 9 @@ -4665,7 +4665,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -4675,7 +4675,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -4711,7 +4711,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -4721,7 +4721,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -4830,7 +4830,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -4895,7 +4895,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -4925,7 +4925,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -4937,7 +4937,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 0 @@ -5047,7 +5047,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -5057,7 +5057,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -5093,7 +5093,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -5103,7 +5103,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -5212,7 +5212,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -5277,7 +5277,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -5307,7 +5307,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -5319,7 +5319,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 1 @@ -5429,7 +5429,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -5439,7 +5439,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -5475,7 +5475,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -5485,7 +5485,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -5594,7 +5594,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -5659,7 +5659,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -5689,7 +5689,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -5701,7 +5701,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 2 @@ -5811,7 +5811,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -5821,7 +5821,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -5857,7 +5857,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -5867,7 +5867,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -5976,7 +5976,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -6041,7 +6041,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -6071,7 +6071,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -6083,7 +6083,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 3 @@ -6193,7 +6193,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -6203,7 +6203,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -6239,7 +6239,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -6249,7 +6249,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -6358,7 +6358,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -6423,7 +6423,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -6453,7 +6453,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -6465,7 +6465,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 4 @@ -6575,7 +6575,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -6585,7 +6585,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -6621,7 +6621,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -6631,7 +6631,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -6740,7 +6740,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -6805,7 +6805,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -6835,7 +6835,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -6847,7 +6847,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 5 @@ -6957,7 +6957,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -6967,7 +6967,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -7003,7 +7003,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -7013,7 +7013,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -7122,7 +7122,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -7187,7 +7187,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -7217,7 +7217,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -7229,7 +7229,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 6 @@ -7339,7 +7339,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -7349,7 +7349,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -7385,7 +7385,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -7395,7 +7395,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -7504,7 +7504,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -7569,7 +7569,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -7599,7 +7599,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -7611,7 +7611,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 7 @@ -7721,7 +7721,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -7731,7 +7731,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -7767,7 +7767,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -7777,7 +7777,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -7886,7 +7886,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -7951,7 +7951,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -7981,7 +7981,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -7993,7 +7993,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 8 @@ -8103,7 +8103,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -8113,7 +8113,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -8149,7 +8149,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -8159,7 +8159,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -8268,7 +8268,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -8333,7 +8333,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -8363,7 +8363,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -8375,7 +8375,7 @@ exports[`TrustedAppsGrid renders correctly when loading data for the second time class="euiSpacer euiSpacer--l" />
Trusted App 9 @@ -8774,7 +8774,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -8784,7 +8784,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -8820,7 +8820,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -8830,7 +8830,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -8939,7 +8939,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -9004,7 +9004,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -9034,7 +9034,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -9046,7 +9046,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 0 @@ -9156,7 +9156,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -9166,7 +9166,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -9202,7 +9202,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -9212,7 +9212,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -9321,7 +9321,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -9386,7 +9386,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -9416,7 +9416,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -9428,7 +9428,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 1 @@ -9538,7 +9538,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -9548,7 +9548,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -9584,7 +9584,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -9594,7 +9594,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -9703,7 +9703,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -9768,7 +9768,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -9798,7 +9798,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -9810,7 +9810,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 2 @@ -9920,7 +9920,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -9930,7 +9930,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -9966,7 +9966,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -9976,7 +9976,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -10085,7 +10085,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -10150,7 +10150,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -10180,7 +10180,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -10192,7 +10192,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 3 @@ -10302,7 +10302,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -10312,7 +10312,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -10348,7 +10348,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -10358,7 +10358,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -10467,7 +10467,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -10532,7 +10532,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -10562,7 +10562,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -10574,7 +10574,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 4 @@ -10684,7 +10684,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -10694,7 +10694,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -10730,7 +10730,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -10740,7 +10740,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -10849,7 +10849,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -10914,7 +10914,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -10944,7 +10944,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -10956,7 +10956,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 5 @@ -11066,7 +11066,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -11076,7 +11076,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -11112,7 +11112,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -11122,7 +11122,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -11231,7 +11231,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -11296,7 +11296,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -11326,7 +11326,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -11338,7 +11338,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 6 @@ -11448,7 +11448,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -11458,7 +11458,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -11494,7 +11494,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -11504,7 +11504,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -11613,7 +11613,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -11678,7 +11678,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -11708,7 +11708,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -11720,7 +11720,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 7 @@ -11830,7 +11830,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -11840,7 +11840,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -11876,7 +11876,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -11886,7 +11886,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -11995,7 +11995,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -12060,7 +12060,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -12090,7 +12090,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -12102,7 +12102,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 8 @@ -12212,7 +12212,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-label" >
Last updated
@@ -12222,7 +12222,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-updated-value" >
1 minute ago @@ -12258,7 +12258,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-label" >
Created
@@ -12268,7 +12268,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-header-created-value" >
1 minute ago @@ -12377,7 +12377,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-createdBy-value" >
someone
@@ -12442,7 +12442,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-touchedBy-updatedBy-value" >
someone
@@ -12472,7 +12472,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not data-test-subj="trustedAppCard-subHeader-effectScope-value" >
Applied globally
@@ -12484,7 +12484,7 @@ exports[`TrustedAppsGrid renders correctly when new page and page size set (not class="euiSpacer euiSpacer--l" />
Trusted App 9 diff --git a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx index ef7dea5164468..f8aa0a5d85730 100644 --- a/x-pack/plugins/security_solution/public/network/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/details/index.tsx @@ -38,7 +38,6 @@ import { inputsSelectors } from '../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions'; import { setNetworkDetailsTablesActivePageToZero } from '../../store/actions'; import { SpyRoute } from '../../../common/utils/route/spy_routes'; -import { OverviewEmpty } from '../../../overview/components/overview_empty'; import { NetworkHttpQueryTable } from './network_http_query_table'; import { NetworkTopCountriesQueryTable } from './network_top_countries_query_table'; import { NetworkTopNFlowQueryTable } from './network_top_n_flow_query_table'; @@ -50,6 +49,7 @@ import { networkModel } from '../../store'; import { SecurityPageName } from '../../../app/types'; import { useSourcererDataView } from '../../../common/containers/sourcerer'; import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query'; +import { LandingPageComponent } from '../../../common/components/landing_page'; export { getBreadcrumbs } from './utils'; const NetworkDetailsManage = manageQuery(IpOverview); @@ -301,9 +301,7 @@ const NetworkDetailsComponent: React.FC = () => { ) : ( - - - + )} diff --git a/x-pack/plugins/security_solution/public/network/pages/network.test.tsx b/x-pack/plugins/security_solution/public/network/pages/network.test.tsx index 23cd7f707dfe8..bf300569d6e23 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.test.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.test.tsx @@ -25,8 +25,7 @@ import { inputsActions } from '../../common/store/inputs'; import { Network } from './network'; import { NetworkRoutes } from './navigation'; import { mockCasesContract } from '../../../../cases/public/mocks'; -import { APP_UI_ID, SecurityPageName } from '../../../common/constants'; -import { getAppLandingUrl } from '../../common/components/link_to/redirect_to_overview'; +import { LandingPageComponent } from '../../common/components/landing_page'; jest.mock('../../common/containers/sourcerer'); @@ -119,13 +118,13 @@ describe('Network page - rendering', () => { beforeEach(() => { jest.clearAllMocks(); }); - test('it renders the Setup Instructions text when no index is available', () => { + test('it renders getting started page when no index is available', () => { mockUseSourcererDataView.mockReturnValue({ selectedPatterns: [], indicesExist: false, }); - mount( + const wrapper = mount( @@ -133,13 +132,10 @@ describe('Network page - rendering', () => { ); - expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); + expect(wrapper.find(LandingPageComponent).exists()).toBe(true); }); - test('it DOES NOT render the Setup Instructions text when an index is available', async () => { + test('it DOES NOT render getting started page when an index is available', async () => { mockUseSourcererDataView.mockReturnValue({ selectedPatterns: [], indicesExist: true, diff --git a/x-pack/plugins/security_solution/public/network/pages/network.tsx b/x-pack/plugins/security_solution/public/network/pages/network.tsx index 422d2877a8504..634a96b0e74df 100644 --- a/x-pack/plugins/security_solution/public/network/pages/network.tsx +++ b/x-pack/plugins/security_solution/public/network/pages/network.tsx @@ -36,7 +36,6 @@ import { SpyRoute } from '../../common/utils/route/spy_routes'; import { Display } from '../../hosts/pages/display'; import { networkModel } from '../store'; import { navTabsNetwork, NetworkRoutes, NetworkRoutesLoading } from './navigation'; -import { OverviewEmpty } from '../../overview/components/overview_empty'; import * as i18n from './translations'; import { NetworkComponentProps } from './types'; import { NetworkRouteType } from './navigation/types'; @@ -52,6 +51,7 @@ import { useSourcererDataView } from '../../common/containers/sourcerer'; import { useDeepEqualSelector, useShallowEqualSelector } from '../../common/hooks/use_selector'; import { useInvalidFilterQuery } from '../../common/hooks/use_invalid_filter_query'; import { filterNetworkExternalAlertData } from '../../common/components/visualization_actions/utils'; +import { LandingPageComponent } from '../../common/components/landing_page'; /** * Need a 100% height here to account for the graph/analyze tool, which sets no explicit height parameters, but fills the available space. */ @@ -234,9 +234,7 @@ const NetworkComponent = React.memo( ) : ( - - - + )} diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx deleted file mode 100644 index db157e9fc7135..0000000000000 --- a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { shallow } from 'enzyme'; -import { OverviewEmpty } from '.'; -import { APP_UI_ID, SecurityPageName } from '../../../../common/constants'; -import { getAppLandingUrl } from '../../../common/components/link_to/redirect_to_overview'; - -const mockNavigateToApp = jest.fn(); -jest.mock('../../../common/lib/kibana', () => { - const original = jest.requireActual('../../../common/lib/kibana'); - - return { - ...original, - useKibana: () => ({ - services: { - ...original.useKibana().services, - application: { - ...original.useKibana().services.application, - navigateToApp: mockNavigateToApp, - }, - }, - }), - }; -}); - -describe('Redirect to landing page', () => { - it('render with correct actions ', () => { - shallow(); - expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx deleted file mode 100644 index 91395aa21486f..0000000000000 --- a/x-pack/plugins/security_solution/public/overview/components/overview_empty/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { useKibana } from '../../../common/lib/kibana'; -import { APP_UI_ID, SecurityPageName } from '../../../../common/constants'; -import { getAppLandingUrl } from '../../../common/components/link_to/redirect_to_overview'; - -const OverviewEmptyComponent: React.FC = () => { - const { navigateToApp } = useKibana().services.application; - - navigateToApp(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); - return null; -}; - -OverviewEmptyComponent.displayName = 'OverviewEmptyComponent'; - -export const OverviewEmpty = React.memo(OverviewEmptyComponent); diff --git a/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx b/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx index e29ea1e923a63..f3dc4d400c9c2 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/detection_response.tsx @@ -11,7 +11,6 @@ import { SiemSearchBar } from '../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; // import { useGlobalTime } from '../../common/containers/use_global_time'; -import { OverviewEmpty } from '../components/overview_empty'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../app/types'; import { useSourcererDataView } from '../../common/containers/sourcerer'; @@ -20,6 +19,7 @@ import { HeaderPage } from '../../common/components/header_page'; import { useShallowEqualSelector } from '../../common/hooks/use_selector'; import { DETECTION_RESPONSE_TITLE, UPDATED, UPDATING } from './translations'; import { inputsSelectors } from '../../common/store/selectors'; +import { LandingPageComponent } from '../../common/components/landing_page'; const DetectionResponseComponent = () => { const getGlobalQuery = useMemo(() => inputsSelectors.globalQuery(), []); @@ -90,7 +90,7 @@ const DetectionResponseComponent = () => { ) : ( - + )} diff --git a/x-pack/plugins/security_solution/public/overview/pages/landing.tsx b/x-pack/plugins/security_solution/public/overview/pages/landing.tsx index 0554f1f51c28a..0b9760d2a8db4 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/landing.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/landing.tsx @@ -8,15 +8,12 @@ import React, { memo } from 'react'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { SecurityPageName } from '../../../common/constants'; -import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; -import { LandingCards } from '../components/landing_cards'; +import { LandingPageComponent } from '../../common/components/landing_page'; export const LandingPage = memo(() => { return ( <> - - - + ); diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx index e5be86a1c9f91..cd941e26e20a6 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.test.tsx @@ -27,9 +27,8 @@ import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experime import { initialUserPrivilegesState } from '../../common/components/user_privileges/user_privileges_context'; import { EndpointPrivileges } from '../../../common/endpoint/types'; import { useHostRiskScore } from '../../risk_score/containers'; -import { APP_UI_ID, SecurityPageName } from '../../../common/constants'; -import { getAppLandingUrl } from '../../common/components/link_to/redirect_to_overview'; import { mockCasesContract } from '../../../../cases/public/mocks'; +import { LandingPageComponent } from '../../common/components/landing_page'; const mockNavigateToApp = jest.fn(); jest.mock('../../common/lib/kibana', () => { @@ -303,8 +302,8 @@ describe('Overview', () => { mockUseMessagesStorage.mockImplementation(() => endpointNoticeMessage(false)); }); - it('renders the Setup Instructions text', () => { - mount( + it('renders getting started page', () => { + const wrapper = mount( @@ -312,10 +311,7 @@ describe('Overview', () => { ); - expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); + expect(wrapper.find(LandingPageComponent).exists()).toBe(true); }); }); }); diff --git a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx index ca95f41e0ea12..3f3d37cd3abae 100644 --- a/x-pack/plugins/security_solution/public/overview/pages/overview.tsx +++ b/x-pack/plugins/security_solution/public/overview/pages/overview.tsx @@ -17,7 +17,6 @@ import { useFetchIndex } from '../../common/containers/source'; import { EventsByDataset } from '../components/events_by_dataset'; import { EventCounts } from '../components/event_counts'; -import { OverviewEmpty } from '../components/overview_empty'; import { StatefulSidebar } from '../components/sidebar'; import { SignalsByCategory } from '../components/signals_by_category'; import { inputsSelectors } from '../../common/store'; @@ -34,6 +33,7 @@ import { useUserPrivileges } from '../../common/components/user_privileges'; import { RiskyHostLinks } from '../components/overview_risky_host_links'; import { useAlertsPrivileges } from '../../detections/containers/detection_engine/alerts/use_alerts_privileges'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; +import { LandingPageComponent } from '../../common/components/landing_page'; const OverviewComponent = () => { const getGlobalFiltersQuerySelector = useMemo( @@ -173,7 +173,7 @@ const OverviewComponent = () => { ) : ( - + )} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx index 1330795841653..242767eac2432 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/network_details/expandable_network.tsx @@ -22,12 +22,12 @@ import { useKibana } from '../../../../common/lib/kibana'; import { convertToBuildEsQuery } from '../../../../common/lib/keury'; import { inputsSelectors } from '../../../../common/store'; import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions'; -import { OverviewEmpty } from '../../../../overview/components/overview_empty'; import { getEsQueryConfig } from '../../../../../../../../src/plugins/data/common'; import { useSourcererDataView } from '../../../../common/containers/sourcerer'; import { useNetworkDetails } from '../../../../network/containers/details'; import { networkModel } from '../../../../network/store'; import { useAnomaliesTableData } from '../../../../common/components/ml/anomaly/use_anomalies_table_data'; +import { LandingCards } from '../../../../common/components/landing_cards'; interface ExpandableNetworkProps { expandedNetwork: { ip: string; flowTarget: FlowTarget }; @@ -141,6 +141,6 @@ export const ExpandableNetworkDetails = ({ narrowDateRange={narrowDateRange} /> ) : ( - + ); }; diff --git a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx index 6151316cc303d..bf402eb56c291 100644 --- a/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx +++ b/x-pack/plugins/security_solution/public/timelines/pages/timelines_page.tsx @@ -15,7 +15,6 @@ import { HeaderPage } from '../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; import { useKibana } from '../../common/lib/kibana'; import { SpyRoute } from '../../common/utils/route/spy_routes'; -import { OverviewEmpty } from '../../overview/components/overview_empty'; import { StatefulOpenTimeline } from '../components/open_timeline'; import { NEW_TEMPLATE_TIMELINE } from '../components/timeline/properties/translations'; import { NewTemplateTimeline } from '../components/timeline/properties/new_template_timeline'; @@ -23,6 +22,7 @@ import { NewTimeline } from '../components/timeline/properties/helpers'; import * as i18n from './translations'; import { SecurityPageName } from '../../app/types'; import { useSourcererDataView } from '../../common/containers/sourcerer'; +import { LandingPageComponent } from '../../common/components/landing_page'; const TimelinesContainer = styled.div` width: 100%; @@ -92,9 +92,7 @@ export const TimelinesPageComponent: React.FC = () => { ) : ( - - - + )} diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.test.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.test.ts index 5c6e10ae8f7ce..702d259f98615 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.test.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.test.ts @@ -15,6 +15,7 @@ import { MatrixHistogramType, NetworkKpiQueries, NetworkQueries, + UsersQueries, } from '../../../common/search_strategy'; /** Get the return type of createIndicesFromPrefix for TypeScript checks against expected */ @@ -75,11 +76,11 @@ describe('get_transform_changes', () => { test('it gets a transform change for authentications', () => { expect( getTransformChanges({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: UsersQueries.authentications, settings: getTransformConfigSchemaMock().settings[0], }) ).toEqual({ - factoryQueryType: HostsQueries.authenticationsEntities, + factoryQueryType: UsersQueries.authenticationsEntities, indices: ['.estc_all_user_ent*'], }); }); diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.ts index 6e327457a683d..1a72c556490a5 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes.ts @@ -9,6 +9,7 @@ import { getTransformChangesForHosts } from './get_transform_changes_for_hosts'; import { getTransformChangesForKpi } from './get_transform_changes_for_kpi'; import { getTransformChangesForMatrixHistogram } from './get_transform_changes_for_matrix_histogram'; import { getTransformChangesForNetwork } from './get_transform_changes_for_network'; +import { getTransformChangesForUsers } from './get_transform_changes_for_users'; import { GetTransformChanges } from './types'; export const getTransformChanges: GetTransformChanges = ({ @@ -26,6 +27,11 @@ export const getTransformChanges: GetTransformChanges = ({ return hostTransform; } + const userTransform = getTransformChangesForUsers({ factoryQueryType, settings }); + if (userTransform != null) { + return userTransform; + } + const networkTransform = getTransformChangesForNetwork({ factoryQueryType, settings, diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.test.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.test.ts index e76c2ee2575ff..8223e3a9cd6e6 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.test.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.test.ts @@ -25,18 +25,6 @@ describe('get_transform_changes_for_host', () => { }); }); - test('it gets a transform change for authentications', () => { - expect( - getTransformChangesForHosts({ - factoryQueryType: HostsQueries.authentications, - settings: getTransformConfigSchemaMock().settings[0], - }) - ).toEqual({ - factoryQueryType: HostsQueries.authenticationsEntities, - indices: ['.estc_all_user_ent*'], - }); - }); - test('it returns an "undefined" for another value', () => { expect( getTransformChangesForHosts({ diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.ts index 95a5e04bd9e51..265b2857d5397 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_hosts.ts @@ -30,15 +30,6 @@ export const getTransformChangesForHosts: GetTransformChanges = ({ factoryQueryType: HostsQueries.hostsEntities, }; } - case HostsQueries.authentications: { - return { - indices: createIndicesFromPrefix({ - prefix: settings.prefix, - transformIndices: ['user_ent*'], - }), - factoryQueryType: HostsQueries.authenticationsEntities, - }; - } default: { return undefined; } diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.test.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.test.ts new file mode 100644 index 0000000000000..ae3690d72baba --- /dev/null +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.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 { UsersQueries } from '../../../common/search_strategy'; +import { getTransformChangesForUsers } from './get_transform_changes_for_users'; +import { getTransformConfigSchemaMock } from './transform_config_schema.mock'; + +/** Get the return type of getTransformChangesForUsers for TypeScript checks against expected */ +type ReturnTypeGetTransformChangesForUsers = ReturnType; + +describe('get_transform_changes_for_user', () => { + test('it gets a transform change for authentications', () => { + expect( + getTransformChangesForUsers({ + factoryQueryType: UsersQueries.authentications, + settings: getTransformConfigSchemaMock().settings[0], + }) + ).toEqual({ + factoryQueryType: UsersQueries.authenticationsEntities, + indices: ['.estc_all_user_ent*'], + }); + }); + + test('it returns an "undefined" for another value', () => { + expect( + getTransformChangesForUsers({ + factoryQueryType: UsersQueries.details, + settings: getTransformConfigSchemaMock().settings[0], + }) + ).toEqual(undefined); + }); +}); diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.ts new file mode 100644 index 0000000000000..a91bc05bb7383 --- /dev/null +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_for_users.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { UsersQueries } from '../../../common/search_strategy'; +import { createIndicesFromPrefix } from './create_indices_from_prefix'; +import { GetTransformChanges } from './types'; + +/** + * Given a factory query type this will return the transform changes such as the transform indices if it matches + * the correct type, otherwise it will return "undefined" + * @param factoryQueryType The query type to check if we have a transform for it and are capable of rendering one or not + * @param settings The settings configuration to get the prefix from + * @returns The transform type if we have one, otherwise undefined + */ +export const getTransformChangesForUsers: GetTransformChanges = ({ + factoryQueryType, + settings, +}) => { + switch (factoryQueryType) { + case UsersQueries.authentications: { + return { + indices: createIndicesFromPrefix({ + prefix: settings.prefix, + transformIndices: ['user_ent*'], + }), + factoryQueryType: UsersQueries.authenticationsEntities, + }; + } + default: { + return undefined; + } + } +}; diff --git a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_if_they_exist.test.ts b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_if_they_exist.test.ts index 7a4e11526d83e..19c9ba5596027 100644 --- a/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_if_they_exist.test.ts +++ b/x-pack/plugins/security_solution/public/transforms/utils/get_transform_changes_if_they_exist.test.ts @@ -35,7 +35,7 @@ describe('get_transform_changes_if_they_exist', () => { test('returns transformed settings if our settings is enabled', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: { ...getTransformConfigSchemaMock(), enabled: true }, // sets enabled to true filterQuery: undefined, @@ -47,15 +47,15 @@ describe('get_transform_changes_if_they_exist', () => { }, }) ).toMatchObject>({ - indices: ['.estc_all_user_ent*'], - factoryQueryType: HostsQueries.authenticationsEntities, + indices: ['.estc_all_host_ent*'], + factoryQueryType: HostsQueries.hostsEntities, }); }); test('returns regular settings if our settings is disabled', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: { ...getTransformConfigSchemaMock(), enabled: false }, // sets enabled to false filterQuery: undefined, @@ -68,7 +68,7 @@ describe('get_transform_changes_if_they_exist', () => { }) ).toMatchObject>({ indices: ['auditbeat-*'], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, }); }); }); @@ -77,7 +77,7 @@ describe('get_transform_changes_if_they_exist', () => { test('returns regular settings if filter is set to something other than match_all', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: { @@ -97,14 +97,14 @@ describe('get_transform_changes_if_they_exist', () => { }) ).toMatchObject>({ indices: ['auditbeat-*'], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, }); }); test('returns transformed settings if filter is set to something such as match_all', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: { @@ -123,15 +123,15 @@ describe('get_transform_changes_if_they_exist', () => { }, }) ).toMatchObject>({ - indices: ['.estc_all_user_ent*'], - factoryQueryType: HostsQueries.authenticationsEntities, + indices: ['.estc_all_host_ent*'], + factoryQueryType: HostsQueries.hostsEntities, }); }); test('returns transformed settings if filter is set to undefined', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: undefined, // undefined should return transform @@ -143,8 +143,8 @@ describe('get_transform_changes_if_they_exist', () => { }, }) ).toMatchObject>({ - indices: ['.estc_all_user_ent*'], - factoryQueryType: HostsQueries.authenticationsEntities, + indices: ['.estc_all_host_ent*'], + factoryQueryType: HostsQueries.hostsEntities, }); }); }); @@ -153,7 +153,7 @@ describe('get_transform_changes_if_they_exist', () => { test('returns regular settings if timerange is less than an hour', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: undefined, @@ -166,14 +166,14 @@ describe('get_transform_changes_if_they_exist', () => { }) ).toMatchObject>({ indices: ['auditbeat-*'], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, }); }); test('returns regular settings if timerange is invalid', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: undefined, @@ -186,14 +186,14 @@ describe('get_transform_changes_if_they_exist', () => { }) ).toMatchObject>({ indices: ['auditbeat-*'], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, }); }); test('returns transformed settings if timerange is greater than an hour', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['auditbeat-*'], transformSettings: getTransformConfigSchemaMock(), filterQuery: undefined, @@ -205,8 +205,8 @@ describe('get_transform_changes_if_they_exist', () => { }, }) ).toMatchObject>({ - indices: ['.estc_all_user_ent*'], - factoryQueryType: HostsQueries.authenticationsEntities, + indices: ['.estc_all_host_ent*'], + factoryQueryType: HostsQueries.hostsEntities, }); }); }); @@ -215,7 +215,7 @@ describe('get_transform_changes_if_they_exist', () => { test('it returns regular settings if settings do not match', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: ['should-not-match-*'], // index doesn't match anything transformSettings: getTransformConfigSchemaMock(), filterQuery: undefined, @@ -228,14 +228,14 @@ describe('get_transform_changes_if_they_exist', () => { }) ).toMatchObject>({ indices: ['should-not-match-*'], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, }); }); test('it returns transformed settings if settings do match', () => { expect( getTransformChangesIfTheyExist({ - factoryQueryType: HostsQueries.authentications, + factoryQueryType: HostsQueries.hosts, indices: [ 'auditbeat-*', 'endgame-*', @@ -255,8 +255,8 @@ describe('get_transform_changes_if_they_exist', () => { }, }) ).toMatchObject>({ - indices: ['.estc_all_user_ent*'], - factoryQueryType: HostsQueries.authenticationsEntities, + indices: ['.estc_all_host_ent*'], + factoryQueryType: HostsQueries.hostsEntities, }); }); }); diff --git a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx index 36ace6a6b4543..3dfe67de92c81 100644 --- a/x-pack/plugins/security_solution/public/users/pages/details/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/details/index.tsx @@ -26,7 +26,6 @@ import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions import { SpyRoute } from '../../../common/utils/route/spy_routes'; import { getEsQueryConfig } from '../../../../../../../src/plugins/data/common'; -import { OverviewEmpty } from '../../../overview/components/overview_empty'; import { UsersDetailsTabs } from './details_tabs'; import { navTabsUsersDetails } from './nav_tabs'; import { UsersDetailsProps } from './types'; @@ -52,6 +51,7 @@ import { getCriteriaFromUsersType } from '../../../common/components/ml/criteria import { UsersType } from '../../store/model'; import { hasMlUserPermissions } from '../../../../common/machine_learning/has_ml_user_permissions'; import { useMlCapabilities } from '../../../common/components/ml/hooks/use_ml_capabilities'; +import { LandingPageComponent } from '../../../common/components/landing_page'; const QUERY_ID = 'UsersDetailsQueryId'; const UsersDetailsComponent: React.FC = ({ @@ -194,11 +194,7 @@ const UsersDetailsComponent: React.FC = ({ ) : ( - - - - - + )} diff --git a/x-pack/plugins/security_solution/public/users/pages/index.tsx b/x-pack/plugins/security_solution/public/users/pages/index.tsx index f1f4e545ae9fd..0449ab59688fa 100644 --- a/x-pack/plugins/security_solution/public/users/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/index.tsx @@ -31,7 +31,12 @@ export const UsersContainer = React.memo(() => { match: { params: { detailName }, }, - }) => } + }) => ( + + )} /> { - const { toggleStatus } = useQueryToggle(ID); - const [querySkip, setQuerySkip] = useState(skip || !toggleStatus); - useEffect(() => { - setQuerySkip(skip || !toggleStatus); - }, [skip, toggleStatus]); - - const [ - loading, - { authentications, totalCount, pageInfo, loadPage, id, inspect, isInspected, refetch }, - ] = useAuthentications({ - docValueFields, - endDate, - filterQuery, - indexNames, - skip: querySkip, - startDate, - // TODO Move authentication table and hook store to 'public/common' folder when 'usersEnabled' FF is removed - // @ts-ignore - type, - deleteQuery, - }); return ( - ); }; diff --git a/x-pack/plugins/security_solution/public/users/pages/users.tsx b/x-pack/plugins/security_solution/public/users/pages/users.tsx index 6acd2ddf32a3c..ae5b485142f9c 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users.tsx @@ -29,7 +29,6 @@ import { setAbsoluteRangeDatePicker } from '../../common/store/inputs/actions'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { getEsQueryConfig } from '../../../../../../src/plugins/data/common'; -import { OverviewEmpty } from '../../overview/components/overview_empty'; import { UsersTabs } from './users_tabs'; import { navTabsUsers } from './nav_tabs'; import * as i18n from './translations'; @@ -49,6 +48,7 @@ import { UsersTableType } from '../store/model'; import { hasMlUserPermissions } from '../../../common/machine_learning/has_ml_user_permissions'; import { useMlCapabilities } from '../../common/components/ml/hooks/use_ml_capabilities'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; +import { LandingPageComponent } from '../../common/components/landing_page'; const ID = 'UsersQueryId'; @@ -220,11 +220,7 @@ const UsersComponent = () => { ) : ( - - - - - + )} diff --git a/x-pack/plugins/security_solution/public/users/pages/users_tabs.test.tsx b/x-pack/plugins/security_solution/public/users/pages/users_tabs.test.tsx index e3807f359a0ff..c3ffdc646966f 100644 --- a/x-pack/plugins/security_solution/public/users/pages/users_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/users/pages/users_tabs.test.tsx @@ -15,8 +15,7 @@ import { SecuritySolutionTabNavigation } from '../../common/components/navigatio import { Users } from './users'; import { useSourcererDataView } from '../../common/containers/sourcerer'; import { mockCasesContext } from '../../../../cases/public/mocks/mock_cases_context'; -import { APP_UI_ID, SecurityPageName } from '../../../common/constants'; -import { getAppLandingUrl } from '../../common/components/link_to/redirect_to_overview'; +import { LandingPageComponent } from '../../common/components/landing_page'; jest.mock('../../common/containers/sourcerer'); jest.mock('../../common/components/search_bar', () => ({ @@ -73,22 +72,20 @@ const mockHistory = { }; const mockUseSourcererDataView = useSourcererDataView as jest.Mock; describe('Users - rendering', () => { - test('it renders the Setup Instructions text when no index is available', async () => { + test('it renders getting started page when no index is available', async () => { mockUseSourcererDataView.mockReturnValue({ indicesExist: false, }); - mount( + const wrapper = mount( ); - expect(mockNavigateToApp).toHaveBeenCalledWith(APP_UI_ID, { - deepLinkId: SecurityPageName.landing, - path: getAppLandingUrl(), - }); + + expect(wrapper.find(LandingPageComponent).exists()).toBe(true); }); test('it should render tab navigation', async () => { diff --git a/x-pack/plugins/security_solution/public/users/store/selectors.ts b/x-pack/plugins/security_solution/public/users/store/selectors.ts index bdeacef2bf774..1ccedf3b5da20 100644 --- a/x-pack/plugins/security_solution/public/users/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/users/store/selectors.ts @@ -21,3 +21,6 @@ export const userRiskScoreSelector = () => export const usersRiskScoreSeverityFilterSelector = () => createSelector(selectUserPage, (users) => users.queries[UsersTableType.risk].severitySelection); + +export const authenticationsSelector = () => + createSelector(selectUserPage, (users) => users.queries[UsersTableType.authentications]); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_index.ts index 0c3da2a114595..b1f1ecf85746a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_index.ts @@ -37,8 +37,8 @@ export const createMigrationIndex = async ({ body: { settings: { index: { + // @ts-expect-error `name` is required on IndicesIndexSettingsLifecycle lifecycle: { - // @ts-expect-error typings don't contain the property yet indexing_complete: true, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts index 13e4b405ca26b..f28dd8b45b035 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_create_notifications.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SanitizedAlert } from '../../../../../alerting/common'; +import { SanitizedRule } from '../../../../../alerting/common'; import { SERVER_APP_ID, LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; // eslint-disable-next-line no-restricted-imports import { CreateNotificationParams, LegacyRuleNotificationAlertTypeParams } from './legacy_types'; @@ -22,7 +22,7 @@ export const legacyCreateNotifications = async ({ ruleAlertId, interval, name, -}: CreateNotificationParams): Promise> => +}: CreateNotificationParams): Promise> => rulesClient.create({ data: { name, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts index 51584879a4bd9..a7fa01226f008 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_find_notifications.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertTypeParams, FindResult } from '../../../../../alerting/server'; +import { RuleTypeParams, FindResult } from '../../../../../alerting/server'; import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; // eslint-disable-next-line no-restricted-imports import { LegacyFindNotificationParams } from './legacy_types'; @@ -32,7 +32,7 @@ export const legacyFindNotifications = async ({ filter, sortField, sortOrder, -}: LegacyFindNotificationParams): Promise> => +}: LegacyFindNotificationParams): Promise> => rulesClient.find({ options: { fields, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts index 9e2fb9515bb82..f6c6f0f982660 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_read_notifications.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertTypeParams, SanitizedAlert } from '../../../../../alerting/common'; +import { RuleTypeParams, SanitizedRule } from '../../../../../alerting/common'; // eslint-disable-next-line no-restricted-imports import { LegacyReadNotificationParams, legacyIsAlertType } from './legacy_types'; // eslint-disable-next-line no-restricted-imports @@ -19,7 +19,7 @@ export const legacyReadNotifications = async ({ rulesClient, id, ruleAlertId, -}: LegacyReadNotificationParams): Promise | null> => { +}: LegacyReadNotificationParams): Promise | null> => { if (id != null) { try { const notification = await rulesClient.get({ id }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts index 20aac86a336e0..c49e6d060c7c0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_rules_notification_alert_type.test.ts @@ -10,7 +10,7 @@ import { getAlertMock } from '../routes/__mocks__/request_responses'; // eslint-disable-next-line no-restricted-imports import { legacyRulesNotificationAlertType } from './legacy_rules_notification_alert_type'; import { buildSignalsSearchQuery } from './build_signals_query'; -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; // eslint-disable-next-line no-restricted-imports import { LegacyNotificationExecutorOptions } from './legacy_types'; import { @@ -30,10 +30,10 @@ describe('legacyRules_notification_alert_type', () => { let payload: LegacyNotificationExecutorOptions; let alert: ReturnType; let logger: ReturnType; - let alertServices: AlertServicesMock; + let alertServices: RuleExecutorServicesMock; beforeEach(() => { - alertServices = alertsMock.createAlertServices(); + alertServices = alertsMock.createRuleExecutorServices(); logger = loggingSystemMock.createLogger(); payload = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts index 225ac707b1f2d..44cca599a0468 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/legacy_types.ts @@ -9,28 +9,28 @@ import { schema, TypeOf } from '@kbn/config-schema'; import { RulesClient, - PartialAlert, + PartialRule, RuleType, - AlertTypeParams, - AlertTypeState, + RuleTypeParams, + RuleTypeState, AlertInstanceState, AlertInstanceContext, - AlertExecutorOptions, + RuleExecutorOptions, } from '../../../../../alerting/server'; -import { Alert, AlertAction } from '../../../../../alerting/common'; +import { Rule, RuleAction } from '../../../../../alerting/common'; import { LEGACY_NOTIFICATIONS_ID } from '../../../../common/constants'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export interface LegacyRuleNotificationAlertTypeParams extends AlertTypeParams { +export interface LegacyRuleNotificationAlertTypeParams extends RuleTypeParams { ruleAlertId: string; } /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export type LegacyRuleNotificationAlertType = Alert; +export type LegacyRuleNotificationAlertType = Rule; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function @@ -56,7 +56,7 @@ export interface LegacyClients { * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ export interface LegacyNotificationAlertParams { - actions: AlertAction[]; + actions: RuleAction[]; enabled: boolean; ruleAlertId: string; interval: string; @@ -81,7 +81,7 @@ export interface LegacyReadNotificationParams { * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ export const legacyIsAlertType = ( - partialAlert: PartialAlert + partialAlert: PartialRule ): partialAlert is LegacyRuleNotificationAlertType => { return partialAlert.alertTypeId === LEGACY_NOTIFICATIONS_ID; }; @@ -89,9 +89,9 @@ export const legacyIsAlertType = ( /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ -export type LegacyNotificationExecutorOptions = AlertExecutorOptions< +export type LegacyNotificationExecutorOptions = RuleExecutorOptions< LegacyRuleNotificationAlertTypeParams, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext >; @@ -106,7 +106,7 @@ export const legacyIsNotificationAlertExecutor = ( ): obj is RuleType< LegacyRuleNotificationAlertTypeParams, LegacyRuleNotificationAlertTypeParams, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext > => { @@ -120,7 +120,7 @@ export type LegacyNotificationAlertTypeDefinition = Omit< RuleType< LegacyRuleNotificationAlertTypeParams, LegacyRuleNotificationAlertTypeParams, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, 'default' @@ -131,7 +131,7 @@ export type LegacyNotificationAlertTypeDefinition = Omit< services, params, state, - }: LegacyNotificationExecutorOptions) => Promise; + }: LegacyNotificationExecutorOptions) => Promise; }; /** diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts index eebda81fd63f0..a10f4a59c7359 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/schedule_notification_actions.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertServicesMock, alertsMock } from '../../../../../alerting/server/mocks'; +import { RuleExecutorServicesMock, alertsMock } from '../../../../../alerting/server/mocks'; import { sampleThresholdAlert } from '../rule_types/__mocks__/threshold'; import { NotificationRuleTypeParams, @@ -13,7 +13,7 @@ import { } from './schedule_notification_actions'; describe('schedule_notification_actions', () => { - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const alertId = 'fb30ddd1-5edc-43e2-9afb-3bcd970b78ee'; const notificationRuleParams: NotificationRuleTypeParams = { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts index 0c9418657a4eb..09e7dc543019f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_responses.ts @@ -35,7 +35,7 @@ import { getFinalizeSignalsMigrationSchemaMock } from '../../../../../common/det import { EqlSearchResponse } from '../../../../../common/detection_engine/types'; import { getSignalsMigrationStatusSchemaMock } from '../../../../../common/detection_engine/schemas/request/get_signals_migration_status_schema.mock'; import { RuleParams } from '../../schemas/rule_schemas'; -import { SanitizedAlert, ResolvedSanitizedRule } from '../../../../../../alerting/common'; +import { SanitizedRule, ResolvedSanitizedRule } from '../../../../../../alerting/common'; import { getQueryRuleParams } from '../../schemas/rule_schemas.mock'; import { getPerformBulkActionSchemaMock, @@ -391,7 +391,7 @@ export const nonRuleAlert = (isRuleRegistryEnabled: boolean) => ({ export const getAlertMock = ( isRuleRegistryEnabled: boolean, params: T -): SanitizedAlert => ({ +): SanitizedRule => ({ id: '04128c15-0d1b-4716-a4c5-46997ac7f3bd', name: 'Detect Root/Admin Users', tags: [`${INTERNAL_RULE_ID_KEY}:rule-1`, `${INTERNAL_IMMUTABLE_KEY}:false`], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts index 4c4eee366ab84..94294192531f8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/perform_bulk_action_route.ts @@ -14,7 +14,7 @@ import { SavedObjectsClientContract } from 'kibana/server'; import { RuleAlertType } from '../../rules/types'; import type { RulesClient } from '../../../../../../alerting/server'; -import { SanitizedAlert } from '../../../../../../alerting/common'; +import { SanitizedRule } from '../../../../../../alerting/common'; import { DETECTION_ENGINE_RULES_BULK_ACTION, @@ -211,7 +211,7 @@ export const migrateRuleActions = async ({ rulesClient: RulesClient; savedObjectsClient: SavedObjectsClientContract; rule: RuleAlertType; -}): Promise> => { +}): Promise> => { const migratedRule = await legacyMigrate({ rulesClient, savedObjectsClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts index 9b8477bd247b5..5e7e0504c99ed 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/preview_rules_route.ts @@ -32,7 +32,7 @@ import { RuleExecutionStatus } from '../../../../../common/detection_engine/sche import { AlertInstanceContext, AlertInstanceState, - AlertTypeState, + RuleTypeState, parseDuration, } from '../../../../../../alerting/common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths @@ -129,7 +129,7 @@ export const previewRulesRoute = async ( const runExecutors = async < TParams extends RuleParams, - TState extends AlertTypeState, + TState extends RuleTypeState, TInstanceState extends AlertInstanceState, TInstanceContext extends AlertInstanceContext, TActionGroupIds extends string = '' diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts index 0ca665bb10584..04823606faf3e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.test.ts @@ -27,7 +27,7 @@ import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { PartialFilter } from '../../types'; import { BulkError, createBulkErrorObject } from '../utils'; import { getOutputRuleAlertForRest } from '../__mocks__/utils'; -import { PartialAlert } from '../../../../../../alerting/server'; +import { PartialRule } from '../../../../../../alerting/server'; import { createRulesAndExceptionsStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { RuleAlertType } from '../../rules/types'; import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; @@ -383,7 +383,7 @@ describe.each([ }); test('returns 500 if the data is not of type siem alert', () => { - const unsafeCast = { data: [{ random: 1 }] } as unknown as PartialAlert; + const unsafeCast = { data: [{ random: 1 }] } as unknown as PartialRule; const output = transform(unsafeCast, undefined, isRuleRegistryEnabled); expect(output).toBeNull(); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts index da07f5ae1a23a..bd74e83f5a664 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/utils.ts @@ -15,7 +15,7 @@ import { RuleExecutionSummary } from '../../../../../common/detection_engine/sch import { RulesSchema } from '../../../../../common/detection_engine/schemas/response/rules_schema'; import { ImportRulesSchemaDecoded } from '../../../../../common/detection_engine/schemas/request/import_rules_schema'; import { CreateRulesBulkSchema } from '../../../../../common/detection_engine/schemas/request/create_rules_bulk_schema'; -import { PartialAlert, FindResult } from '../../../../../../alerting/server'; +import { PartialRule, FindResult } from '../../../../../../alerting/server'; import { ActionsClient, FindActionResult } from '../../../../../../actions/server'; import { INTERNAL_IDENTIFIER } from '../../../../../common/constants'; import { RuleAlertType, isAlertType } from '../../rules/types'; @@ -121,7 +121,7 @@ export const transformFindAlerts = ( }; export const transform = ( - rule: PartialAlert, + rule: PartialRule, ruleExecutionSummary?: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts index e743e26e8da3f..293f73b9dcd05 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts @@ -16,7 +16,7 @@ import { RulesSchema, rulesSchema, } from '../../../../../common/detection_engine/schemas/response/rules_schema'; -import { PartialAlert } from '../../../../../../alerting/server'; +import { PartialRule } from '../../../../../../alerting/server'; import { isAlertType } from '../../rules/types'; import { createBulkErrorObject, BulkError } from '../utils'; import { transform } from './utils'; @@ -26,7 +26,7 @@ import { LegacyRulesActionsSavedObject } from '../../rule_actions/legacy_get_rul import { internalRuleToAPIResponse } from '../../schemas/rule_converters'; export const transformValidate = ( - rule: PartialAlert, + rule: PartialRule, ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null @@ -45,7 +45,7 @@ export const transformValidate = ( }; export const newTransformValidate = ( - rule: PartialAlert, + rule: PartialRule, ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean, legacyRuleActions?: LegacyRulesActionsSavedObject | null @@ -65,7 +65,7 @@ export const newTransformValidate = ( export const transformValidateBulkError = ( ruleId: string, - rule: PartialAlert, + rule: PartialRule, ruleExecutionSummary: RuleExecutionSummary | null, isRuleRegistryEnabled?: boolean ): RulesSchema | BulkError => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts index df27a5bcc280d..55e3ae3b346bc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_create_rule_actions_saved_object.ts @@ -6,7 +6,7 @@ */ import { SavedObjectReference } from 'kibana/server'; -import { AlertServices } from '../../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../../alerting/server'; // eslint-disable-next-line no-restricted-imports import { legacyRuleActionsSavedObjectType } from './legacy_saved_object_mappings'; // eslint-disable-next-line no-restricted-imports @@ -18,15 +18,15 @@ import { legacyGetThrottleOptions, legacyTransformActionToReference, } from './legacy_utils'; -import { AlertAction } from '../../../../../alerting/common'; +import { RuleAction } from '../../../../../alerting/common'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ interface LegacyCreateRuleActionsSavedObject { ruleAlertId: string; - savedObjectsClient: AlertServices['savedObjectsClient']; - actions: AlertAction[] | undefined; + savedObjectsClient: RuleExecutorServices['savedObjectsClient']; + actions: RuleAction[] | undefined; throttle: string | null | undefined; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts index feaaa7f3e6c08..df135e9c1c8ef 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_bulk_rule_actions_saved_object.ts @@ -9,7 +9,7 @@ import { chunk } from 'lodash'; import { SavedObjectsFindOptionsReference } from 'kibana/server'; import { Logger } from 'src/core/server'; -import { AlertServices } from '../../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../../alerting/server'; // eslint-disable-next-line no-restricted-imports import { legacyRuleActionsSavedObjectType } from './legacy_saved_object_mappings'; // eslint-disable-next-line no-restricted-imports @@ -25,7 +25,7 @@ import { initPromisePool } from '../../../utils/promise_pool'; */ interface LegacyGetBulkRuleActionsSavedObject { alertIds: string[]; - savedObjectsClient: AlertServices['savedObjectsClient']; + savedObjectsClient: RuleExecutorServices['savedObjectsClient']; logger: Logger; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts index d972c6535b3b6..de47e127daa73 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_get_rule_actions_saved_object.ts @@ -7,7 +7,7 @@ import { SavedObjectsFindOptionsReference } from 'kibana/server'; import { Logger } from 'src/core/server'; -import { AlertServices } from '../../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../../alerting/server'; // eslint-disable-next-line no-restricted-imports import { legacyRuleActionsSavedObjectType } from './legacy_saved_object_mappings'; @@ -24,7 +24,7 @@ import { legacyGetRuleActionsFromSavedObject } from './legacy_utils'; */ interface LegacyGetRuleActionsSavedObject { ruleAlertId: string; - savedObjectsClient: AlertServices['savedObjectsClient']; + savedObjectsClient: RuleExecutorServices['savedObjectsClient']; logger: Logger; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts index 36f81709b293f..475f17b8b58a3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_types.ts @@ -6,7 +6,7 @@ */ import { SavedObjectAttributes } from 'kibana/server'; -import { AlertActionParams } from '../../../../../alerting/common'; +import { RuleActionParams } from '../../../../../alerting/common'; /** * This was the pre-7.16 version of LegacyRuleAlertAction and how it was stored on disk pre-7.16. @@ -16,7 +16,7 @@ import { AlertActionParams } from '../../../../../alerting/common'; export interface LegacyRuleAlertAction { group: string; id: string; - params: AlertActionParams; + params: RuleActionParams; action_type_id: string; } @@ -26,7 +26,7 @@ export interface LegacyRuleAlertAction { */ export interface LegacyRuleAlertSavedObjectAction { group: string; - params: AlertActionParams; + params: RuleActionParams; action_type_id: string; actionRef: string; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts index d56d4ff921bd3..f700f78fd41b6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_or_create_rule_actions_saved_object.ts @@ -6,8 +6,8 @@ */ import { Logger } from 'src/core/server'; -import { AlertAction } from '../../../../../alerting/common'; -import { AlertServices } from '../../../../../alerting/server'; +import { RuleAction } from '../../../../../alerting/common'; +import { RuleExecutorServices } from '../../../../../alerting/server'; // eslint-disable-next-line no-restricted-imports import { legacyGetRuleActionsSavedObject } from './legacy_get_rule_actions_saved_object'; @@ -21,8 +21,8 @@ import { legacyUpdateRuleActionsSavedObject } from './legacy_update_rule_actions */ interface LegacyUpdateOrCreateRuleActionsSavedObject { ruleAlertId: string; - savedObjectsClient: AlertServices['savedObjectsClient']; - actions: AlertAction[] | undefined; + savedObjectsClient: RuleExecutorServices['savedObjectsClient']; + actions: RuleAction[] | undefined; throttle: string | null | undefined; logger: Logger; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts index fbbbda24e48be..feb6895b87a2f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_update_rule_actions_saved_object.ts @@ -6,7 +6,7 @@ */ import { SavedObjectReference } from 'kibana/server'; -import { AlertServices } from '../../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../../alerting/server'; // eslint-disable-next-line no-restricted-imports import { legacyRuleActionsSavedObjectType } from './legacy_saved_object_mappings'; // eslint-disable-next-line no-restricted-imports @@ -21,15 +21,15 @@ import { } from './legacy_utils'; // eslint-disable-next-line no-restricted-imports import { LegacyIRuleActionsAttributesSavedObjectAttributes } from './legacy_types'; -import { AlertAction } from '../../../../../alerting/common'; +import { RuleAction } from '../../../../../alerting/common'; /** * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ interface LegacyUpdateRuleActionsSavedObject { ruleAlertId: string; - savedObjectsClient: AlertServices['savedObjectsClient']; - actions: AlertAction[] | undefined; + savedObjectsClient: RuleExecutorServices['savedObjectsClient']; + actions: RuleAction[] | undefined; throttle: string | null | undefined; ruleActions: LegacyRulesActionsSavedObject; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts index 448548e96884b..0d5e4e704d7ff 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.test.ts @@ -8,7 +8,7 @@ import { SavedObjectsUpdateResponse } from 'kibana/server'; import { loggingSystemMock } from 'src/core/server/mocks'; -import { AlertAction } from '../../../../../alerting/common'; +import { RuleAction } from '../../../../../alerting/common'; // eslint-disable-next-line no-restricted-imports import { legacyRuleActionsSavedObjectType } from './legacy_saved_object_mappings'; @@ -343,7 +343,7 @@ describe('legacy_utils', () => { describe('legacyTransformActionToReference', () => { type FuncReturn = ReturnType; - const alertAction: AlertAction = { + const alertAction: RuleAction = { id: '123', group: 'group_1', params: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts index 78f6c7419ae66..b84550d56dbd5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions/legacy_utils.ts @@ -8,7 +8,7 @@ import { SavedObjectsUpdateResponse } from 'kibana/server'; import { Logger } from 'src/core/server'; -import { AlertAction } from '../../../../../alerting/common'; +import { RuleAction } from '../../../../../alerting/common'; // eslint-disable-next-line no-restricted-imports import { @@ -112,7 +112,7 @@ export const legacyGetActionReference = (id: string, index: number) => ({ * @deprecated Once we are confident all rules relying on side-car actions SO's have been migrated to SO references we should remove this function */ export const legacyTransformActionToReference = ( - alertAction: AlertAction, + alertAction: RuleAction, index: number ): LegacyRuleAlertSavedObjectAction => ({ actionRef: `action_${index}`, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 2537f7eeeaf72..fdcddd52d5c66 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -10,11 +10,11 @@ import { Moment } from 'moment'; import { Logger } from '@kbn/logging'; import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { AlertExecutorOptions, RuleType } from '../../../../../alerting/server'; +import { RuleExecutorOptions, RuleType } from '../../../../../alerting/server'; import { AlertInstanceContext, AlertInstanceState, - AlertTypeState, + RuleTypeState, WithoutReservedActionGroups, } from '../../../../../alerting/common'; import { ListClient } from '../../../../../lists/server'; @@ -34,7 +34,7 @@ import { IEventLogService } from '../../../../../event_log/server'; import { ITelemetryEventsSender } from '../../telemetry/sender'; import { RuleExecutionLogForExecutorsFactory } from '../rule_execution_log'; -export interface SecurityAlertTypeReturnValue { +export interface SecurityAlertTypeReturnValue { bulkCreateTimes: string[]; createdSignalsCount: number; createdSignals: unknown[]; @@ -65,7 +65,7 @@ export interface RunOpts { export type SecurityAlertType< TParams extends RuleParams, - TState extends AlertTypeState, + TState extends RuleTypeState, TInstanceContext extends AlertInstanceContext = {}, TActionGroupIds extends string = never > = Omit< @@ -73,7 +73,7 @@ export type SecurityAlertType< 'executor' > & { executor: ( - options: AlertExecutorOptions< + options: RuleExecutorOptions< TParams, TState, AlertInstanceState, @@ -99,7 +99,7 @@ export type CreateSecurityRuleTypeWrapper = ( options: CreateSecurityRuleTypeWrapperProps ) => < TParams extends RuleParams, - TState extends AlertTypeState, + TState extends RuleTypeState, TInstanceContext extends AlertInstanceContext = {} >( type: SecurityAlertType diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/index.ts index ac2f6495b8b46..59e2b9f2f597b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/index.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { AlertTypeState } from '../../../../../../alerting/server'; +import { RuleTypeState } from '../../../../../../alerting/server'; import { SecurityAlertTypeReturnValue } from '../types'; -export const createResultObject = (state: TState) => { +export const createResultObject = (state: TState) => { const result: SecurityAlertTypeReturnValue = { bulkCreateTimes: [], createdSignalsCount: 0, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts index ef9d198d2040f..863d1104ded36 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/create_rules.ts @@ -12,7 +12,7 @@ import { normalizeThresholdObject, } from '../../../../common/detection_engine/utils'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { AlertTypeParams, SanitizedAlert } from '../../../../../alerting/common'; +import { RuleTypeParams, SanitizedRule } from '../../../../../alerting/common'; import { DEFAULT_INDICATOR_SOURCE_PATH, NOTIFICATION_THROTTLE_NO_ACTIONS, @@ -77,8 +77,8 @@ export const createRules = async ({ actions, isRuleRegistryEnabled, id, -}: CreateRulesOptions): Promise> => { - const rule = await rulesClient.create({ +}: CreateRulesOptions): Promise> => { + const rule = await rulesClient.create({ options: { id, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts index 2ccd5f21366ee..1b15f71a1827c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/duplicate_rule.ts @@ -10,7 +10,7 @@ import uuid from 'uuid'; import { i18n } from '@kbn/i18n'; import { ruleTypeMappings, SIGNALS_ID } from '@kbn/securitysolution-rules'; -import { SanitizedAlert } from '../../../../../alerting/common'; +import { SanitizedRule } from '../../../../../alerting/common'; import { SERVER_APP_ID } from '../../../../common/constants'; import { InternalRuleCreate, RuleParams } from '../schemas/rule_schemas'; import { addTags } from './add_tags'; @@ -23,7 +23,7 @@ const DUPLICATE_TITLE = i18n.translate( ); export const duplicateRule = ( - rule: SanitizedAlert, + rule: SanitizedRule, isRuleRegistryEnabled: boolean ): InternalRuleCreate => { const newRuleId = uuid.v4(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts index c0389de766ea5..81db46bb9fee2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_all.ts @@ -9,7 +9,7 @@ import { transformDataToNdjson } from '@kbn/securitysolution-utils'; import { Logger } from 'src/core/server'; import { ExceptionListClient } from '../../../../../lists/server'; -import { RulesClient, AlertServices } from '../../../../../alerting/server'; +import { RulesClient, RuleExecutorServices } from '../../../../../alerting/server'; import { getNonPackagedRules } from './get_existing_prepackaged_rules'; import { getExportDetailsNdjson } from './get_export_details_ndjson'; import { transformAlertsToRules } from '../routes/rules/utils'; @@ -21,7 +21,7 @@ import { legacyGetBulkRuleActionsSavedObject } from '../rule_actions/legacy_get_ export const getExportAll = async ( rulesClient: RulesClient, exceptionsClient: ExceptionListClient | undefined, - savedObjectsClient: AlertServices['savedObjectsClient'], + savedObjectsClient: RuleExecutorServices['savedObjectsClient'], logger: Logger, isRuleRegistryEnabled: boolean ): Promise<{ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts index 1181995e0ae4a..9da3cc3cfdde3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/get_export_by_object_ids.ts @@ -11,7 +11,7 @@ import { transformDataToNdjson } from '@kbn/securitysolution-utils'; import { Logger } from 'src/core/server'; import { ExceptionListClient } from '../../../../../lists/server'; import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema'; -import { RulesClient, AlertServices } from '../../../../../alerting/server'; +import { RulesClient, RuleExecutorServices } from '../../../../../alerting/server'; import { getExportDetailsNdjson } from './get_export_details_ndjson'; @@ -43,7 +43,7 @@ export interface RulesErrors { export const getExportByObjectIds = async ( rulesClient: RulesClient, exceptionsClient: ExceptionListClient | undefined, - savedObjectsClient: AlertServices['savedObjectsClient'], + savedObjectsClient: RuleExecutorServices['savedObjectsClient'], objects: Array<{ rule_id: string }>, logger: Logger, isRuleRegistryEnabled: boolean @@ -81,7 +81,7 @@ export const getExportByObjectIds = async ( export const getRulesFromObjects = async ( rulesClient: RulesClient, - savedObjectsClient: AlertServices['savedObjectsClient'], + savedObjectsClient: RuleExecutorServices['savedObjectsClient'], objects: Array<{ rule_id: string }>, logger: Logger, isRuleRegistryEnabled: boolean diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts index 3f7191a970020..59fcca766f1b9 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/install_prepacked_rules.ts @@ -6,7 +6,7 @@ */ import { AddPrepackagedRulesSchemaDecoded } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; -import { SanitizedAlert, AlertTypeParams } from '../../../../../alerting/common'; +import { SanitizedRule, RuleTypeParams } from '../../../../../alerting/common'; import { RulesClient } from '../../../../../alerting/server'; import { createRules } from './create_rules'; import { PartialFilter } from '../types'; @@ -16,8 +16,8 @@ export const installPrepackagedRules = ( rules: AddPrepackagedRulesSchemaDecoded[], outputIndex: string, isRuleRegistryEnabled: boolean -): Array>> => - rules.reduce>>>((acc, rule) => { +): Array>> => + rules.reduce>>>((acc, rule) => { const { anomaly_threshold: anomalyThreshold, author, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts index b862dca6a022a..8b86f139cd742 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/patch_rules.ts @@ -7,7 +7,7 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { defaults } from 'lodash/fp'; -import { PartialAlert } from '../../../../../alerting/server'; +import { PartialRule } from '../../../../../alerting/server'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; import { normalizeMachineLearningJobIds, @@ -85,7 +85,7 @@ export const patchRules = async ({ anomalyThreshold, machineLearningJobId, actions, -}: PatchRulesOptions): Promise | null> => { +}: PatchRulesOptions): Promise | null> => { if (rule == null) { return null; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts index 2571791164b6b..b866755e00371 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/read_rules.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ResolvedSanitizedRule, SanitizedAlert } from '../../../../../alerting/common'; +import { ResolvedSanitizedRule, SanitizedRule } from '../../../../../alerting/common'; import { INTERNAL_RULE_ID_KEY } from '../../../../common/constants'; import { RuleParams } from '../schemas/rule_schemas'; import { findRules } from './find_rules'; @@ -25,7 +25,7 @@ export const readRules = async ({ id, ruleId, }: ReadRuleOptions): Promise< - SanitizedAlert | ResolvedSanitizedRule | null + SanitizedRule | ResolvedSanitizedRule | null > => { if (id != null) { try { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts index 7e66f1d0aa7a2..6c98ba56b9c88 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/types.ts @@ -93,13 +93,13 @@ import { NamespaceOrUndefined, } from '../../../../common/detection_engine/schemas/common'; -import { RulesClient, PartialAlert } from '../../../../../alerting/server'; -import { SanitizedAlert } from '../../../../../alerting/common'; +import { RulesClient, PartialRule } from '../../../../../alerting/server'; +import { SanitizedRule } from '../../../../../alerting/common'; import { PartialFilter } from '../types'; import { RuleParams } from '../schemas/rule_schemas'; import { IRuleExecutionLogForRoutes } from '../rule_execution_log'; -export type RuleAlertType = SanitizedAlert; +export type RuleAlertType = SanitizedRule; // eslint-disable-next-line @typescript-eslint/no-explicit-any export interface IRuleAssetSOAttributes extends Record { @@ -126,14 +126,14 @@ export interface Clients { export const isAlertTypes = ( isRuleRegistryEnabled: boolean, - partialAlert: Array> + partialAlert: Array> ): partialAlert is RuleAlertType[] => { return partialAlert.every((rule) => isAlertType(isRuleRegistryEnabled, rule)); }; export const isAlertType = ( isRuleRegistryEnabled: boolean, - partialAlert: PartialAlert + partialAlert: PartialRule ): partialAlert is RuleAlertType => { const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[]; return isRuleRegistryEnabled @@ -287,5 +287,5 @@ export interface FindRuleOptions { export interface LegacyMigrateParams { rulesClient: RulesClient; savedObjectsClient: SavedObjectsClientContract; - rule: SanitizedAlert | null | undefined; + rule: SanitizedRule | null | undefined; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts index ceb6a3739bd6c..93b038fbb58ce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_prepacked_rules.ts @@ -9,7 +9,7 @@ import { chunk } from 'lodash/fp'; import { SavedObjectsClientContract } from 'kibana/server'; import { AddPrepackagedRulesSchemaDecoded } from '../../../../common/detection_engine/schemas/request/add_prepackaged_rules_schema'; import { MAX_RULES_TO_UPDATE_IN_PARALLEL } from '../../../../common/constants'; -import { RulesClient, PartialAlert } from '../../../../../alerting/server'; +import { RulesClient, PartialRule } from '../../../../../alerting/server'; import { patchRules } from './patch_rules'; import { readRules } from './read_rules'; import { PartialFilter } from '../types'; @@ -67,7 +67,7 @@ export const createPromises = ( outputIndex: string, isRuleRegistryEnabled: boolean, ruleExecutionLog: IRuleExecutionLogForRoutes -): Array | null>> => { +): Array | null>> => { return rules.map(async (rule) => { const { author, @@ -202,7 +202,7 @@ export const createPromises = ( // the existing rule exceptionsList, actions: migratedRule.actions.map(transformAlertToRuleAction), // Actions come from the existing rule - })) as PartialAlert; // TODO: Replace AddPrepackagedRulesSchema with type specific rules schema so we can clean up these types + })) as PartialRule; // TODO: Replace AddPrepackagedRulesSchema with type specific rules schema so we can clean up these types } else { // Note: we do not pass down enabled as we do not want to suddenly disable // or enable rules on the user when they were not expecting it if a rule updates diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts index 6c13955aaab58..23038df541ff2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/update_rules.ts @@ -9,7 +9,7 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { DEFAULT_MAX_SIGNALS } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { PartialAlert } from '../../../../../alerting/server'; +import { PartialRule } from '../../../../../alerting/server'; import { UpdateRulesOptions } from './types'; import { addTags } from './add_tags'; @@ -30,7 +30,7 @@ export const updateRules = async ({ defaultOutputIndex, existingRule, ruleUpdate, -}: UpdateRulesOptions): Promise | null> => { +}: UpdateRulesOptions): Promise | null> => { if (existingRule == null) { return null; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts index 448d1b1a1db63..06324f4827b84 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.test.ts @@ -14,7 +14,7 @@ import { transformFromAlertThrottle, transformActions, } from './utils'; -import { AlertAction, SanitizedAlert } from '../../../../../alerting/common'; +import { RuleAction, SanitizedRule } from '../../../../../alerting/common'; import { RuleParams } from '../schemas/rule_schemas'; import { NOTIFICATION_THROTTLE_NO_ACTIONS, @@ -297,7 +297,7 @@ describe('utils', () => { params: {}, }, ], - } as SanitizedAlert, + } as SanitizedRule, undefined ) ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); @@ -310,7 +310,7 @@ describe('utils', () => { muteAll: false, notifyWhen: 'onActiveAlert', actions: [], - } as unknown as SanitizedAlert, + } as unknown as SanitizedRule, undefined ) ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); @@ -324,7 +324,7 @@ describe('utils', () => { notifyWhen: 'onThrottleInterval', actions: [], throttle: '1d', - } as unknown as SanitizedAlert, + } as unknown as SanitizedRule, undefined ) ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); @@ -344,7 +344,7 @@ describe('utils', () => { params: {}, }, ], - } as SanitizedAlert, + } as SanitizedRule, undefined ) ).toEqual(NOTIFICATION_THROTTLE_RULE); @@ -363,7 +363,7 @@ describe('utils', () => { params: {}, }, ], - } as SanitizedAlert, + } as SanitizedRule, undefined ) ).toEqual(NOTIFICATION_THROTTLE_RULE); @@ -397,7 +397,7 @@ describe('utils', () => { params: {}, }, ], - } as SanitizedAlert, + } as SanitizedRule, legacyRuleActions ) ).toEqual(NOTIFICATION_THROTTLE_NO_ACTIONS); @@ -424,7 +424,7 @@ describe('utils', () => { muteAll: true, notifyWhen: 'onActiveAlert', actions: [], - } as unknown as SanitizedAlert, + } as unknown as SanitizedRule, legacyRuleActions ) ).toEqual(NOTIFICATION_THROTTLE_RULE); @@ -451,7 +451,7 @@ describe('utils', () => { muteAll: true, notifyWhen: 'onActiveAlert', actions: null, - } as unknown as SanitizedAlert, + } as unknown as SanitizedRule, legacyRuleActions ) ).toEqual(NOTIFICATION_THROTTLE_RULE); @@ -460,7 +460,7 @@ describe('utils', () => { describe('#transformActions', () => { test('It transforms two alert actions', () => { - const alertAction: AlertAction[] = [ + const alertAction: RuleAction[] = [ { id: 'id_1', group: 'group', @@ -493,7 +493,7 @@ describe('utils', () => { }); test('It transforms two alert actions but not a legacyRuleActions if this is also passed in', () => { - const alertAction: AlertAction[] = [ + const alertAction: RuleAction[] = [ { id: 'id_1', group: 'group', @@ -538,7 +538,7 @@ describe('utils', () => { }); test('It will transform the legacyRuleActions if the alertAction is an empty array', () => { - const alertAction: AlertAction[] = []; + const alertAction: RuleAction[] = []; const legacyRuleActions: LegacyRuleActions = { id: 'id_1', ruleThrottle: '', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts index 73039697268e6..fe5785d841b8f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rules/utils.ts @@ -28,7 +28,7 @@ import type { } from '@kbn/securitysolution-io-ts-alerting-types'; import type { ListArrayOrUndefined } from '@kbn/securitysolution-io-ts-list-types'; import type { VersionOrUndefined } from '@kbn/securitysolution-io-ts-types'; -import { AlertAction, AlertNotifyWhenType, SanitizedAlert } from '../../../../../alerting/common'; +import { RuleAction, RuleNotifyWhenType, SanitizedRule } from '../../../../../alerting/common'; import { DescriptionOrUndefined, AnomalyThresholdOrUndefined, @@ -194,7 +194,7 @@ export const calculateName = ({ */ export const transformToNotifyWhen = ( throttle: string | null | undefined -): AlertNotifyWhenType | null => { +): RuleNotifyWhenType | null => { if (throttle == null || throttle === NOTIFICATION_THROTTLE_NO_ACTIONS) { return null; // Although I return null, this does not change the value of the "notifyWhen" and it keeps the current value of "notifyWhen" } else if (throttle === NOTIFICATION_THROTTLE_RULE) { @@ -232,7 +232,7 @@ export const transformToAlertThrottle = (throttle: string | null | undefined): s * @returns The actions of the FullResponseSchema */ export const transformActions = ( - alertAction: AlertAction[] | undefined, + alertAction: RuleAction[] | undefined, legacyRuleActions: LegacyRuleActions | null | undefined ): FullResponseSchema['actions'] => { if (alertAction != null && alertAction.length !== 0) { @@ -254,7 +254,7 @@ export const transformActions = ( * @returns The "security_solution" throttle */ export const transformFromAlertThrottle = ( - rule: SanitizedAlert, + rule: SanitizedRule, legacyRuleActions: LegacyRuleActions | null | undefined ): string => { if (legacyRuleActions == null || (rule.actions != null && rule.actions.length > 0)) { @@ -288,9 +288,9 @@ export const maybeMute = async ({ muteAll, throttle, }: { - id: SanitizedAlert['id']; + id: SanitizedRule['id']; rulesClient: RulesClient; - muteAll: SanitizedAlert['muteAll']; + muteAll: SanitizedRule['muteAll']; throttle: string | null | undefined; }): Promise => { if (muteAll && throttle !== NOTIFICATION_THROTTLE_NO_ACTIONS) { @@ -310,7 +310,7 @@ export const legacyMigrate = async ({ rulesClient, savedObjectsClient, rule, -}: LegacyMigrateParams): Promise | null | undefined> => { +}: LegacyMigrateParams): Promise | null | undefined> => { if (rule == null || rule.id == null) { return rule; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts index fbfab6304a4aa..d72cdc560543f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/schemas/rule_converters.ts @@ -31,7 +31,7 @@ import { AppClient } from '../../../types'; import { addTags } from '../rules/add_tags'; import { DEFAULT_MAX_SIGNALS, SERVER_APP_ID } from '../../../../common/constants'; import { transformRuleToAlertAction } from '../../../../common/detection_engine/transform_actions'; -import { ResolvedSanitizedRule, SanitizedAlert } from '../../../../../alerting/common'; +import { ResolvedSanitizedRule, SanitizedRule } from '../../../../../alerting/common'; import { transformTags } from '../routes/rules/utils'; import { transformFromAlertThrottle, @@ -283,7 +283,7 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { }; export const internalRuleToAPIResponse = ( - rule: SanitizedAlert | ResolvedSanitizedRule, + rule: SanitizedRule | ResolvedSanitizedRule, ruleExecutionSummary?: RuleExecutionSummary | null, legacyRuleActions?: LegacyRuleActions | null ): FullResponseSchema => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts index 1a35d9f0771fe..fdd6dcf0f4da2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/bulk_create_ml_signals.ts @@ -12,7 +12,7 @@ import { Logger } from '../../../../../../../src/core/server'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../alerting/server'; import { GenericBulkCreateResponse } from '../rule_types/factories'; import { AnomalyResults, Anomaly } from '../../machine_learning'; @@ -25,7 +25,7 @@ import { BaseFieldsLatest } from '../../../../common/detection_engine/schemas/al interface BulkCreateMlSignalsParams { someResult: AnomalyResults; completeRule: CompleteRule; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; id: string; signalsIndex: string; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts index 604a3a79e7152..e7810e6fe0078 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.test.ts @@ -7,7 +7,7 @@ import dateMath from '@elastic/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; -import { alertsMock, AlertServicesMock } from '../../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { eqlExecutor } from './eql'; import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { getEntryListMock } from '../../../../../../lists/common/schemas/types/entry_list.mock'; @@ -22,7 +22,7 @@ jest.mock('../../routes/index/get_index_version'); describe('eql_executor', () => { const version = '8.0.0'; let logger: ReturnType; - let alertServices: AlertServicesMock; + let alertServices: RuleExecutorServicesMock; (getIndexVersion as jest.Mock).mockReturnValue(SIGNALS_TEMPLATE_VERSION); const params = getEqlRuleParams(); const eqlCompleteRule = getCompleteRuleMock(params); @@ -33,7 +33,7 @@ describe('eql_executor', () => { }; beforeEach(() => { - alertServices = alertsMock.createAlertServices(); + alertServices = alertsMock.createRuleExecutorServices(); logger = loggingSystemMock.createLogger(); alertServices.scopedClusterClient.asCurrentUser.eql.search.mockResolvedValue({ hits: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts index dd9d5e2938e67..6975445f5d04f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/eql.ts @@ -11,7 +11,7 @@ import { Logger } from 'src/core/server'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { buildEqlSearchRequest } from '../build_events_query'; import { hasLargeValueItem } from '../../../../../common/detection_engine/utils'; @@ -54,7 +54,7 @@ export const eqlExecutor = async ({ tuple: RuleRangeTuple; exceptionItems: ExceptionListItemSchema[]; experimentalFeatures: ExperimentalFeatures; - services: AlertServices; + services: RuleExecutorServices; version: string; logger: Logger; bulkCreate: BulkCreate; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts index 9b93ba182785f..417382b0bd05a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.test.ts @@ -7,7 +7,7 @@ import dateMath from '@elastic/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; -import { alertsMock, AlertServicesMock } from '../../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { mlExecutor } from './ml'; import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { getCompleteRuleMock, getMlRuleParams } from '../../schemas/rule_schemas.mock'; @@ -26,7 +26,7 @@ describe('ml_executor', () => { let mlMock: ReturnType; const exceptionItems = [getExceptionListItemSchemaMock()]; let logger: ReturnType; - let alertServices: AlertServicesMock; + let alertServices: RuleExecutorServicesMock; const params = getMlRuleParams(); const mlCompleteRule = getCompleteRuleMock(params); @@ -44,7 +44,7 @@ describe('ml_executor', () => { beforeEach(() => { jobsSummaryMock = jest.fn(); - alertServices = alertsMock.createAlertServices(); + alertServices = alertsMock.createRuleExecutorServices(); logger = loggingSystemMock.createLogger(); mlMock = mlPluginServerMock.createSetupContract(); mlMock.jobServiceProvider.mockReturnValue({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts index 3610c45017019..d20885ebb9292 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/ml.ts @@ -10,7 +10,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { ListClient } from '../../../../../../lists/server'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; @@ -41,7 +41,7 @@ export const mlExecutor = async ({ ml: SetupPlugins['ml']; listClient: ListClient; exceptionItems: ExceptionListItemSchema[]; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; buildRuleMessage: BuildRuleMessage; bulkCreate: BulkCreate; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts index 5f1ab1c2dd5ff..da1e93bf76b54 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/query.ts @@ -10,7 +10,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { ListClient } from '../../../../../../lists/server'; import { getFilter } from '../get_filter'; @@ -44,7 +44,7 @@ export const queryExecutor = async ({ listClient: ListClient; exceptionItems: ExceptionListItemSchema[]; experimentalFeatures: ExperimentalFeatures; - services: AlertServices; + services: RuleExecutorServices; version: string; searchAfterSize: number; logger: Logger; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts index 00edf2fffc8e0..1aedf7111e078 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threat_match.ts @@ -10,7 +10,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { ListClient } from '../../../../../../lists/server'; import { getInputIndex } from '../get_input_output_index'; @@ -42,7 +42,7 @@ export const threatMatchExecutor = async ({ tuple: RuleRangeTuple; listClient: ListClient; exceptionItems: ExceptionListItemSchema[]; - services: AlertServices; + services: RuleExecutorServices; version: string; searchAfterSize: number; logger: Logger; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts index e01e3498c2c7a..14c56aa3bc9be 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.test.ts @@ -9,7 +9,7 @@ import dateMath from '@elastic/datemath'; import { loggingSystemMock } from 'src/core/server/mocks'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; -import { alertsMock, AlertServicesMock } from '../../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { thresholdExecutor } from './threshold'; import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { getEntryListMock } from '../../../../../../lists/common/schemas/types/entry_list.mock'; @@ -22,7 +22,7 @@ import { ThresholdRuleParams } from '../../schemas/rule_schemas'; describe('threshold_executor', () => { const version = '8.0.0'; let logger: ReturnType; - let alertServices: AlertServicesMock; + let alertServices: RuleExecutorServicesMock; const params = getThresholdRuleParams(); const thresholdCompleteRule = getCompleteRuleMock(params); @@ -40,7 +40,7 @@ describe('threshold_executor', () => { }); beforeEach(() => { - alertServices = alertsMock.createAlertServices(); + alertServices = alertsMock.createRuleExecutorServices(); alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValue( elasticsearchClientMock.createSuccessTransportRequestPromise(sampleEmptyDocSearchResults()) ); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts index 441baa7ee94fd..7055269abacda 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/executors/threshold.ts @@ -13,7 +13,7 @@ import { Logger } from 'src/core/server'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { hasLargeValueItem } from '../../../../../common/detection_engine/utils'; import { CompleteRule, ThresholdRuleParams } from '../../schemas/rule_schemas'; @@ -60,7 +60,7 @@ export const thresholdExecutor = async ({ tuple: RuleRangeTuple; exceptionItems: ExceptionListItemSchema[]; experimentalFeatures: ExperimentalFeatures; - services: AlertServices; + services: RuleExecutorServices; version: string; logger: Logger; buildRuleMessage: BuildRuleMessage; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts index 49f70eafd7d3a..6e824a9a639a3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts @@ -6,18 +6,18 @@ */ import { getFilter } from './get_filter'; -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; describe('get_filter', () => { - let servicesMock: AlertServicesMock; + let servicesMock: RuleExecutorServicesMock; beforeAll(() => { jest.resetAllMocks(); }); beforeEach(() => { - servicesMock = alertsMock.createAlertServices(); + servicesMock = alertsMock.createRuleExecutorServices(); servicesMock.savedObjectsClient.get.mockImplementation(async (type: string, id: string) => ({ id, type, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts index f113e84c88ba8..d674cc9a3e5a1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.ts @@ -18,7 +18,7 @@ import { import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../alerting/server'; import { PartialFilter } from '../types'; import { withSecuritySpan } from '../../../utils/with_security_span'; @@ -30,7 +30,7 @@ interface GetFilterArgs { language: LanguageOrUndefined; query: QueryOrUndefined; savedId: SavedIdOrUndefined; - services: AlertServices; + services: RuleExecutorServices; index: IndexOrUndefined; lists: ExceptionListItemSchema[]; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.test.ts index 2aaa56493df60..fea6ac75677bf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.test.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; import { DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN } from '../../../../common/constants'; import { getInputIndex, GetInputIndex } from './get_input_output_index'; import { allowedExperimentalValues } from '../../../../common/experimental_features'; describe('get_input_output_index', () => { - let servicesMock: AlertServicesMock; + let servicesMock: RuleExecutorServicesMock; beforeAll(() => { jest.resetAllMocks(); @@ -22,7 +22,7 @@ describe('get_input_output_index', () => { }); let defaultProps: GetInputIndex; beforeEach(() => { - servicesMock = alertsMock.createAlertServices(); + servicesMock = alertsMock.createRuleExecutorServices(); servicesMock.savedObjectsClient.get.mockImplementation(async (type: string, id: string) => ({ id, type, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.ts index ba1b9344aa8a1..c2a77cb608303 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_input_output_index.ts @@ -9,7 +9,7 @@ import { DEFAULT_INDEX_KEY, DEFAULT_INDEX_PATTERN } from '../../../../common/con import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../alerting/server'; import { ExperimentalFeatures } from '../../../../common/experimental_features'; import { withSecuritySpan } from '../../../utils/with_security_span'; @@ -17,7 +17,7 @@ import { withSecuritySpan } from '../../../utils/with_security_span'; export interface GetInputIndex { experimentalFeatures: ExperimentalFeatures; index: string[] | null | undefined; - services: AlertServices; + services: RuleExecutorServices; version: string; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts index 88d6114387aa3..3958cb2a81a7f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/preview/alert_instance_factory_stub.ts @@ -9,14 +9,14 @@ import { RuleParams } from '../../schemas/rule_schemas'; import { AlertInstanceContext, AlertInstanceState, - AlertTypeState, + RuleTypeState, } from '../../../../../../alerting/common'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { Alert } from '../../../../../../alerting/server/alert'; export const alertInstanceFactoryStub = < TParams extends RuleParams, - TState extends AlertTypeState, + TState extends RuleTypeState, TInstanceState extends AlertInstanceState, TInstanceContext extends AlertInstanceContext, TActionGroupIds extends string = '' diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts index d6332af195fcf..58e472c75870c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/search_after_bulk_create.test.ts @@ -15,7 +15,7 @@ import { sampleDocWithSortId, } from './__mocks__/es_results'; import { searchAfterAndBulkCreate } from './search_after_bulk_create'; -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; import uuid from 'uuid'; import { listMock } from '../../../../../lists/server/mocks'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; @@ -51,7 +51,7 @@ import { CommonAlertFieldsLatest } from '../../../../../rule_registry/common/sch const buildRuleMessage = mockBuildRuleMessage; describe('searchAfterAndBulkCreate', () => { - let mockService: AlertServicesMock; + let mockService: RuleExecutorServicesMock; let mockPersistenceServices: jest.Mocked; let buildReasonMessage: BuildReasonMessage; let bulkCreate: BulkCreate; @@ -84,7 +84,7 @@ describe('searchAfterAndBulkCreate', () => { listClient = listMock.getListClient(); listClient.searchListItemByValues = jest.fn().mockResolvedValue([]); inputIndexPattern = ['auditbeat-*']; - mockService = alertsMock.createAlertServices(); + mockService = alertsMock.createRuleExecutorServices(); tuple = getRuleRangeTuples({ logger: mockLogger, previousStartedAt: new Date(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts index d00925af74316..5bbef98b48335 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.test.ts @@ -11,7 +11,7 @@ import { sampleDocSearchResultsWithSortId, } from './__mocks__/es_results'; import { singleSearchAfter } from './single_search_after'; -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; import { buildRuleMessageFactory } from './rule_messages'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { elasticsearchClientMock } from 'src/core/server/elasticsearch/client/mocks'; @@ -23,7 +23,7 @@ const buildRuleMessage = buildRuleMessageFactory({ name: 'fake name', }); describe('singleSearchAfter', () => { - const mockService: AlertServicesMock = alertsMock.createAlertServices(); + const mockService: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); beforeEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts index 62b0097c17e75..c247cf00b141f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/single_search_after.ts @@ -9,7 +9,7 @@ import { performance } from 'perf_hooks'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../alerting/server'; import { Logger } from '../../../../../../../src/core/server'; import type { SignalSearchResponse, SignalSource } from './types'; @@ -25,7 +25,7 @@ interface SingleSearchAfterParams { index: string[]; from: string; to: string; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; pageSize: number; sortOrder?: estypes.SortOrder; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts index f0f2d7e1af3b5..08915efd4f372 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threat_mapping/types.ts @@ -23,7 +23,7 @@ import { ListClient } from '../../../../../../lists/server'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { ElasticsearchClient, Logger } from '../../../../../../../../src/core/server'; import { ITelemetryEventsSender } from '../../../telemetry/sender'; @@ -57,7 +57,7 @@ export interface CreateThreatSignalsOptions { query: string; savedId: string | undefined; searchAfterSize: number; - services: AlertServices; + services: RuleExecutorServices; threatFilters: unknown[]; threatIndex: ThreatIndex; threatIndicatorPath: ThreatIndicatorPath; @@ -87,7 +87,7 @@ export interface CreateThreatSignalOptions { query: string; savedId: string | undefined; searchAfterSize: number; - services: AlertServices; + services: RuleExecutorServices; threatEnrichment: SignalsEnrichment; threatMapping: ThreatMapping; tuple: RuleRangeTuple; @@ -113,7 +113,7 @@ export interface CreateEventSignalOptions { query: string; savedId: string | undefined; searchAfterSize: number; - services: AlertServices; + services: RuleExecutorServices; threatEnrichment: SignalsEnrichment; tuple: RuleRangeTuple; type: Type; @@ -234,7 +234,7 @@ export interface BuildThreatEnrichmentOptions { buildRuleMessage: BuildRuleMessage; exceptionItems: ExceptionListItemSchema[]; logger: Logger; - services: AlertServices; + services: RuleExecutorServices; threatFilters: unknown[]; threatIndex: ThreatIndex; threatIndicatorPath: ThreatIndicatorPath; @@ -245,7 +245,7 @@ export interface BuildThreatEnrichmentOptions { } export interface EventsOptions { - services: AlertServices; + services: RuleExecutorServices; query: string; buildRuleMessage: BuildRuleMessage; language: ThreatLanguageOrUndefined; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts index 49a81a47502d2..f7d0418f63b2c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/bulk_create_threshold_signals.ts @@ -14,7 +14,7 @@ import { Logger } from '../../../../../../../../src/core/server'; import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { BaseHit } from '../../../../../common/detection_engine/types'; import { TermAggregationBucket } from '../../../types'; @@ -35,7 +35,7 @@ import { BaseFieldsLatest } from '../../../../../common/detection_engine/schemas interface BulkCreateThresholdSignalsParams { someResult: SignalSearchResponse; completeRule: CompleteRule; - services: AlertServices; + services: RuleExecutorServices; inputIndexPattern: string[]; logger: Logger; filter: unknown; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_previous_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_previous_threshold_signals.ts index 1a2bfbf3a962d..3cfa2be0202f5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_previous_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_previous_threshold_signals.ts @@ -9,7 +9,7 @@ import { TimestampOverrideOrUndefined } from '../../../../../common/detection_en import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { Logger } from '../../../../../../../../src/core/server'; import { BuildRuleMessage } from '../rule_messages'; @@ -20,7 +20,7 @@ interface FindPreviousThresholdSignalsParams { from: string; to: string; indexPattern: string[]; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; ruleId: string; bucketByFields: string[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts index 3a1149e8c8e99..5b0ee22d87093 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { alertsMock, AlertServicesMock } from '../../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../../alerting/server/mocks'; import { getQueryFilter } from '../../../../../common/detection_engine/get_query_filter'; import { mockLogger } from '../__mocks__/es_results'; import { buildRuleMessageFactory } from '../rule_messages'; @@ -24,12 +24,12 @@ const mockSingleSearchAfter = jest.fn(); // Failing with rule registry enabled describe('findThresholdSignals', () => { - let mockService: AlertServicesMock; + let mockService: RuleExecutorServicesMock; beforeEach(() => { jest.clearAllMocks(); jest.spyOn(single_search_after, 'singleSearchAfter').mockImplementation(mockSingleSearchAfter); - mockService = alertsMock.createAlertServices(); + mockService = alertsMock.createRuleExecutorServices(); }); it('should generate a threshold signal query when only a value is provided', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts index 52aa429dd64d6..45b56dce7e69e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/find_threshold_signals.ts @@ -15,7 +15,7 @@ import { import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { Logger } from '../../../../../../../../src/core/server'; import { BuildRuleMessage } from '../rule_messages'; @@ -26,7 +26,7 @@ interface FindThresholdSignalsParams { from: string; to: string; inputIndexPattern: string[]; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; filter: unknown; threshold: ThresholdNormalized; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/get_threshold_signal_history.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/get_threshold_signal_history.ts index 276431c3bc929..097bdfe8d6034 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/get_threshold_signal_history.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/threshold/get_threshold_signal_history.ts @@ -9,7 +9,7 @@ import { TimestampOverrideOrUndefined } from '../../../../../common/detection_en import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, } from '../../../../../../alerting/server'; import { Logger } from '../../../../../../../../src/core/server'; import { ThresholdSignalHistory } from '../types'; @@ -21,7 +21,7 @@ interface GetThresholdSignalHistoryParams { from: string; to: string; indexPattern: string[]; - services: AlertServices; + services: RuleExecutorServices; logger: Logger; ruleId: string; bucketByFields: string[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts index bbe6adc5c729f..541d2cd4c19b8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/types.ts @@ -12,11 +12,11 @@ import { Status } from '../../../../common/detection_engine/schemas/common/schem import { RulesSchema } from '../../../../common/detection_engine/schemas/response/rules_schema'; import { RuleType, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, - AlertExecutorOptions, - AlertServices, + RuleExecutorOptions as AlertingRuleExecutorOptions, + RuleExecutorServices, } from '../../../../../alerting/server'; import { TermAggregationBucket } from '../../types'; import { @@ -189,9 +189,9 @@ export type AlertSourceHit = estypes.SearchHit; export type WrappedSignalHit = BaseHit; export type BaseSignalHit = estypes.SearchHit; -export type RuleExecutorOptions = AlertExecutorOptions< +export type RuleExecutorOptions = AlertingRuleExecutorOptions< RuleParams, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext >; @@ -203,7 +203,7 @@ export const isAlertExecutor = ( ): obj is RuleType< RuleParams, RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values. - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, 'default' @@ -214,7 +214,7 @@ export const isAlertExecutor = ( export type SignalRuleAlertTypeDefinition = RuleType< RuleParams, RuleParams, // This type is used for useSavedObjectReferences, use an Omit here if you want to remove any values. - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, 'default' @@ -302,7 +302,7 @@ export interface SearchAfterAndBulkCreateParams { maxSignals: number; }; completeRule: CompleteRule; - services: AlertServices; + services: RuleExecutorServices; listClient: ListClient; exceptionsList: ExceptionListItemSchema[]; logger: Logger; @@ -361,7 +361,7 @@ export interface ThresholdQueryBucket extends TermAggregationBucket { }; } -export interface ThresholdAlertState extends AlertTypeState { +export interface ThresholdAlertState extends RuleTypeState { initialized: boolean; signalHistory: ThresholdSignalHistory; } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index 7c020a476c41b..02ed86b65e878 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -10,7 +10,7 @@ import sinon from 'sinon'; import type { TransportResult } from '@elastic/elasticsearch'; import { ALERT_REASON, ALERT_RULE_PARAMETERS, ALERT_UUID } from '@kbn/rule-data-utils'; -import { alertsMock, AlertServicesMock } from '../../../../../alerting/server/mocks'; +import { alertsMock, RuleExecutorServicesMock } from '../../../../../alerting/server/mocks'; import { listMock } from '../../../../../lists/server/mocks'; import { buildRuleMessageFactory } from './rule_messages'; import { ExceptionListClient } from '../../../../../lists/server'; @@ -426,10 +426,10 @@ describe('utils', () => { }); describe('#getListsClient', () => { - let alertServices: AlertServicesMock; + let alertServices: RuleExecutorServicesMock; beforeEach(() => { - alertServices = alertsMock.createAlertServices(); + alertServices = alertsMock.createRuleExecutorServices(); }); test('it successfully returns list and exceptions list client', async () => { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 0a4618d81081b..a0d73707466ce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -34,7 +34,7 @@ import type { import { AlertInstanceContext, AlertInstanceState, - AlertServices, + RuleExecutorServices, parseDuration, } from '../../../../../alerting/server'; import type { ExceptionListClient, ListClient, ListPluginSetup } from '../../../../../lists/server'; @@ -193,7 +193,7 @@ export const hasTimestampFields = async (args: { }; export const checkPrivileges = async ( - services: AlertServices, + services: RuleExecutorServices, indices: string[] ): Promise => checkPrivilegesFromEsClient(services.scopedClusterClient.asCurrentUser, indices); @@ -247,7 +247,7 @@ export const getListsClient = ({ lists: ListPluginSetup | undefined; spaceId: string; updatedByUser: string | null; - services: AlertServices; + services: RuleExecutorServices; savedObjectClient: SavedObjectsClientContract; }): { listClient: ListClient; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts index f25c23d2d5ed3..d81832d9bbe35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/types.ts @@ -53,11 +53,11 @@ import { EventCategoryOverrideOrUndefined, } from '../../../common/detection_engine/schemas/common/schemas'; -import { AlertTypeParams } from '../../../../alerting/common'; +import { RuleTypeParams as AlertingRuleTypeParams } from '../../../../alerting/common'; export type PartialFilter = Partial; -export interface RuleTypeParams extends AlertTypeParams { +export interface RuleTypeParams extends AlertingRuleTypeParams { anomalyThreshold?: AnomalyThresholdOrUndefined; author: AuthorOrUndefined; buildingBlockType: BuildingBlockTypeOrUndefined; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts index fda1e1c166ce3..901d577fdbf5a 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.test.ts @@ -13,7 +13,6 @@ import { hostOverview } from './overview'; import { firstOrLastSeenHost } from './last_first_seen'; import { uncommonProcesses } from './uncommon_processes'; -import { authentications, authenticationsEntities } from './authentications'; import { hostsKpiAuthentications, hostsKpiAuthenticationsEntities } from './kpi/authentications'; import { hostsKpiHosts, hostsKpiHostsEntities } from './kpi/hosts'; import { hostsKpiUniqueIps, hostsKpiUniqueIpsEntities } from './kpi/unique_ips'; @@ -23,7 +22,6 @@ jest.mock('./details'); jest.mock('./overview'); jest.mock('./last_first_seen'); jest.mock('./uncommon_processes'); -jest.mock('./authentications'); jest.mock('./kpi/authentications'); jest.mock('./kpi/hosts'); jest.mock('./kpi/unique_ips'); @@ -36,8 +34,6 @@ describe('hostsFactory', () => { [HostsQueries.overview]: hostOverview, [HostsQueries.firstOrLastSeen]: firstOrLastSeenHost, [HostsQueries.uncommonProcesses]: uncommonProcesses, - [HostsQueries.authentications]: authentications, - [HostsQueries.authenticationsEntities]: authenticationsEntities, [HostsKpiQueries.kpiAuthentications]: hostsKpiAuthentications, [HostsKpiQueries.kpiAuthenticationsEntities]: hostsKpiAuthenticationsEntities, [HostsKpiQueries.kpiHosts]: hostsKpiHosts, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts index cd95a38ec3092..5d40e5e153599 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/index.ts @@ -17,7 +17,6 @@ import { hostDetails } from './details'; import { hostOverview } from './overview'; import { firstOrLastSeenHost } from './last_first_seen'; import { uncommonProcesses } from './uncommon_processes'; -import { authentications, authenticationsEntities } from './authentications'; import { hostsKpiAuthentications, hostsKpiAuthenticationsEntities } from './kpi/authentications'; import { hostsKpiHosts, hostsKpiHostsEntities } from './kpi/hosts'; import { hostsKpiUniqueIps, hostsKpiUniqueIpsEntities } from './kpi/unique_ips'; @@ -32,8 +31,6 @@ export const hostsFactory: Record< [HostsQueries.overview]: hostOverview, [HostsQueries.firstOrLastSeen]: firstOrLastSeenHost, [HostsQueries.uncommonProcesses]: uncommonProcesses, - [HostsQueries.authentications]: authentications, - [HostsQueries.authenticationsEntities]: authenticationsEntities, [HostsKpiQueries.kpiAuthentications]: hostsKpiAuthentications, [HostsKpiQueries.kpiAuthenticationsEntities]: hostsKpiAuthenticationsEntities, [HostsKpiQueries.kpiHosts]: hostsKpiHosts, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/__mocks__/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/__mocks__/index.ts similarity index 99% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/__mocks__/index.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/__mocks__/index.ts index 6e43d771d1a02..6b57ff7fdb7cd 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/__mocks__/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/__mocks__/index.ts @@ -6,15 +6,15 @@ */ import type { IEsSearchResponse } from '../../../../../../../../../../src/plugins/data/common'; - import { + UserAuthenticationsRequestOptions, AuthenticationHit, Direction, - HostAuthenticationsRequestOptions, - HostsQueries, + UsersQueries, + AuthStackByField, } from '../../../../../../../common/search_strategy'; -export const mockOptions: HostAuthenticationsRequestOptions = { +export const mockOptions: UserAuthenticationsRequestOptions = { defaultIndex: [ 'apm-*-transaction*', 'traces-apm*', @@ -25,6 +25,7 @@ export const mockOptions: HostAuthenticationsRequestOptions = { 'packetbeat-*', 'winlogbeat-*', ], + stackByField: AuthStackByField.userName, docValueFields: [ { field: '@timestamp', @@ -427,7 +428,7 @@ export const mockOptions: HostAuthenticationsRequestOptions = { format: 'date_time', }, ], - factoryQueryType: HostsQueries.authentications, + factoryQueryType: UsersQueries.authentications, filterQuery: '{"bool":{"must":[],"filter":[{"match_all":{}}],"should":[],"must_not":[]}}', pagination: { activePage: 0, @@ -456,7 +457,7 @@ export const mockSearchStrategyResponse: IEsSearchResponse = { _shards: { total: 21, successful: 21, skipped: 0, failed: 0 }, hits: { total: -1, max_score: 0, hits: [] }, aggregations: { - group_by_users: { + stack_by: { doc_count_error_upper_bound: -1, sum_other_doc_count: 408, buckets: [ @@ -1290,7 +1291,7 @@ export const mockSearchStrategyResponse: IEsSearchResponse = { }, ], }, - user_count: { value: 188 }, + stack_by_count: { value: 188 }, }, }, total: 21, @@ -1306,7 +1307,7 @@ export const formattedSearchStrategyResponse = { _shards: { total: 21, successful: 21, skipped: 0, failed: 0 }, hits: { total: -1, max_score: 0, hits: [] }, aggregations: { - group_by_users: { + stack_by: { doc_count_error_upper_bound: -1, sum_other_doc_count: 408, buckets: [ @@ -2140,7 +2141,7 @@ export const formattedSearchStrategyResponse = { }, ], }, - user_count: { value: 188 }, + stack_by_count: { value: 188 }, }, }, total: 21, @@ -2164,8 +2165,8 @@ export const formattedSearchStrategyResponse = { body: { docvalue_fields: mockOptions.docValueFields, aggregations: { - user_count: { cardinality: { field: 'user.name' } }, - group_by_users: { + stack_by_count: { cardinality: { field: 'user.name' } }, + stack_by: { terms: { size: 10, field: 'user.name', @@ -2231,7 +2232,7 @@ export const formattedSearchStrategyResponse = { failures: 0, successes: 4, _id: 'SYSTEM+281', - user: { name: ['SYSTEM'] }, + stackedValue: ['SYSTEM'], lastSuccess: { timestamp: ['2020-09-04T13:08:02.532Z'], host: { id: ['ce1d3c9b-a815-4643-9641-ada0f2c00609'], name: ['siem-windows'] }, @@ -2244,7 +2245,7 @@ export const formattedSearchStrategyResponse = { failures: 0, successes: 1, _id: 'tsg+1', - user: { name: ['tsg'] }, + stackedValue: ['tsg'], lastSuccess: { timestamp: ['2020-09-04T11:49:21.000Z'], source: { ip: ['77.183.42.188'] }, @@ -2258,7 +2259,7 @@ export const formattedSearchStrategyResponse = { failures: 23, successes: 0, _id: 'admin+23', - user: { name: ['admin'] }, + stackedValue: ['admin'], lastFailure: { timestamp: ['2020-09-04T13:40:46.000Z'], source: { ip: ['59.15.3.197'] }, @@ -2272,7 +2273,7 @@ export const formattedSearchStrategyResponse = { failures: 21, successes: 0, _id: 'user+21', - user: { name: ['user'] }, + stackedValue: ['user'], lastFailure: { timestamp: ['2020-09-04T13:25:43.000Z'], source: { ip: ['64.227.88.245'] }, @@ -2286,7 +2287,7 @@ export const formattedSearchStrategyResponse = { failures: 18, successes: 0, _id: 'ubuntu+18', - user: { name: ['ubuntu'] }, + stackedValue: ['ubuntu'], lastFailure: { timestamp: ['2020-09-04T13:25:07.000Z'], source: { ip: ['64.227.88.245'] }, @@ -2300,7 +2301,7 @@ export const formattedSearchStrategyResponse = { failures: 17, successes: 0, _id: 'odoo+17', - user: { name: ['odoo'] }, + stackedValue: ['odoo'], lastFailure: { timestamp: ['2020-09-04T12:26:36.000Z'], source: { ip: ['180.151.228.166'] }, @@ -2314,7 +2315,7 @@ export const formattedSearchStrategyResponse = { failures: 17, successes: 0, _id: 'pi+17', - user: { name: ['pi'] }, + stackedValue: ['pi'], lastFailure: { timestamp: ['2020-09-04T11:37:22.000Z'], source: { ip: ['178.174.148.58'] }, @@ -2328,7 +2329,7 @@ export const formattedSearchStrategyResponse = { failures: 14, successes: 0, _id: 'demo+14', - user: { name: ['demo'] }, + stackedValue: ['demo'], lastFailure: { timestamp: ['2020-09-04T07:23:22.000Z'], source: { ip: ['45.95.168.157'] }, @@ -2342,7 +2343,7 @@ export const formattedSearchStrategyResponse = { failures: 13, successes: 0, _id: 'git+13', - user: { name: ['git'] }, + stackedValue: ['git'], lastFailure: { timestamp: ['2020-09-04T11:20:26.000Z'], source: { ip: ['123.206.30.76'] }, @@ -2356,7 +2357,7 @@ export const formattedSearchStrategyResponse = { failures: 13, successes: 0, _id: 'webadmin+13', - user: { name: ['webadmin'] }, + stackedValue: ['webadmin'], lastFailure: { timestamp: ['2020-09-04T07:25:28.000Z'], source: { ip: ['45.95.168.157'] }, @@ -2386,8 +2387,8 @@ export const expectedDsl = { body: { docvalue_fields: mockOptions.docValueFields, aggregations: { - user_count: { cardinality: { field: 'user.name' } }, - group_by_users: { + stack_by_count: { cardinality: { field: 'user.name' } }, + stack_by: { terms: { size: 10, field: 'user.name', @@ -2445,7 +2446,7 @@ export const mockHit: AuthenticationHit = { }, cursor: 'cursor-1', sort: [0], - user: 'Evan', + stackedValue: 'Evan', failures: 10, successes: 20, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query.dsl.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query.dsl.test.ts similarity index 100% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query.dsl.test.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query.dsl.test.ts diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query.dsl.ts similarity index 90% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query.dsl.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query.dsl.ts index c88104745ba06..e018716d4c216 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query.dsl.ts @@ -7,7 +7,7 @@ import { isEmpty } from 'lodash/fp'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { HostAuthenticationsRequestOptions } from '../../../../../../../common/search_strategy/security_solution/hosts/authentications'; +import { UserAuthenticationsRequestOptions } from '../../../../../../../common/search_strategy/security_solution/users/authentications'; import { sourceFieldsMap, hostFieldsMap } from '../../../../../../../common/ecs/ecs_fields'; import { createQueryFilterClauses } from '../../../../../../utils/build_query'; @@ -28,11 +28,12 @@ export const auditdFieldsMap: Readonly> = { export const buildQuery = ({ filterQuery, + stackByField, timerange: { from, to }, pagination: { querySize }, defaultIndex, docValueFields, -}: HostAuthenticationsRequestOptions) => { +}: UserAuthenticationsRequestOptions) => { const esFields = reduceFields(authenticationsFields, { ...hostFieldsMap, ...sourceFieldsMap, @@ -52,14 +53,6 @@ export const buildQuery = ({ }, ]; - const agg = { - user_count: { - cardinality: { - field: 'user.name', - }, - }, - }; - const dslQuery = { allow_no_indices: true, index: defaultIndex, @@ -67,11 +60,15 @@ export const buildQuery = ({ body: { ...(!isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), aggregations: { - ...agg, - group_by_users: { + stack_by_count: { + cardinality: { + field: stackByField, + }, + }, + stack_by: { terms: { size: querySize, - field: 'user.name', + field: stackByField, order: [ { 'successes.doc_count': 'desc' as const }, { 'failures.doc_count': 'desc' as const }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query_entities.dsl.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query_entities.dsl.ts similarity index 83% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query_entities.dsl.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query_entities.dsl.ts index ab726b41ae01b..7c9c29a1efdc4 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/dsl/query_entities.dsl.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/dsl/query_entities.dsl.ts @@ -8,9 +8,8 @@ import { isEmpty } from 'lodash/fp'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { HostAuthenticationsRequestOptions } from '../../../../../../../common/search_strategy/security_solution/hosts/authentications'; - import { createQueryFilterClauses } from '../../../../../../utils/build_query'; +import { UserAuthenticationsRequestOptions } from '../../../../../../../common/search_strategy'; export const buildQueryEntities = ({ filterQuery, @@ -18,7 +17,8 @@ export const buildQueryEntities = ({ pagination: { querySize }, defaultIndex, docValueFields, -}: HostAuthenticationsRequestOptions) => { + stackByField, +}: UserAuthenticationsRequestOptions) => { const filter = [ ...createQueryFilterClauses(filterQuery), { @@ -32,14 +32,6 @@ export const buildQueryEntities = ({ }, ]; - const agg = { - user_count: { - cardinality: { - field: 'user.name', - }, - }, - }; - const dslQuery = { allow_no_indices: true, index: defaultIndex, @@ -47,11 +39,15 @@ export const buildQueryEntities = ({ body: { ...(!isEmpty(docValueFields) ? { docvalue_fields: docValueFields } : {}), aggregations: { - ...agg, - group_by_users: { + stack_by_count: { + cardinality: { + field: stackByField, + }, + }, + stack_by: { terms: { size: querySize, - field: 'user.name', + field: stackByField, order: [ { successes: 'desc' }, { failures: 'desc' }, diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.test.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.test.ts similarity index 90% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.test.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.test.ts index a8cce8a4c2bcf..1e745ffcbf2ed 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.test.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AuthenticationsEdges } from '../../../../../../common/search_strategy/security_solution/hosts/authentications'; +import { AuthenticationsEdges } from '../../../../../../common/search_strategy'; import { auditdFieldsMap } from './dsl/query.dsl'; import { formatAuthenticationData } from './helpers'; @@ -24,9 +24,7 @@ describe('#formatAuthenticationsData', () => { _id: 'id-123', failures: 10, successes: 20, - user: { - name: ['Evan'], - }, + stackedValue: ['Evan'], }, }; @@ -45,9 +43,7 @@ describe('#formatAuthenticationsData', () => { _id: 'id-123', failures: 10, successes: 20, - user: { - name: ['Evan'], - }, + stackedValue: ['Evan'], }, }; @@ -66,9 +62,7 @@ describe('#formatAuthenticationsData', () => { _id: 'id-123', failures: 10, successes: 20, - user: { - name: ['Evan'], - }, + stackedValue: ['Evan'], }, }; @@ -87,9 +81,7 @@ describe('#formatAuthenticationsData', () => { _id: 'id-123', failures: 10, successes: 20, - user: { - name: ['Evan'], - }, + stackedValue: ['Evan'], }, }; @@ -108,9 +100,7 @@ describe('#formatAuthenticationsData', () => { _id: 'id-123', failures: 10, successes: 20, - user: { - name: ['Evan'], - }, + stackedValue: ['Evan'], }, }; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts similarity index 91% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts index 7517d112aebdc..02a89dd08a222 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts @@ -21,7 +21,7 @@ export const authenticationsFields = [ '_id', 'failures', 'successes', - 'user.name', + 'stackedValue', 'lastSuccess.timestamp', 'lastSuccess.source.ip', 'lastSuccess.host.id', @@ -46,7 +46,7 @@ export const formatAuthenticationData = ( ...flattenedFields.node, ...{ _id: hit._id, - user: { name: [hit.user] }, + stackedValue: [hit.stackedValue], failures: hit.failures, successes: hit.successes, }, @@ -69,9 +69,7 @@ export const formatAuthenticationData = ( failures: 0, successes: 0, _id: '', - user: { - name: [''], - }, + stackedValue: [''], }, cursor: { value: '', @@ -81,7 +79,7 @@ export const formatAuthenticationData = ( ); export const getHits = (response: StrategyResponseType) => - getOr([], 'aggregations.group_by_users.buckets', response.rawResponse).map( + getOr([], 'aggregations.stack_by.buckets', response.rawResponse).map( (bucket: AuthenticationBucket) => ({ _id: getOr( `${bucket.key}+${bucket.doc_count}`, @@ -92,14 +90,14 @@ export const getHits = (response: StrategyResponseT lastSuccess: getOr(null, 'successes.lastSuccess.hits.hits[0]._source', bucket), lastFailure: getOr(null, 'failures.lastFailure.hits.hits[0]._source', bucket), }, - user: bucket.key, + stackedValue: bucket.key, failures: bucket.failures.doc_count, successes: bucket.successes.doc_count, }) ); export const getHitsEntities = (response: StrategyResponseType) => - getOr([], 'aggregations.group_by_users.buckets', response.rawResponse).map( + getOr([], 'aggregations.stack_by.buckets', response.rawResponse).map( (bucket: AuthenticationBucket) => ({ _id: getOr( `${bucket.key}+${bucket.doc_count}`, @@ -110,7 +108,7 @@ export const getHitsEntities = (response: StrategyR lastSuccess: getOr(null, 'successes.lastSuccess.hits.hits[0]._source', bucket), lastFailure: getOr(null, 'failures.lastFailure.hits.hits[0]._source', bucket), }, - user: bucket.key, + stackedValue: bucket.key, failures: bucket.failures.value, successes: bucket.successes.value, }) @@ -130,7 +128,7 @@ export const formatAuthenticationEntitiesData = ( ...flattenedFields.node, ...{ _id: hit._id, - user: { name: [hit.user] }, + stackedValue: [hit.stackedValue], failures: hit.failures, successes: hit.successes, }, @@ -153,9 +151,7 @@ export const formatAuthenticationEntitiesData = ( failures: 0, successes: 0, _id: '', - user: { - name: [''], - }, + stackedValue: [''], }, cursor: { value: '', diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.test.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.test.tsx similarity index 90% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.test.tsx rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.test.tsx index 960f1a516e814..e4342cf266474 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.test.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.test.tsx @@ -7,7 +7,6 @@ import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; -import { HostAuthenticationsRequestOptions } from '../../../../../../common/search_strategy/security_solution/hosts/authentications'; import * as buildQuery from './dsl/query.dsl'; import { authentications } from '.'; import { @@ -15,6 +14,7 @@ import { mockSearchStrategyResponse, formattedSearchStrategyResponse, } from './__mocks__'; +import { UserAuthenticationsRequestOptions } from '../../../../../../common/search_strategy'; describe('authentications search strategy', () => { const buildAuthenticationQuery = jest.spyOn(buildQuery, 'buildQuery'); @@ -36,7 +36,7 @@ describe('authentications search strategy', () => { ...mockOptions.pagination, querySize: DEFAULT_MAX_TABLE_QUERY_SIZE, }, - } as HostAuthenticationsRequestOptions; + } as UserAuthenticationsRequestOptions; expect(() => { authentications.buildDsl(overSizeOptions); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.tsx similarity index 78% rename from x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.tsx rename to x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.tsx index e32d3592d3417..11400166e3344 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/authentications/index.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/index.tsx @@ -11,12 +11,12 @@ import type { IEsSearchResponse } from '../../../../../../../../../src/plugins/d import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants'; import { - HostsQueries, - AuthenticationsEdges, - HostAuthenticationsRequestOptions, - HostAuthenticationsStrategyResponse, AuthenticationHit, -} from '../../../../../../common/search_strategy/security_solution/hosts'; + AuthenticationsEdges, + UserAuthenticationsRequestOptions, + UserAuthenticationsStrategyResponse, +} from '../../../../../../common/search_strategy'; +import { UsersQueries } from '../../../../../../common/search_strategy/security_solution/users'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { SecuritySolutionFactory } from '../../types'; @@ -32,8 +32,8 @@ import { getHitsEntities, } from './helpers'; -export const authentications: SecuritySolutionFactory = { - buildDsl: (options: HostAuthenticationsRequestOptions) => { +export const authentications: SecuritySolutionFactory = { + buildDsl: (options: UserAuthenticationsRequestOptions) => { if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) { throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`); } @@ -41,11 +41,11 @@ export const authentications: SecuritySolutionFactory - ): Promise => { + ): Promise => { const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; - const totalCount = getOr(0, 'aggregations.user_count.value', response.rawResponse); + const totalCount = getOr(0, 'aggregations.stack_by_count.value', response.rawResponse); const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; const hits: AuthenticationHit[] = getHits(response); @@ -72,8 +72,8 @@ export const authentications: SecuritySolutionFactory = { - buildDsl: (options: HostAuthenticationsRequestOptions) => { +export const authenticationsEntities: SecuritySolutionFactory = { + buildDsl: (options: UserAuthenticationsRequestOptions) => { if (options.pagination && options.pagination.querySize >= DEFAULT_MAX_TABLE_QUERY_SIZE) { throw new Error(`No query size above ${DEFAULT_MAX_TABLE_QUERY_SIZE}`); } @@ -81,11 +81,11 @@ export const authenticationsEntities: SecuritySolutionFactory - ): Promise => { + ): Promise => { const { activePage, cursorStart, fakePossibleCount, querySize } = options.pagination; - const totalCount = getOr(0, 'aggregations.user_count.value', response.rawResponse); + const totalCount = getOr(0, 'aggregations.stack_by_count.value', response.rawResponse); const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount; const hits: AuthenticationHit[] = getHitsEntities(response); diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/index.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/index.ts index dce2195867358..0b13319cc11c7 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/index.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/index.ts @@ -10,6 +10,7 @@ import { UsersQueries } from '../../../../../common/search_strategy/security_sol import { SecuritySolutionFactory } from '../types'; import { allUsers } from './all'; +import { authentications, authenticationsEntities } from './authentications'; import { userDetails } from './details'; import { totalUsersKpi } from './kpi/total_users'; @@ -17,4 +18,6 @@ export const usersFactory: Record, + SanitizedRule, 'createdBy' | 'updatedBy' | 'createdAt' | 'updatedAt' > & { createdBy: string | null; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/constant.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/constant.ts index 6f10f25934afc..a04c8aed403d9 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/constant.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/constant.ts @@ -13,4 +13,6 @@ export const REPOSITORY_EDIT = getRepository({ name: REPOSITORY_NAME }); export const POLICY_NAME = 'my-test-policy'; +export const SNAPSHOT_NAME = 'my-test-snapshot'; + export const POLICY_EDIT = getPolicy({ name: POLICY_NAME, retention: { minCount: 1 } }); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/home.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/home.helpers.ts index 45b31a19693b7..9970b0100ceb8 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/home.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/home.helpers.ts @@ -14,6 +14,7 @@ import { AsyncTestBedConfig, delay, } from '@kbn/test-jest-helpers'; +import { HttpSetup } from 'src/core/public'; import { SnapshotRestoreHome } from '../../../public/application/sections/home/home'; import { BASE_PATH } from '../../../public/application/constants'; import { WithAppDependencies } from './setup_environment'; @@ -26,8 +27,6 @@ const testBedConfig: AsyncTestBedConfig = { doMountAsync: true, }; -const initTestBed = registerTestBed(WithAppDependencies(SnapshotRestoreHome), testBedConfig); - export interface HomeTestBed extends TestBed { actions: { clickReloadButton: () => void; @@ -40,7 +39,11 @@ export interface HomeTestBed extends TestBed { }; } -export const setup = async (): Promise => { +export const setup = async (httpSetup: HttpSetup): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(SnapshotRestoreHome, httpSetup), + testBedConfig + ); const testBed = await initTestBed(); const REPOSITORY_TABLE = 'repositoryTable'; const SNAPSHOT_TABLE = 'snapshotTable'; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts index 662c50a98bfe8..3c14c444d4664 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/http_requests.ts @@ -5,117 +5,119 @@ * 2.0. */ -import sinon, { SinonFakeServer } from 'sinon'; +import { httpServiceMock } from '../../../../../../src/core/public/mocks'; import { API_BASE_PATH } from '../../../common'; +type HttpMethod = 'GET' | 'PUT' | 'POST'; type HttpResponse = Record | any[]; -const mockResponse = (defaultResponse: HttpResponse, response?: HttpResponse) => [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify({ ...defaultResponse, ...response }), -]; +export interface ResponseError { + statusCode: number; + message: string | Error; +} // Register helpers to mock HTTP Requests -const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { - const setLoadRepositoriesResponse = (response: HttpResponse = {}) => { - const defaultResponse = { repositories: [] }; - - server.respondWith( - 'GET', - `${API_BASE_PATH}repositories`, - mockResponse(defaultResponse, response) - ); +const registerHttpRequestMockHelpers = ( + httpSetup: ReturnType +) => { + const mockResponses = new Map>>( + ['GET', 'PUT', 'POST'].map( + (method) => [method, new Map()] as [HttpMethod, Map>] + ) + ); + + const mockMethodImplementation = (method: HttpMethod, path: string) => + mockResponses.get(method)?.get(path) ?? Promise.resolve({}); + + httpSetup.get.mockImplementation((path) => + mockMethodImplementation('GET', path as unknown as string) + ); + httpSetup.post.mockImplementation((path) => + mockMethodImplementation('POST', path as unknown as string) + ); + httpSetup.put.mockImplementation((path) => + mockMethodImplementation('PUT', path as unknown as string) + ); + + const mockResponse = (method: HttpMethod, path: string, response?: unknown, error?: unknown) => { + const defuse = (promise: Promise) => { + promise.catch(() => {}); + return promise; + }; + + return mockResponses + .get(method)! + .set(path, error ? defuse(Promise.reject({ body: error })) : Promise.resolve(response)); }; - const setLoadRepositoryTypesResponse = (response: HttpResponse = []) => { - server.respondWith('GET', `${API_BASE_PATH}repository_types`, JSON.stringify(response)); - }; + const setLoadRepositoriesResponse = ( + response: HttpResponse = { repositories: [] }, + error?: ResponseError + ) => mockResponse('GET', `${API_BASE_PATH}repositories`, response, error); - const setGetRepositoryResponse = (response?: HttpResponse, delay = 0) => { - const defaultResponse = {}; - - server.respondWith( - 'GET', - /api\/snapshot_restore\/repositories\/.+/, - mockResponse(defaultResponse, response) - ); - }; + const setLoadRepositoryTypesResponse = (response: HttpResponse = [], error?: ResponseError) => + mockResponse('GET', `${API_BASE_PATH}repository_types`, response, error); - const setSaveRepositoryResponse = (response?: HttpResponse, error?: any) => { - const status = error ? error.status || 400 : 200; - const body = error ? JSON.stringify(error.body) : JSON.stringify(response); + const setGetRepositoryResponse = ( + repositoryName: string, + response?: HttpResponse, + error?: ResponseError + ) => mockResponse('GET', `${API_BASE_PATH}repositories/${repositoryName}`, response, error); - server.respondWith('PUT', `${API_BASE_PATH}repositories`, [ - status, - { 'Content-Type': 'application/json' }, - body, - ]); - }; + const setSaveRepositoryResponse = (response?: HttpResponse, error?: ResponseError) => + mockResponse('PUT', `${API_BASE_PATH}repositories`, response, error); - const setLoadSnapshotsResponse = (response: HttpResponse = {}) => { + const setLoadSnapshotsResponse = (response?: HttpResponse, error?: ResponseError) => { const defaultResponse = { errors: {}, snapshots: [], repositories: [], total: 0 }; - - server.respondWith('GET', `${API_BASE_PATH}snapshots`, mockResponse(defaultResponse, response)); + return mockResponse('GET', `${API_BASE_PATH}snapshots`, response ?? defaultResponse, error); }; - const setGetSnapshotResponse = (response?: HttpResponse) => { - const defaultResponse = {}; - - server.respondWith( + const setGetSnapshotResponse = ( + repositoryName: string, + snapshotName: string, + response?: HttpResponse, + error?: ResponseError + ) => + mockResponse( 'GET', - /\/api\/snapshot_restore\/snapshots\/.+/, - mockResponse(defaultResponse, response) + `${API_BASE_PATH}snapshots/${repositoryName}/${snapshotName}`, + response, + error ); - }; - - const setLoadIndicesResponse = (response: HttpResponse = {}) => { - const defaultResponse = { indices: [] }; - server.respondWith( - 'GET', - `${API_BASE_PATH}policies/indices`, - mockResponse(defaultResponse, response) + const setLoadIndicesResponse = ( + response: HttpResponse = { indices: [] }, + error?: ResponseError + ) => mockResponse('GET', `${API_BASE_PATH}policies/indices`, response, error); + + const setAddPolicyResponse = (response?: HttpResponse, error?: ResponseError) => + mockResponse('POST', `${API_BASE_PATH}policies`, response, error); + + const setCleanupRepositoryResponse = ( + repositoryName: string, + response?: HttpResponse, + error?: ResponseError + ) => + mockResponse('POST', `${API_BASE_PATH}repositories/${repositoryName}/cleanup`, response, error); + + const setGetPolicyResponse = ( + policyName: string, + response?: HttpResponse, + error?: ResponseError + ) => mockResponse('GET', `${API_BASE_PATH}policy/${policyName}`, response, error); + + const setRestoreSnapshotResponse = ( + repositoryName: string, + snapshotId: string, + response?: HttpResponse, + error?: ResponseError + ) => + mockResponse( + 'POST', + `${API_BASE_PATH}restore/${repositoryName}/${snapshotId}`, + response, + error ); - }; - - const setAddPolicyResponse = (response?: HttpResponse, error?: any) => { - const status = error ? error.status || 400 : 200; - const body = error ? JSON.stringify(error.body) : JSON.stringify(response); - - server.respondWith('POST', `${API_BASE_PATH}policies`, [ - status, - { 'Content-Type': 'application/json' }, - body, - ]); - }; - - const setCleanupRepositoryResponse = (response?: HttpResponse, error?: any) => { - const status = error ? error.status || 503 : 200; - const body = error ? JSON.stringify(error) : JSON.stringify(response); - - server.respondWith('POST', `${API_BASE_PATH}repositories/:name/cleanup`, [ - status, - { 'Content-Type': 'application/json' }, - body, - ]); - }; - - const setGetPolicyResponse = (response?: HttpResponse) => { - server.respondWith('GET', `${API_BASE_PATH}policy/:name`, [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(response), - ]); - }; - - const setRestoreSnapshotResponse = (response?: HttpResponse) => { - server.respondWith('POST', `${API_BASE_PATH}restore/:repository/:snapshot`, [ - 200, - { 'Content-Type': 'application/json' }, - JSON.stringify(response), - ]); - }; return { setLoadRepositoriesResponse, @@ -133,18 +135,11 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { }; export const init = () => { - const server = sinon.fakeServer.create(); - server.respondImmediately = true; - - // Define default response for unhandled requests. - // We make requests to APIs which don't impact the component under test, e.g. UI metric telemetry, - // and we can mock them all with a 200 instead of mocking each one individually. - server.respondWith([200, {}, 'DefaultResponse']); - - const httpRequestsMockHelpers = registerHttpRequestMockHelpers(server); + const httpSetup = httpServiceMock.createSetupContract(); + const httpRequestsMockHelpers = registerHttpRequestMockHelpers(httpSetup); return { - server, + httpSetup, httpRequestsMockHelpers, }; }; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_add.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_add.helpers.ts index d921b96781d0c..a5cf9aceff8c4 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_add.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_add.helpers.ts @@ -6,6 +6,7 @@ */ import { registerTestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; +import { HttpSetup } from 'src/core/public'; import { PolicyAdd } from '../../../public/application/sections/policy_add'; import { formSetup, PolicyFormTestSubjects } from './policy_form.helpers'; import { WithAppDependencies } from './setup_environment'; @@ -18,9 +19,11 @@ const testBedConfig: AsyncTestBedConfig = { doMountAsync: true, }; -const initTestBed = registerTestBed( - WithAppDependencies(PolicyAdd), - testBedConfig -); +export const setup = async (httpSetup: HttpSetup) => { + const initTestBed = registerTestBed( + WithAppDependencies(PolicyAdd, httpSetup), + testBedConfig + ); -export const setup = formSetup.bind(null, initTestBed); + return formSetup(initTestBed); +}; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_edit.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_edit.helpers.ts index 461351e744125..3334dc5337a4d 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_edit.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/policy_edit.helpers.ts @@ -6,6 +6,7 @@ */ import { registerTestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; +import { HttpSetup } from 'src/core/public'; import { PolicyEdit } from '../../../public/application/sections/policy_edit'; import { WithAppDependencies } from './setup_environment'; import { POLICY_NAME } from './constant'; @@ -19,9 +20,11 @@ const testBedConfig: AsyncTestBedConfig = { doMountAsync: true, }; -const initTestBed = registerTestBed( - WithAppDependencies(PolicyEdit), - testBedConfig -); +export const setup = async (httpSetup: HttpSetup) => { + const initTestBed = registerTestBed( + WithAppDependencies(PolicyEdit, httpSetup), + testBedConfig + ); -export const setup = formSetup.bind(null, initTestBed); + return formSetup(initTestBed); +}; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_add.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_add.helpers.ts index c6460078482bf..c4a5fc4b7be93 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_add.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_add.helpers.ts @@ -6,14 +6,11 @@ */ import { registerTestBed, TestBed } from '@kbn/test-jest-helpers'; +import { HttpSetup } from 'src/core/public'; import { RepositoryType } from '../../../common/types'; import { RepositoryAdd } from '../../../public/application/sections/repository_add'; import { WithAppDependencies } from './setup_environment'; -const initTestBed = registerTestBed(WithAppDependencies(RepositoryAdd), { - doMountAsync: true, -}); - export interface RepositoryAddTestBed extends TestBed { actions: { clickNextButton: () => void; @@ -23,7 +20,13 @@ export interface RepositoryAddTestBed extends TestBed }; } -export const setup = async (): Promise => { +export const setup = async (httpSetup: HttpSetup): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(RepositoryAdd, httpSetup), + { + doMountAsync: true, + } + ); const testBed = await initTestBed(); // User actions diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_edit.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_edit.helpers.ts index 275c216d70664..3e8bbf95d5ea9 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_edit.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/repository_edit.helpers.ts @@ -6,6 +6,7 @@ */ import { registerTestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; +import { HttpSetup } from 'src/core/public'; import { RepositoryEdit } from '../../../public/application/sections/repository_edit'; import { WithAppDependencies } from './setup_environment'; import { REPOSITORY_NAME } from './constant'; @@ -18,10 +19,14 @@ const testBedConfig: AsyncTestBedConfig = { doMountAsync: true, }; -export const setup = registerTestBed( - WithAppDependencies(RepositoryEdit), - testBedConfig -); +export const setup = async (httpSetup: HttpSetup) => { + const initTestBed = registerTestBed( + WithAppDependencies(RepositoryEdit, httpSetup), + testBedConfig + ); + + return await initTestBed(); +}; export type RepositoryEditTestSubjects = TestSubjects | ThreeLevelDepth | NonVisibleTestSubjects; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts index 86c93a6811bd4..fe5a82f421def 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/restore_snapshot.helpers.ts @@ -6,23 +6,20 @@ */ import { act } from 'react-dom/test-utils'; +import { HttpSetup } from 'src/core/public'; import { registerTestBed, TestBed, AsyncTestBedConfig } from '@kbn/test-jest-helpers'; import { RestoreSnapshot } from '../../../public/application/sections/restore_snapshot'; import { WithAppDependencies } from './setup_environment'; +import { REPOSITORY_NAME, SNAPSHOT_NAME } from '../helpers/constant'; const testBedConfig: AsyncTestBedConfig = { memoryRouter: { - initialEntries: ['/add_policy'], - componentRoutePath: '/add_policy', + initialEntries: [`/restore/${REPOSITORY_NAME}/${SNAPSHOT_NAME}`], + componentRoutePath: '/restore/:repositoryName?/:snapshotId*', }, doMountAsync: true, }; -const initTestBed = registerTestBed( - WithAppDependencies(RestoreSnapshot), - testBedConfig -); - const setupActions = (testBed: TestBed) => { const { find, component, form, exists } = testBed; @@ -84,7 +81,12 @@ export type RestoreSnapshotTestBed = TestBed & { actions: Actions; }; -export const setup = async (): Promise => { +export const setup = async (httpSetup: HttpSetup): Promise => { + const initTestBed = registerTestBed( + WithAppDependencies(RestoreSnapshot, httpSetup), + testBedConfig + ); + const testBed = await initTestBed(); return { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/setup_environment.tsx index 66ba21b136816..0c961d5e151bc 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/setup_environment.tsx @@ -6,11 +6,10 @@ */ import React from 'react'; -import axios from 'axios'; -import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import { i18n } from '@kbn/i18n'; import { LocationDescriptorObject } from 'history'; +import { HttpSetup } from 'src/core/public'; import { coreMock, scopedHistoryMock } from 'src/core/public/mocks'; import { setUiMetricService, httpService } from '../../../public/application/services/http'; import { @@ -22,8 +21,6 @@ import { textService } from '../../../public/application/services/text'; import { init as initHttpRequests } from './http_requests'; import { UiMetricService } from '../../../public/application/services'; -const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); - const history = scopedHistoryMock.create(); history.createHref.mockImplementation((location: LocationDescriptorObject) => { return `${location.pathname}?${location.search}`; @@ -48,18 +45,11 @@ const appDependencies = { }; export const setupEnvironment = () => { - // @ts-ignore - httpService.setup(mockHttpClient); breadcrumbService.setup(() => undefined); textService.setup(i18n); docTitleService.setup(() => undefined); - const { server, httpRequestsMockHelpers } = initHttpRequests(); - - return { - server, - httpRequestsMockHelpers, - }; + return initHttpRequests(); }; /** @@ -70,9 +60,16 @@ export const setupEnvironment = () => { this.terminate = () => {}; }; -export const WithAppDependencies = (Comp: any) => (props: any) => - ( +export const WithAppDependencies = (Comp: any, httpSetup?: HttpSetup) => (props: any) => { + // We need to optionally setup the httpService since some cit helpers (such as snapshot_list.helpers) + // use jest mocks to stub the fetch hooks instead of mocking api responses. + if (httpSetup) { + httpService.setup(httpSetup); + } + + return ( ); +}; diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/snapshot_list.helpers.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/snapshot_list.helpers.ts index 261976623144b..d81db28c5353a 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/snapshot_list.helpers.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/helpers/snapshot_list.helpers.ts @@ -35,6 +35,7 @@ const searchErrorSelector = 'snapshotListSearchError'; export const setup = async (query?: string): Promise => { const testBed = await initTestBed(query); + const { form, component, find, exists } = testBed; const setSearchText = async (value: string, advanceTime = true) => { diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts index a99a6fdb81167..09a726a6b9abe 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/home.test.ts @@ -41,16 +41,12 @@ const removeWhiteSpaceOnArrayValues = (array: any[]) => }); describe('', () => { - const { server, httpRequestsMockHelpers } = setupEnvironment(); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); let testBed: HomeTestBed; - afterAll(() => { - server.restore(); - }); - describe('on component mount', () => { beforeEach(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); test('should set the correct app title', () => { @@ -79,7 +75,7 @@ describe('', () => { describe('tabs', () => { beforeEach(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); @@ -132,7 +128,7 @@ describe('', () => { }); test('should display an empty prompt', async () => { - const { component, exists } = await setup(); + const { component, exists } = await setup(httpSetup); await act(async () => { await nextTick(); @@ -164,7 +160,7 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoriesResponse({ repositories }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); @@ -208,7 +204,6 @@ describe('', () => { test('should have a button to reload the repositories', async () => { const { component, exists, actions } = testBed; - const totalRequests = server.requests.length; expect(exists('reloadButton')).toBe(true); await act(async () => { @@ -217,9 +212,9 @@ describe('', () => { component.update(); }); - expect(server.requests.length).toBe(totalRequests + 1); - expect(server.requests[server.requests.length - 1].url).toBe( - `${API_BASE_PATH}repositories` + expect(httpSetup.get).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.anything() ); }); @@ -273,10 +268,10 @@ describe('', () => { component.update(); }); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(latestRequest.method).toBe('DELETE'); - expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}`); + expect(httpSetup.delete).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories/${repo1.name}`, + expect.anything() + ); }); }); @@ -304,23 +299,20 @@ describe('', () => { }); test('should show a loading state while fetching the repository', async () => { - server.respondImmediately = false; const { find, exists, actions } = testBed; // By providing undefined, the "loading section" will be displayed - httpRequestsMockHelpers.setGetRepositoryResponse(undefined); + httpRequestsMockHelpers.setGetRepositoryResponse(repo1.name, undefined); await actions.clickRepositoryAt(0); expect(exists('repositoryDetail.sectionLoading')).toBe(true); expect(find('repositoryDetail.sectionLoading').text()).toEqual('Loading repository…'); - - server.respondImmediately = true; }); describe('when the repository has been fetched', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetRepositoryResponse({ + httpRequestsMockHelpers.setGetRepositoryResponse(repo1.name, { repository: { name: 'my-repo', type: 'fs', @@ -357,15 +349,15 @@ describe('', () => { component.update(); }); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(latestRequest.method).toBe('GET'); - expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/verify`); + expect(httpSetup.get).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories/${repo1.name}/verify`, + expect.anything() + ); }); describe('clean repository', () => { test('shows results when request succeeds', async () => { - httpRequestsMockHelpers.setCleanupRepositoryResponse({ + httpRequestsMockHelpers.setCleanupRepositoryResponse(repo1.name, { cleanup: { cleaned: true, response: { @@ -383,16 +375,17 @@ describe('', () => { }); component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - expect(latestRequest.method).toBe('POST'); - expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/cleanup`); + expect(httpSetup.post).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories/${repo1.name}/cleanup`, + expect.anything() + ); expect(exists('repositoryDetail.cleanupCodeBlock')).toBe(true); expect(exists('repositoryDetail.cleanupError')).toBe(false); }); test('shows error when success fails', async () => { - httpRequestsMockHelpers.setCleanupRepositoryResponse({ + httpRequestsMockHelpers.setCleanupRepositoryResponse(repo1.name, { cleanup: { cleaned: false, error: { @@ -408,9 +401,10 @@ describe('', () => { }); component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - expect(latestRequest.method).toBe('POST'); - expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/cleanup`); + expect(httpSetup.post).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories/${repo1.name}/cleanup`, + expect.anything() + ); expect(exists('repositoryDetail.cleanupCodeBlock')).toBe(false); expect(exists('repositoryDetail.cleanupError')).toBe(true); @@ -420,7 +414,7 @@ describe('', () => { describe('when the repository has been fetched (and has snapshots)', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetRepositoryResponse({ + httpRequestsMockHelpers.setGetRepositoryResponse(repo1.name, { repository: { name: 'my-repo', type: 'fs', @@ -448,7 +442,7 @@ describe('', () => { }); beforeEach(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { testBed.actions.selectTab('snapshots'); @@ -478,7 +472,7 @@ describe('', () => { total: 0, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { testBed.actions.selectTab('snapshots'); @@ -517,7 +511,7 @@ describe('', () => { total: 2, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { testBed.actions.selectTab('snapshots'); @@ -561,7 +555,7 @@ describe('', () => { }, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { testBed.actions.selectTab('snapshots'); @@ -589,7 +583,7 @@ describe('', () => { }, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { testBed.actions.selectTab('snapshots'); @@ -625,7 +619,6 @@ describe('', () => { test('should have a button to reload the snapshots', async () => { const { component, exists, actions } = testBed; - const totalRequests = server.requests.length; expect(exists('reloadButton')).toBe(true); await act(async () => { @@ -634,13 +627,19 @@ describe('', () => { component.update(); }); - expect(server.requests.length).toBe(totalRequests + 1); - expect(server.requests[server.requests.length - 1].url).toBe(`${API_BASE_PATH}snapshots`); + expect(httpSetup.get).toHaveBeenLastCalledWith( + `${API_BASE_PATH}snapshots`, + expect.anything() + ); }); describe('detail panel', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(snapshot1); + httpRequestsMockHelpers.setGetSnapshotResponse( + snapshot1.repository, + snapshot1.snapshot, + snapshot1 + ); }); test('should show the detail when clicking on a snapshot', async () => { @@ -656,17 +655,18 @@ describe('', () => { // that makes the component crash. I tried a few things with no luck so, as this // is a low impact test, I prefer to skip it and move on. test.skip('should show a loading while fetching the snapshot', async () => { - server.respondImmediately = false; const { find, exists, actions } = testBed; // By providing undefined, the "loading section" will be displayed - httpRequestsMockHelpers.setGetSnapshotResponse(undefined); + httpRequestsMockHelpers.setGetSnapshotResponse( + snapshot1.repository, + snapshot1.snapshot, + undefined + ); await actions.clickSnapshotAt(0); expect(exists('snapshotDetail.sectionLoading')).toBe(true); expect(find('snapshotDetail.sectionLoading').text()).toEqual('Loading snapshot…'); - - server.respondImmediately = true; }); describe('on mount', () => { @@ -757,7 +757,11 @@ describe('', () => { const setSnapshotStateAndUpdateDetail = async (state: string) => { const updatedSnapshot = { ...snapshot1, state }; - httpRequestsMockHelpers.setGetSnapshotResponse(updatedSnapshot); + httpRequestsMockHelpers.setGetSnapshotResponse( + itemIndexToClickOn === 0 ? snapshot1.repository : snapshot2.repository, + itemIndexToClickOn === 0 ? snapshot1.snapshot : snapshot2.snapshot, + updatedSnapshot + ); await actions.clickSnapshotAt(itemIndexToClickOn); // click another snapshot to trigger the HTTP call }; @@ -787,9 +791,12 @@ describe('', () => { }; // Call sequentially each state and verify that the message is ok - return Object.entries(mapStateToMessage).reduce((promise, [state, message]) => { - return promise.then(async () => expectMessageForSnapshotState(state, message)); - }, Promise.resolve()); + return Object.entries(mapStateToMessage).reduce( + async (promise, [state, message]) => { + return promise.then(async () => expectMessageForSnapshotState(state, message)); + }, + Promise.resolve() + ); }); }); @@ -805,8 +812,12 @@ describe('', () => { test('should display a message when snapshot in progress ', async () => { const { find, actions } = testBed; - const updatedSnapshot = { ...snapshot1, state: 'IN_PROGRESS' }; - httpRequestsMockHelpers.setGetSnapshotResponse(updatedSnapshot); + const updatedSnapshot = { ...snapshot2, state: 'IN_PROGRESS' }; + httpRequestsMockHelpers.setGetSnapshotResponse( + snapshot2.repository, + snapshot2.snapshot, + updatedSnapshot + ); await actions.clickSnapshotAt(1); // click another snapshot to trigger the HTTP call actions.selectSnapshotDetailTab('failedIndices'); @@ -825,7 +836,11 @@ describe('', () => { beforeEach(async () => { const updatedSnapshot = { ...snapshot1, indexFailures }; - httpRequestsMockHelpers.setGetSnapshotResponse(updatedSnapshot); + httpRequestsMockHelpers.setGetSnapshotResponse( + updatedSnapshot.repository, + updatedSnapshot.snapshot, + updatedSnapshot + ); await testBed.actions.clickSnapshotAt(0); testBed.actions.selectSnapshotDetailTab('failedIndices'); }); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts index 1e8546bef50e5..0950eda8fc630 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_add.test.ts @@ -12,6 +12,7 @@ import { ReactElement } from 'react'; import { act } from 'react-dom/test-utils'; import * as fixtures from '../../test/fixtures'; +import { API_BASE_PATH } from '../../common'; import { PolicyFormTestBed } from './helpers/policy_form.helpers'; import { DEFAULT_POLICY_SCHEDULE } from '../../public/application/constants'; @@ -36,12 +37,7 @@ const repository = fixtures.getRepository({ name: `a${getRandomString()}`, type: describe('', () => { let testBed: PolicyFormTestBed; - - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); describe('on component mount', () => { beforeEach(async () => { @@ -51,7 +47,7 @@ describe('', () => { dataStreams: ['my_data_stream', 'my_other_data_stream'], }); - testBed = await setup(); + testBed = await setup(httpSetup); await nextTick(); testBed.component.update(); }); @@ -241,36 +237,37 @@ describe('', () => { await nextTick(); }); - const latestRequest = server.requests[server.requests.length - 1]; - - const expected = { - config: {}, - isManagedPolicy: false, - name: POLICY_NAME, - repository: repository.name, - retention: { - expireAfterUnit: 'd', // default - expireAfterValue: Number(EXPIRE_AFTER_VALUE), - maxCount: Number(MAX_COUNT), - minCount: Number(MIN_COUNT), - }, - schedule: DEFAULT_POLICY_SCHEDULE, - snapshotName: SNAPSHOT_NAME, - }; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + expect(httpSetup.post).toHaveBeenLastCalledWith( + `${API_BASE_PATH}policies`, + expect.objectContaining({ + body: JSON.stringify({ + name: POLICY_NAME, + snapshotName: SNAPSHOT_NAME, + schedule: DEFAULT_POLICY_SCHEDULE, + repository: repository.name, + config: {}, + retention: { + expireAfterValue: Number(EXPIRE_AFTER_VALUE), + expireAfterUnit: 'd', // default + maxCount: Number(MAX_COUNT), + minCount: Number(MIN_COUNT), + }, + isManagedPolicy: false, + }), + }) + ); }); it('should surface the API errors from the put HTTP request', async () => { const { component, actions, find, exists } = testBed; const error = { - status: 409, + statusCode: 409, error: 'Conflict', message: `There is already a policy with name '${POLICY_NAME}'`, }; - httpRequestsMockHelpers.setAddPolicyResponse(undefined, { body: error }); + httpRequestsMockHelpers.setAddPolicyResponse(undefined, error); await act(async () => { actions.clickSubmitButton(); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts index 7d5d605b216bc..117d6f0e0e223 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/policy_edit.test.ts @@ -8,6 +8,7 @@ import { act } from 'react-dom/test-utils'; import { setupEnvironment, pageHelpers, nextTick } from './helpers'; +import { API_BASE_PATH } from '../../common'; import { PolicyForm } from '../../public/application/components/policy_form'; import { PolicyFormTestBed } from './helpers/policy_form.helpers'; import { POLICY_EDIT } from './helpers/constant'; @@ -22,15 +23,11 @@ const EXPIRE_AFTER_UNIT = TIME_UNITS.MINUTE; describe('', () => { let testBed: PolicyFormTestBed; let testBedPolicyAdd: PolicyFormTestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); describe('on component mount', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetPolicyResponse({ policy: POLICY_EDIT }); + httpRequestsMockHelpers.setGetPolicyResponse(POLICY_EDIT.name, { policy: POLICY_EDIT }); httpRequestsMockHelpers.setLoadIndicesResponse({ indices: ['my_index'], dataStreams: ['my_data_stream'], @@ -39,7 +36,7 @@ describe('', () => { repositories: [{ name: POLICY_EDIT.repository }], }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); @@ -55,7 +52,7 @@ describe('', () => { describe('policy with pre-existing repository that was deleted', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetPolicyResponse({ policy: POLICY_EDIT }); + httpRequestsMockHelpers.setGetPolicyResponse(POLICY_EDIT.name, { policy: POLICY_EDIT }); httpRequestsMockHelpers.setLoadIndicesResponse({ indices: ['my_index'], dataStreams: ['my_data_stream'], @@ -64,7 +61,7 @@ describe('', () => { repositories: [{ name: 'this-is-a-new-repository' }], }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); @@ -97,7 +94,7 @@ describe('', () => { * the same form component is indeed shared between the 2 app sections. */ test('should use the same Form component as the "" section', async () => { - testBedPolicyAdd = await setupPolicyAdd(); + testBedPolicyAdd = await setupPolicyAdd(httpSetup); await act(async () => { await nextTick(); @@ -143,27 +140,28 @@ describe('', () => { await nextTick(); }); - const latestRequest = server.requests[server.requests.length - 1]; - const { name, isManagedPolicy, schedule, repository, retention } = POLICY_EDIT; - const expected = { - name, - isManagedPolicy, - schedule, - repository, - config: { - ignoreUnavailable: true, - }, - retention: { - ...retention, - expireAfterValue: Number(EXPIRE_AFTER_VALUE), - expireAfterUnit: EXPIRE_AFTER_UNIT, - }, - snapshotName: editedSnapshotName, - }; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}policies/${name}`, + expect.objectContaining({ + body: JSON.stringify({ + name, + snapshotName: editedSnapshotName, + schedule, + repository, + config: { + ignoreUnavailable: true, + }, + retention: { + ...retention, + expireAfterUnit: EXPIRE_AFTER_UNIT, + expireAfterValue: Number(EXPIRE_AFTER_VALUE), + }, + isManagedPolicy, + }), + }) + ); }); it('should provide a default time unit value for retention', async () => { @@ -184,25 +182,27 @@ describe('', () => { await nextTick(); }); - const latestRequest = server.requests[server.requests.length - 1]; - const { name, isManagedPolicy, schedule, repository, retention, config, snapshotName } = POLICY_EDIT; - const expected = { - name, - isManagedPolicy, - schedule, - repository, - config, - snapshotName, - retention: { - ...retention, - expireAfterValue: Number(EXPIRE_AFTER_VALUE), - expireAfterUnit: TIME_UNITS.DAY, // default value - }, - }; - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}policies/${name}`, + expect.objectContaining({ + body: JSON.stringify({ + name, + snapshotName, + schedule, + repository, + config, + retention: { + ...retention, + expireAfterUnit: TIME_UNITS.DAY, // default value + expireAfterValue: Number(EXPIRE_AFTER_VALUE), + }, + isManagedPolicy, + }), + }) + ); }); }); }); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts index 85d438fc5f3ae..3a34926272e07 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_add.test.ts @@ -8,6 +8,7 @@ import { act } from 'react-dom/test-utils'; import { INVALID_NAME_CHARS } from '../../public/application/services/validation/validate_repository'; +import { API_BASE_PATH } from '../../common'; import { getRepository } from '../../test/fixtures'; import { RepositoryType } from '../../common/types'; import { setupEnvironment, pageHelpers, nextTick, delay } from './helpers'; @@ -18,18 +19,13 @@ const repositoryTypes = ['fs', 'url', 'source', 'azure', 'gcs', 's3', 'hdfs']; describe('', () => { let testBed: RepositoryAddTestBed; - - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); describe('on component mount', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse(repositoryTypes); - testBed = await setup(); + testBed = await setup(httpSetup); }); test('should set the correct page title', () => { @@ -65,7 +61,7 @@ describe('', () => { describe('when no repository types are not found', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse([]); - testBed = await setup(); + testBed = await setup(httpSetup); await nextTick(); testBed.component.update(); }); @@ -81,7 +77,7 @@ describe('', () => { describe('when repository types are found', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse(repositoryTypes); - testBed = await setup(); + testBed = await setup(httpSetup); await nextTick(); testBed.component.update(); }); @@ -104,7 +100,7 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse(repositoryTypes); - testBed = await setup(); + testBed = await setup(httpSetup); await nextTick(); testBed.component.update(); }); @@ -205,7 +201,7 @@ describe('', () => { beforeEach(async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse(repositoryTypes); - testBed = await setup(); + testBed = await setup(httpSetup); }); describe('not source only', () => { @@ -231,17 +227,23 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: fsRepository.name, - type: fsRepository.type, - settings: { - ...fsRepository.settings, - compress: true, - readonly: true, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: fsRepository.name, + type: fsRepository.type, + settings: { + location: fsRepository.settings.location, + compress: true, + chunkSize: fsRepository.settings.chunkSize, + maxSnapshotBytesPerSec: fsRepository.settings.maxSnapshotBytesPerSec, + maxRestoreBytesPerSec: fsRepository.settings.maxRestoreBytesPerSec, + readonly: true, + }, + }), + }) + ); }); test('should send the correct payload for Azure repository', async () => { @@ -283,17 +285,25 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: azureRepository.name, - type: azureRepository.type, - settings: { - ...azureRepository.settings, - compress: false, - readonly: true, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: azureRepository.name, + type: azureRepository.type, + settings: { + client: azureRepository.settings.client, + container: azureRepository.settings.container, + basePath: azureRepository.settings.basePath, + compress: false, + chunkSize: azureRepository.settings.chunkSize, + maxSnapshotBytesPerSec: azureRepository.settings.maxSnapshotBytesPerSec, + maxRestoreBytesPerSec: azureRepository.settings.maxRestoreBytesPerSec, + readonly: true, + }, + }), + }) + ); }); test('should send the correct payload for GCS repository', async () => { @@ -332,17 +342,25 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: gcsRepository.name, - type: gcsRepository.type, - settings: { - ...gcsRepository.settings, - compress: false, - readonly: true, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: gcsRepository.name, + type: gcsRepository.type, + settings: { + client: gcsRepository.settings.client, + bucket: gcsRepository.settings.bucket, + basePath: gcsRepository.settings.basePath, + compress: false, + chunkSize: gcsRepository.settings.chunkSize, + maxSnapshotBytesPerSec: gcsRepository.settings.maxSnapshotBytesPerSec, + maxRestoreBytesPerSec: gcsRepository.settings.maxRestoreBytesPerSec, + readonly: true, + }, + }), + }) + ); }); test('should send the correct payload for HDFS repository', async () => { @@ -379,18 +397,24 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: hdfsRepository.name, - type: hdfsRepository.type, - settings: { - ...hdfsRepository.settings, - uri: `hdfs://${hdfsRepository.settings.uri}`, - compress: false, - readonly: true, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: hdfsRepository.name, + type: hdfsRepository.type, + settings: { + uri: `hdfs://${hdfsRepository.settings.uri}`, + path: hdfsRepository.settings.path, + compress: false, + chunkSize: hdfsRepository.settings.chunkSize, + maxSnapshotBytesPerSec: hdfsRepository.settings.maxSnapshotBytesPerSec, + maxRestoreBytesPerSec: hdfsRepository.settings.maxRestoreBytesPerSec, + readonly: true, + }, + }), + }) + ); }); test('should send the correct payload for S3 repository', async () => { @@ -431,17 +455,26 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: s3Repository.name, - type: s3Repository.type, - settings: { - ...s3Repository.settings, - compress: false, - readonly: true, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: s3Repository.name, + type: s3Repository.type, + settings: { + bucket: s3Repository.settings.bucket, + client: s3Repository.settings.client, + basePath: s3Repository.settings.basePath, + bufferSize: s3Repository.settings.bufferSize, + compress: false, + chunkSize: s3Repository.settings.chunkSize, + maxSnapshotBytesPerSec: s3Repository.settings.maxSnapshotBytesPerSec, + maxRestoreBytesPerSec: s3Repository.settings.maxRestoreBytesPerSec, + readonly: true, + }, + }), + }) + ); }); test('should surface the API errors from the "save" HTTP request', async () => { @@ -457,12 +490,12 @@ describe('', () => { form.toggleEuiSwitch('compressToggle'); const error = { - status: 400, + statusCode: 400, error: 'Bad request', message: 'Repository payload is invalid', }; - httpRequestsMockHelpers.setSaveRepositoryResponse(undefined, { body: error }); + httpRequestsMockHelpers.setSaveRepositoryResponse(undefined, error); await act(async () => { actions.clickSubmitButton(); @@ -496,16 +529,19 @@ describe('', () => { component.update(); - const latestRequest = server.requests[server.requests.length - 1]; - - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual({ - name: fsRepository.name, - type: 'source', - settings: { - delegateType: fsRepository.type, - location: fsRepository.settings.location, - }, - }); + expect(httpSetup.put).toHaveBeenLastCalledWith( + `${API_BASE_PATH}repositories`, + expect.objectContaining({ + body: JSON.stringify({ + name: fsRepository.name, + type: 'source', + settings: { + delegateType: fsRepository.type, + location: fsRepository.settings.location, + }, + }), + }) + ); }); }); }); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts index 8adf1e988ff1e..102c0d13a012b 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/repository_edit.test.ts @@ -11,7 +11,7 @@ import { setupEnvironment, pageHelpers, nextTick, TestBed, getRandomString } fro import { RepositoryForm } from '../../public/application/components/repository_form'; import { RepositoryEditTestSubjects } from './helpers/repository_edit.helpers'; import { RepositoryAddTestSubjects } from './helpers/repository_add.helpers'; -import { REPOSITORY_EDIT } from './helpers/constant'; +import { REPOSITORY_EDIT, REPOSITORY_NAME } from './helpers/constant'; const { setup } = pageHelpers.repositoryEdit; const { setup: setupRepositoryAdd } = pageHelpers.repositoryAdd; @@ -19,19 +19,15 @@ const { setup: setupRepositoryAdd } = pageHelpers.repositoryAdd; describe('', () => { let testBed: TestBed; let testBedRepositoryAdd: TestBed; - const { server, httpRequestsMockHelpers } = setupEnvironment(); - - afterAll(() => { - server.restore(); - }); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); describe('on component mount', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetRepositoryResponse({ + httpRequestsMockHelpers.setGetRepositoryResponse(REPOSITORY_EDIT.name, { repository: REPOSITORY_EDIT, snapshots: { count: 0 }, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); @@ -54,7 +50,7 @@ describe('', () => { test('should use the same Form component as the "" section', async () => { httpRequestsMockHelpers.setLoadRepositoryTypesResponse(['fs', 'url']); - testBedRepositoryAdd = await setupRepositoryAdd(); + testBedRepositoryAdd = await setupRepositoryAdd(httpSetup); const formEdit = testBed.component.find(RepositoryForm); const formAdd = testBedRepositoryAdd.component.find(RepositoryForm); @@ -66,11 +62,11 @@ describe('', () => { describe('should populate the correct values', () => { const mountComponentWithMock = async (repository: any) => { - httpRequestsMockHelpers.setGetRepositoryResponse({ + httpRequestsMockHelpers.setGetRepositoryResponse(REPOSITORY_NAME, { repository: { name: getRandomString(), ...repository }, snapshots: { count: 0 }, }); - testBed = await setup(); + testBed = await setup(httpSetup); await act(async () => { await nextTick(); diff --git a/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts b/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts index 2d8c734af3605..1bd9898f9f1b2 100644 --- a/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts +++ b/x-pack/plugins/snapshot_restore/__jest__/client_integration/restore_snapshot.test.ts @@ -6,8 +6,10 @@ */ import { act } from 'react-dom/test-utils'; +import { API_BASE_PATH } from '../../common'; import { pageHelpers, setupEnvironment } from './helpers'; import { RestoreSnapshotTestBed } from './helpers/restore_snapshot.helpers'; +import { REPOSITORY_NAME, SNAPSHOT_NAME } from './helpers/constant'; import * as fixtures from '../../test/fixtures'; const { @@ -15,19 +17,19 @@ const { } = pageHelpers; describe('', () => { - const { server, httpRequestsMockHelpers } = setupEnvironment(); + const { httpSetup, httpRequestsMockHelpers } = setupEnvironment(); let testBed: RestoreSnapshotTestBed; - afterAll(() => { - server.restore(); - }); - describe('wizard navigation', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot()); + httpRequestsMockHelpers.setGetSnapshotResponse( + REPOSITORY_NAME, + SNAPSHOT_NAME, + fixtures.getSnapshot() + ); await act(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); testBed.component.update(); @@ -44,10 +46,14 @@ describe('', () => { describe('with data streams', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot()); + httpRequestsMockHelpers.setGetSnapshotResponse( + REPOSITORY_NAME, + SNAPSHOT_NAME, + fixtures.getSnapshot() + ); await act(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); testBed.component.update(); @@ -61,9 +67,13 @@ describe('', () => { describe('without data streams', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot({ totalDataStreams: 0 })); + httpRequestsMockHelpers.setGetSnapshotResponse( + REPOSITORY_NAME, + SNAPSHOT_NAME, + fixtures.getSnapshot({ totalDataStreams: 0 }) + ); await act(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); testBed.component.update(); @@ -77,9 +87,13 @@ describe('', () => { describe('global state', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot()); + httpRequestsMockHelpers.setGetSnapshotResponse( + REPOSITORY_NAME, + SNAPSHOT_NAME, + fixtures.getSnapshot() + ); await act(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); testBed.component.update(); @@ -100,11 +114,14 @@ describe('', () => { // the form controls and asserting that the correct payload is sent to the API. describe('include aliases', () => { beforeEach(async () => { - httpRequestsMockHelpers.setGetSnapshotResponse(fixtures.getSnapshot()); - httpRequestsMockHelpers.setRestoreSnapshotResponse({}); + httpRequestsMockHelpers.setGetSnapshotResponse( + REPOSITORY_NAME, + SNAPSHOT_NAME, + fixtures.getSnapshot() + ); await act(async () => { - testBed = await setup(); + testBed = await setup(httpSetup); }); testBed.component.update(); @@ -116,9 +133,14 @@ describe('', () => { actions.goToStep(3); await actions.clickRestore(); - const expectedPayload = { includeAliases: false }; - const latestRequest = server.requests[server.requests.length - 1]; - expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expectedPayload); + expect(httpSetup.post).toHaveBeenLastCalledWith( + `${API_BASE_PATH}restore/${REPOSITORY_NAME}/${SNAPSHOT_NAME}`, + expect.objectContaining({ + body: JSON.stringify({ + includeAliases: false, + }), + }) + ); }); }); }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts index 218cbff3bb1ec..740bf10c04432 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts @@ -11,7 +11,7 @@ import { validateExpression } from './validation'; import { EsQueryAlertParams, SearchType } from './types'; import { RuleTypeModel } from '../../../../triggers_actions_ui/public'; import { PluginSetupContract as AlertingSetup } from '../../../../alerting/public'; -import { SanitizedAlert } from '../../../../alerting/common'; +import { SanitizedRule } from '../../../../alerting/common'; const PLUGIN_ID = 'discover'; const ES_QUERY_ALERT_TYPE = '.es-query'; @@ -47,7 +47,7 @@ function registerNavigation(alerting: AlertingSetup) { alerting.registerNavigation( PLUGIN_ID, ES_QUERY_ALERT_TYPE, - (alert: SanitizedAlert>) => { + (alert: SanitizedRule>) => { return `#/viewAlert/${alert.id}`; } ); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts index b60183d7ae2fb..8b46dd6d57337 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertTypeParams } from '../../../../alerting/common'; +import { RuleTypeParams } from '../../../../alerting/common'; import { SerializedSearchSourceFields } from '../../../../../../src/plugins/data/common'; export interface Comparator { @@ -19,7 +19,7 @@ export enum SearchType { searchSource = 'searchSource', } -export interface CommonAlertParams extends AlertTypeParams { +export interface CommonAlertParams extends RuleTypeParams { size: number; thresholdComparator?: string; threshold: number[]; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/types.ts b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/types.ts index fec011223f65e..ccc94c8ac00f9 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/types.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/geo_containment/types.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { AlertTypeParams } from '../../../../alerting/common'; +import { RuleTypeParams } from '../../../../alerting/common'; import { Query } from '../../../../../../src/plugins/data/common'; -export interface GeoContainmentAlertParams extends AlertTypeParams { +export interface GeoContainmentAlertParams extends RuleTypeParams { index: string; indexId: string; geoField: string; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/threshold/types.ts b/x-pack/plugins/stack_alerts/public/alert_types/threshold/types.ts index a6257c1b5b7fa..ba6ca421173f5 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/threshold/types.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/threshold/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertTypeParams } from '../../../../alerting/common'; +import { RuleTypeParams } from '../../../../alerting/common'; export interface Comparator { text: string; @@ -27,7 +27,7 @@ export interface GroupByType { validNormalizedTypes: string[]; } -export interface IndexThresholdAlertParams extends AlertTypeParams { +export interface IndexThresholdAlertParams extends RuleTypeParams { index: string | string[]; timeField?: string; aggType: string; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.ts index e340ba6505506..7e4e8bf831493 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.ts @@ -7,12 +7,12 @@ import { i18n } from '@kbn/i18n'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { AlertExecutorOptions, AlertInstanceContext } from '../../../../alerting/server'; +import { RuleExecutorOptions, AlertInstanceContext } from '../../../../alerting/server'; import { OnlyEsQueryAlertParams, OnlySearchSourceAlertParams } from './types'; // alert type context provided to actions -type AlertInfo = Pick; +type AlertInfo = Pick; export interface ActionContext extends EsQueryAlertActionContext { // a short pre-constructed message which may be used in an action field diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts index 18f182d32deb2..c59b24ddb6210 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts @@ -7,9 +7,9 @@ import uuid from 'uuid'; import type { Writable } from '@kbn/utility-types'; -import { AlertServices } from '../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../alerting/server'; import { - AlertServicesMock, + RuleExecutorServicesMock, alertsMock, AlertInstanceMock, } from '../../../../alerting/server/mocks'; @@ -146,7 +146,7 @@ describe('alertType', () => { thresholdComparator: Comparator.BETWEEN, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const searchResult: ESSearchResponse = generateResults([]); alertServices.scopedClusterClient.asCurrentUser.search.mockResolvedValueOnce( @@ -175,7 +175,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const newestDocumentTimestamp = Date.now(); @@ -220,7 +220,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const previousTimestamp = Date.now(); const newestDocumentTimestamp = previousTimestamp + 1000; @@ -268,7 +268,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const oldestDocumentTimestamp = Date.now(); @@ -310,7 +310,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const oldestDocumentTimestamp = Date.now(); @@ -381,7 +381,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const oldestDocumentTimestamp = Date.now(); @@ -426,7 +426,7 @@ describe('alertType', () => { thresholdComparator: Comparator.GT, threshold: [0], }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const oldestDocumentTimestamp = Date.now(); @@ -524,7 +524,7 @@ describe('alertType', () => { it('alert executor handles no documents returned by ES', async () => { const params = defaultParams; const searchResult: ESSearchResponse = generateResults([]); - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); (searchSourceInstanceMock.getField as jest.Mock).mockImplementationOnce((name: string) => { if (name === 'index') { @@ -540,7 +540,7 @@ describe('alertType', () => { it('alert executor throws an error when index does not have time field', async () => { const params = defaultParams; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); (searchSourceInstanceMock.getField as jest.Mock).mockImplementationOnce((name: string) => { if (name === 'index') { @@ -555,7 +555,7 @@ describe('alertType', () => { it('alert executor schedule actions when condition met', async () => { const params = { ...defaultParams, thresholdComparator: Comparator.GT_OR_EQ, threshold: [3] }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); (searchSourceInstanceMock.getField as jest.Mock).mockImplementationOnce((name: string) => { if (name === 'index') { @@ -620,7 +620,7 @@ async function invokeExecutor({ state, }: { params: OnlySearchSourceAlertParams | OnlyEsQueryAlertParams; - alertServices: AlertServicesMock; + alertServices: RuleExecutorServicesMock; state?: EsQueryAlertState; }) { return await alertType.executor({ @@ -628,7 +628,7 @@ async function invokeExecutor({ executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), - services: alertServices as unknown as AlertServices< + services: alertServices as unknown as RuleExecutorServices< EsQueryAlertState, ActionContext, typeof ActionGroupId diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts index 12b8a7465e82b..794e740c8cca6 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { schema, TypeOf } from '@kbn/config-schema'; import { validateTimeWindowUnits } from '../../../../triggers_actions_ui/server'; -import { AlertTypeState } from '../../../../alerting/server'; +import { RuleTypeState } from '../../../../alerting/server'; import { Comparator } from '../../../common/comparator_types'; import { ComparatorFnNames } from '../lib'; import { getComparatorSchemaType } from '../lib/comparator'; @@ -17,7 +17,7 @@ export const ES_QUERY_MAX_HITS_PER_EXECUTION = 10000; // alert type parameters export type EsQueryAlertParams = TypeOf; -export interface EsQueryAlertState extends AlertTypeState { +export interface EsQueryAlertState extends RuleTypeState { latestTimestamp: string | undefined; } diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/types.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/types.ts index 3bcfbc1aef8f9..12b2ee02af171 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/types.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertExecutorOptions, AlertTypeParams } from '../../types'; +import { RuleExecutorOptions, RuleTypeParams } from '../../types'; import { ActionContext } from './action_context'; import { EsQueryAlertParams, EsQueryAlertState } from './alert_type_params'; import { ActionGroupId } from './constants'; @@ -19,7 +19,7 @@ export type OnlySearchSourceAlertParams = Omit< searchType: 'searchSource'; }; -export type ExecutorOptions

= AlertExecutorOptions< +export type ExecutorOptions

= RuleExecutorOptions< P, EsQueryAlertState, {}, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts index a25e9e8d7bf69..c65dc4d5745ea 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts @@ -12,11 +12,11 @@ import { STACK_ALERTS_FEATURE_ID } from '../../../common'; import { getGeoContainmentExecutor } from './geo_containment'; import { RuleType, - AlertTypeState, + RuleTypeState, AlertInstanceState, AlertInstanceContext, RuleParamsAndRefs, - AlertTypeParams, + RuleTypeParams, } from '../../../../alerting/server'; import { Query } from '../../../../../../src/plugins/data/common/query'; @@ -24,7 +24,7 @@ export const ActionGroupId = 'Tracked entity contained'; export const RecoveryActionGroupId = 'notGeoContained'; export const GEO_CONTAINMENT_ID = '.geo-containment'; -export interface GeoContainmentParams extends AlertTypeParams { +export interface GeoContainmentParams extends RuleTypeParams { index: string; indexId: string; geoField: string; @@ -126,7 +126,7 @@ export const ParamsSchema = schema.object({ boundaryIndexQuery: schema.maybe(schema.any({})), }); -export interface GeoContainmentState extends AlertTypeState { +export interface GeoContainmentState extends RuleTypeState { shapesFilters: Record; shapesIdsNamesMap: Record; prevLocationMap: Record; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts index aca79e29cd3e5..5d59c3cab0746 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts @@ -9,7 +9,7 @@ import _ from 'lodash'; import { Logger } from 'src/core/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { executeEsQueryFactory, getShapesFilters, OTHER_CATEGORY } from './es_query_builder'; -import { AlertServices } from '../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../alerting/server'; import { ActionGroupId, GeoContainmentInstanceState, @@ -87,7 +87,7 @@ export function transformResults( export function getActiveEntriesAndGenerateAlerts( prevLocationMap: Map, currLocationMap: Map, - alertFactory: AlertServices< + alertFactory: RuleExecutorServices< GeoContainmentInstanceState, GeoContainmentInstanceContext, typeof ActionGroupId diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts index bf9489e12777c..a5f8d0e064874 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts @@ -7,7 +7,7 @@ import _ from 'lodash'; import { loggingSystemMock, elasticsearchServiceMock } from 'src/core/server/mocks'; -import { AlertServicesMock, alertsMock } from '../../../../../alerting/server/mocks'; +import { RuleExecutorServicesMock, alertsMock } from '../../../../../alerting/server/mocks'; import sampleAggsJsonResponse from './es_sample_response.json'; import sampleShapesJsonResponse from './es_sample_response_shapes.json'; import sampleAggsJsonResponseWithNesting from './es_sample_response_with_nesting.json'; @@ -525,8 +525,8 @@ describe('geo_containment', () => { } }); - const alertServicesWithSearchMock: AlertServicesMock = { - ...alertsMock.createAlertServices(), + const alertServicesWithSearchMock: RuleExecutorServicesMock = { + ...alertsMock.createRuleExecutorServices(), // @ts-ignore alertFactory: alertFactory(contextKeys, testAlertActionArr), // @ts-ignore diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/action_context.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/action_context.ts index 02450da5bbdf7..f75869d8e0db2 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/action_context.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/action_context.ts @@ -7,11 +7,11 @@ import { i18n } from '@kbn/i18n'; import { Params } from './alert_type_params'; -import { AlertExecutorOptions, AlertInstanceContext } from '../../../../alerting/server'; +import { RuleExecutorOptions, AlertInstanceContext } from '../../../../alerting/server'; // alert type context provided to actions -type RuleInfo = Pick; +type RuleInfo = Pick; export interface ActionContext extends BaseActionContext { // a short pre-constructed message which may be used in an action field diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts index 060730fb668e3..16117ed6fd507 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.test.ts @@ -8,11 +8,11 @@ import uuid from 'uuid'; import type { Writable } from '@kbn/utility-types'; import { loggingSystemMock } from '../../../../../../src/core/server/mocks'; -import { AlertServices } from '../../../../alerting/server'; +import { RuleExecutorServices } from '../../../../alerting/server'; import { getAlertType, ActionGroupId } from './alert_type'; import { ActionContext } from './action_context'; import { Params } from './alert_type_params'; -import { AlertServicesMock, alertsMock } from '../../../../alerting/server/mocks'; +import { RuleExecutorServicesMock, alertsMock } from '../../../../alerting/server/mocks'; import { Comparator } from '../../../common/comparator_types'; describe('alertType', () => { @@ -20,7 +20,7 @@ describe('alertType', () => { const data = { timeSeriesQuery: jest.fn(), }; - const alertServices: AlertServicesMock = alertsMock.createAlertServices(); + const alertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); const alertType = getAlertType(logger, Promise.resolve(data)); @@ -173,7 +173,11 @@ describe('alertType', () => { executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), - services: alertServices as unknown as AlertServices<{}, ActionContext, typeof ActionGroupId>, + services: alertServices as unknown as RuleExecutorServices< + {}, + ActionContext, + typeof ActionGroupId + >, params, state: { latestTimestamp: undefined, @@ -208,7 +212,7 @@ describe('alertType', () => { }); it('should ensure a null result does not fire actions', async () => { - const customAlertServices: AlertServicesMock = alertsMock.createAlertServices(); + const customAlertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); data.timeSeriesQuery.mockImplementation((...args) => { return { results: [ @@ -235,7 +239,7 @@ describe('alertType', () => { executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), - services: customAlertServices as unknown as AlertServices< + services: customAlertServices as unknown as RuleExecutorServices< {}, ActionContext, typeof ActionGroupId @@ -274,7 +278,7 @@ describe('alertType', () => { }); it('should ensure an undefined result does not fire actions', async () => { - const customAlertServices: AlertServicesMock = alertsMock.createAlertServices(); + const customAlertServices: RuleExecutorServicesMock = alertsMock.createRuleExecutorServices(); data.timeSeriesQuery.mockImplementation((...args) => { return { results: [ @@ -301,7 +305,7 @@ describe('alertType', () => { executionId: uuid.v4(), startedAt: new Date(), previousStartedAt: new Date(), - services: customAlertServices as unknown as AlertServices< + services: customAlertServices as unknown as RuleExecutorServices< {}, ActionContext, typeof ActionGroupId diff --git a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts index 1d838fda0e8e0..9da47aa76e0c0 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/index_threshold/alert_type.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { Logger } from 'src/core/server'; -import { RuleType, AlertExecutorOptions, StackAlertsStartDeps } from '../../types'; +import { RuleType, RuleExecutorOptions, StackAlertsStartDeps } from '../../types'; import { Params, ParamsSchema } from './alert_type_params'; import { ActionContext, BaseActionContext, addMessages } from './action_context'; import { STACK_ALERTS_FEATURE_ID } from '../../../common'; @@ -132,7 +132,7 @@ export function getAlertType( }; async function executor( - options: AlertExecutorOptions + options: RuleExecutorOptions ) { const { alertId: ruleId, name, services, params } = options; const { alertFactory, scopedClusterClient } = services; diff --git a/x-pack/plugins/stack_alerts/server/types.ts b/x-pack/plugins/stack_alerts/server/types.ts index 719373d21f18a..3690cbd92e459 100644 --- a/x-pack/plugins/stack_alerts/server/types.ts +++ b/x-pack/plugins/stack_alerts/server/types.ts @@ -12,8 +12,8 @@ export type { PluginSetupContract as AlertingSetup, RuleType, RuleParamsAndRefs, - AlertExecutorOptions, - AlertTypeParams, + RuleExecutorOptions, + RuleTypeParams, } from '../../alerting/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../features/server'; diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 02cbcf2c7b0c0..7db9d905d5c93 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -1943,6 +1943,332 @@ "type": "long" } } + }, + "percentile_num_scheduled_actions_per_day": { + "properties": { + "p50": { + "type": "long" + }, + "p90": { + "type": "long" + }, + "p99": { + "type": "long" + } + } + }, + "percentile_num_scheduled_actions_by_type_per_day": { + "properties": { + "p50": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "siem__eqlRule": { + "type": "long" + }, + "siem__indicatorRule": { + "type": "long" + }, + "siem__mlRule": { + "type": "long" + }, + "siem__queryRule": { + "type": "long" + }, + "siem__savedQueryRule": { + "type": "long" + }, + "siem__thresholdRule": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "p90": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "siem__eqlRule": { + "type": "long" + }, + "siem__indicatorRule": { + "type": "long" + }, + "siem__mlRule": { + "type": "long" + }, + "siem__queryRule": { + "type": "long" + }, + "siem__savedQueryRule": { + "type": "long" + }, + "siem__thresholdRule": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + }, + "p99": { + "properties": { + "DYNAMIC_KEY": { + "type": "long" + }, + "__index-threshold": { + "type": "long" + }, + "__es-query": { + "type": "long" + }, + "transform_health": { + "type": "long" + }, + "apm__error_rate": { + "type": "long" + }, + "apm__transaction_error_rate": { + "type": "long" + }, + "apm__transaction_duration": { + "type": "long" + }, + "apm__transaction_duration_anomaly": { + "type": "long" + }, + "metrics__alert__threshold": { + "type": "long" + }, + "metrics__alert__inventory__threshold": { + "type": "long" + }, + "logs__alert__document__count": { + "type": "long" + }, + "monitoring_alert_cluster_health": { + "type": "long" + }, + "monitoring_alert_cpu_usage": { + "type": "long" + }, + "monitoring_alert_disk_usage": { + "type": "long" + }, + "monitoring_alert_elasticsearch_version_mismatch": { + "type": "long" + }, + "monitoring_alert_kibana_version_mismatch": { + "type": "long" + }, + "monitoring_alert_license_expiration": { + "type": "long" + }, + "monitoring_alert_logstash_version_mismatch": { + "type": "long" + }, + "monitoring_alert_nodes_changed": { + "type": "long" + }, + "siem__signals": { + "type": "long" + }, + "siem__notifications": { + "type": "long" + }, + "siem__eqlRule": { + "type": "long" + }, + "siem__indicatorRule": { + "type": "long" + }, + "siem__mlRule": { + "type": "long" + }, + "siem__queryRule": { + "type": "long" + }, + "siem__savedQueryRule": { + "type": "long" + }, + "siem__thresholdRule": { + "type": "long" + }, + "xpack__uptime__alerts__monitorStatus": { + "type": "long" + }, + "xpack__uptime__alerts__tls": { + "type": "long" + }, + "xpack__uptime__alerts__durationAnomaly": { + "type": "long" + }, + "__geo-containment": { + "type": "long" + }, + "xpack__ml__anomaly_detection_alert": { + "type": "long" + }, + "xpack__ml__anomaly_detection_jobs_health": { + "type": "long" + } + } + } + } } } }, diff --git a/x-pack/plugins/transform/common/types/alerting.ts b/x-pack/plugins/transform/common/types/alerting.ts index 07d6bbdbe4152..cc031d36f0483 100644 --- a/x-pack/plugins/transform/common/types/alerting.ts +++ b/x-pack/plugins/transform/common/types/alerting.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { Alert, AlertTypeParams } from '../../../alerting/common'; +import type { Rule, RuleTypeParams } from '../../../alerting/common'; export type TransformHealthRuleParams = { includeTransforms?: string[]; @@ -18,10 +18,10 @@ export type TransformHealthRuleParams = { enabled: boolean; } | null; } | null; -} & AlertTypeParams; +} & RuleTypeParams; export type TransformHealthRuleTestsConfig = TransformHealthRuleParams['testsConfig']; export type TransformHealthTests = keyof Exclude; -export type TransformHealthAlertRule = Omit, 'apiKey'>; +export type TransformHealthAlertRule = Omit, 'apiKey'>; diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts index ad85649c0f2c4..04a4685c45892 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts @@ -11,7 +11,7 @@ import type { ActionGroup, AlertInstanceContext, AlertInstanceState, - AlertTypeState, + RuleTypeState, } from '../../../../../alerting/common'; import { PLUGIN, TRANSFORM_RULE_TYPE } from '../../../../common/constants'; import { transformHealthRuleParams, TransformHealthRuleParams } from './schema'; @@ -64,7 +64,7 @@ export function registerTransformHealthRuleType(params: RegisterParams) { export function getTransformHealthRuleType(): RuleType< TransformHealthRuleParams, never, - AlertTypeState, + RuleTypeState, AlertInstanceState, TransformHealthAlertContext, TransformIssue diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 0bdb7f8b02255..6f60efe51bdff 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27776,13 +27776,6 @@ "xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerEditText": "ルールを編集", "xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerTitle": "このルールに関連付けられたコネクターの1つで問題が発生しています。", "xpack.triggersActionsUI.sections.ruleDetails.ruleDetailsTitle": "{ruleName}", - "xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRule": "このルールは無効になっていて再表示できません。", - "xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRuleTitle": "無効なルール", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableLoadingTitle": "有効にする", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableTitle": "有効にする", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteLoadingTitle": "ミュート", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteTitle": "ミュート", - "xpack.triggersActionsUI.sections.ruleDetails.dismissButtonTitle": "閉じる", "xpack.triggersActionsUI.sections.ruleDetails.editRuleButtonLabel": "編集", "xpack.triggersActionsUI.sections.ruleDetails.manageLicensePlanBannerLinkTitle": "ライセンスの管理", "xpack.triggersActionsUI.sections.ruleDetails.redirectObjectNoun": "ルール", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 39fd63bf68d80..8f16c032a6b1c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27805,13 +27805,6 @@ "xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerEditText": "编辑规则", "xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerTitle": "与此规则关联的连接器之一出现问题。", "xpack.triggersActionsUI.sections.ruleDetails.ruleDetailsTitle": "{ruleName}", - "xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRule": "此规则已禁用,无法显示。", - "xpack.triggersActionsUI.sections.ruleDetails.alertInstances.disabledRuleTitle": "已禁用规则", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableLoadingTitle": "启用", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.enableTitle": "启用", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteLoadingTitle": "静音", - "xpack.triggersActionsUI.sections.ruleDetails.collapsedItemActons.muteTitle": "静音", - "xpack.triggersActionsUI.sections.ruleDetails.dismissButtonTitle": "关闭", "xpack.triggersActionsUI.sections.ruleDetails.editRuleButtonLabel": "编辑", "xpack.triggersActionsUI.sections.ruleDetails.manageLicensePlanBannerLinkTitle": "管理许可证", "xpack.triggersActionsUI.sections.ruleDetails.redirectObjectNoun": "规则", diff --git a/x-pack/plugins/triggers_actions_ui/README.md b/x-pack/plugins/triggers_actions_ui/README.md index 14bf6164979e7..f4a1f79da1546 100644 --- a/x-pack/plugins/triggers_actions_ui/README.md +++ b/x-pack/plugins/triggers_actions_ui/README.md @@ -266,7 +266,7 @@ export interface RuleType { params?: { validate: (object: any) => any }; }; actionGroups: string[]; - executor: ({ services, params, state }: AlertExecutorOptions) => Promise; + executor: ({ services, params, state }: RuleExecutorOptions) => Promise; requiresAppContext: boolean; } ``` @@ -1385,7 +1385,7 @@ Then this dependencies will be used to embed Actions form or register your own a ``` import React, { useCallback } from 'react'; import { ActionForm } from '../../../../../../../../../plugins/triggers_actions_ui/public'; - import { AlertAction } from '../../../../../../../../../plugins/triggers_actions_ui/public/types'; + import { RuleAction } from '../../../../../../../../../plugins/triggers_actions_ui/public/types'; const ALOWED_BY_PLUGIN_ACTION_TYPES = [ { id: '.email', name: 'Email', enabled: true }, @@ -1428,7 +1428,7 @@ Then this dependencies will be used to embed Actions form or register your own a setActionIdByIndex={(id: string, index: number) => { initialAlert.actions[index].id = id; }} - setRuleProperty={(_updatedActions: AlertAction[]) => {}} + setRuleProperty={(_updatedActions: RuleAction[]) => {}} setActionParamsProperty={(key: string, value: any, index: number) => (initialAlert.actions[index] = { ...initialAlert.actions[index], [key]: value }) } @@ -1446,12 +1446,12 @@ Then this dependencies will be used to embed Actions form or register your own a ActionForm Props definition: ``` interface ActionAccordionFormProps { - actions: AlertAction[]; + actions: RuleAction[]; defaultActionGroupId: string; actionGroups?: ActionGroup[]; setActionIdByIndex: (id: string, index: number) => void; setActionGroupIdByIndex?: (group: string, index: number) => void; - setRuleProperty: (actions: AlertAction[]) => void; + setRuleProperty: (actions: RuleAction[]) => void; setActionParamsProperty: (key: string, value: any, index: number) => void; http: HttpSetup; actionTypeRegistry: ActionTypeRegistryContract; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts index 7936e5843de7f..a06eb360a70c3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/get_defaults_for_action_params.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { AlertActionParam } from '../../../../alerting/common'; +import { RuleActionParam } from '../../../../alerting/common'; import { EventActionOptions } from '../components/builtin_action_types/types'; import { AlertProvidedActionVariables } from './action_variables'; -export type DefaultActionParams = Record | undefined; +export type DefaultActionParams = Record | undefined; export type DefaultActionParamsGetter = ( actionTypeId: string, actionGroupId: string diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts index b2556900e763a..d67c4f80b142d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts @@ -14,12 +14,14 @@ const rewriteBodyRes: RewriteRequestCase = ({ rule_execution_status: ruleExecutionStatus, rule_enabled_status: ruleEnabledStatus, rule_muted_status: ruleMutedStatus, + rule_snoozed_status: ruleSnoozedStatus, ...rest }: any) => ({ ...rest, ruleExecutionStatus, ruleEnabledStatus, ruleMutedStatus, + ruleSnoozedStatus, }); export async function loadRuleAggregations({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts index 69b7b494431fc..10a16313e87a4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/common_transformations.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { AlertExecutionStatus } from '../../../../../alerting/common'; +import { RuleExecutionStatus } from '../../../../../alerting/common'; import { AsApiContract, RewriteRequestCase } from '../../../../../actions/common'; import { Rule, RuleAction, ResolvedRule } from '../../../types'; @@ -20,7 +20,7 @@ const transformAction: RewriteRequestCase = ({ actionTypeId, }); -const transformExecutionStatus: RewriteRequestCase = ({ +const transformExecutionStatus: RewriteRequestCase = ({ last_execution_date: lastExecutionDate, last_duration: lastDuration, ...rest diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts index 2dceac6dfd7d9..bb631b32328f4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts @@ -12,9 +12,9 @@ import type { SortOrder } from '@elastic/elasticsearch/lib/api/typesWithBodyKey' import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants'; import { - IExecutionLogResult, IExecutionLog, ExecutionLogSortFields, + IExecutionLogWithErrorsResult, } from '../../../../../alerting/common'; import { AsApiContract, RewriteRequestCase } from '../../../../../actions/common'; @@ -36,9 +36,12 @@ const getRenamedLog = (data: IExecutionLog) => { }; }; -const rewriteBodyRes: RewriteRequestCase = ({ data, total }: any) => ({ +const rewriteBodyRes: RewriteRequestCase = ({ + data, + ...rest +}: any) => ({ data: data.map((log: IExecutionLog) => getRenamedLog(log)), - total, + ...rest, }); const getFilter = (filter: string[] | undefined) => { @@ -77,7 +80,7 @@ export const loadExecutionLogAggregations = async ({ }: LoadExecutionLogAggregationsProps & { http: HttpSetup }) => { const sortField: any[] = sort; - const result = await http.get>( + const result = await http.get>( `${INTERNAL_BASE_ALERTING_API_PATH}/rule/${id}/_execution_log`, { query: { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx index 7c1af79c05626..34e2094d51a6d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.tsx @@ -35,7 +35,7 @@ import { AddConnectorInline } from './connector_add_inline'; import { actionTypeCompare } from '../../lib/action_type_compare'; import { checkActionFormActionTypeEnabled } from '../../lib/check_action_type_enabled'; import { VIEW_LICENSE_OPTIONS_LINK, DEFAULT_HIDDEN_ACTION_TYPES } from '../../../common/constants'; -import { ActionGroup, AlertActionParam } from '../../../../../alerting/common'; +import { ActionGroup, RuleActionParam } from '../../../../../alerting/common'; import { useKibana } from '../../../common/lib/kibana'; import { DefaultActionParamsGetter } from '../../lib/get_defaults_for_action_params'; import { ConnectorAddModal } from '.'; @@ -55,7 +55,7 @@ export interface ActionAccordionFormProps { setActionIdByIndex: (id: string, index: number) => void; setActionGroupIdByIndex?: (group: string, index: number) => void; setActions: (actions: RuleAction[]) => void; - setActionParamsProperty: (key: string, value: AlertActionParam, index: number) => void; + setActionParamsProperty: (key: string, value: RuleActionParam, index: number) => void; actionTypes?: ActionType[]; messageVariables?: ActionVariables; setHasActionsDisabled?: (value: boolean) => void; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index c817f5895a816..5c336d37ebb51 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -25,7 +25,7 @@ import { EuiErrorBoundary, } from '@elastic/eui'; import { partition } from 'lodash'; -import { ActionVariable, AlertActionParam } from '../../../../../alerting/common'; +import { ActionVariable, RuleActionParam } from '../../../../../alerting/common'; import { IErrorObject, RuleAction, @@ -49,7 +49,7 @@ export type ActionTypeFormProps = { onAddConnector: () => void; onConnectorSelected: (id: string) => void; onDeleteAction: () => void; - setActionParamsProperty: (key: string, value: AlertActionParam, index: number) => void; + setActionParamsProperty: (key: string, value: RuleActionParam, index: number) => void; actionTypesIndex: ActionTypeIndex; connectors: ActionConnector[]; actionTypeRegistry: ActionTypeRegistryContract; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.tsx index a9c9dfa72279c..3398df07ce219 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/common/components/with_bulk_rule_api_operations.tsx @@ -35,8 +35,10 @@ import { resolveRule, loadExecutionLogAggregations, LoadExecutionLogAggregationsProps, + snoozeRule, + unsnoozeRule, } from '../../../lib/rule_api'; -import { IExecutionLogResult } from '../../../../../../alerting/common'; +import { IExecutionLogWithErrorsResult } from '../../../../../../alerting/common'; import { useKibana } from '../../../../common/lib/kibana'; export interface ComponentOpts { @@ -64,9 +66,11 @@ export interface ComponentOpts { loadRuleTypes: () => Promise; loadExecutionLogAggregations: ( props: LoadExecutionLogAggregationsProps - ) => Promise; + ) => Promise; getHealth: () => Promise; resolveRule: (id: Rule['id']) => Promise; + snoozeRule: (rule: Rule, snoozeEndTime: string | -1) => Promise; + unsnoozeRule: (rule: Rule) => Promise; } export type PropsWithOptionalApiHandlers = Omit & Partial; @@ -145,6 +149,12 @@ export function withBulkRuleOperations( } resolveRule={async (ruleId: Rule['id']) => resolveRule({ http, ruleId })} getHealth={async () => alertingFrameworkHealth({ http })} + snoozeRule={async (rule: Rule, snoozeEndTime: string | -1) => { + return await snoozeRule({ http, id: rule.id, snoozeEndTime }); + }} + unsnoozeRule={async (rule: Rule) => { + return await unsnoozeRule({ http, id: rule.id }); + }} /> ); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx index c3eb699cc0c90..106567a3c363d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx @@ -12,17 +12,19 @@ import { EuiSpacer, EuiFlexGroup, EuiFlexItem, - EuiHorizontalRule, EuiPanel, EuiStat, EuiIconTip, EuiTabbedContent, + EuiText, } from '@elastic/eui'; // @ts-ignore import { RIGHT_ALIGNMENT, CENTER_ALIGNMENT } from '@elastic/eui/lib/services'; +import { FormattedMessage } from '@kbn/i18n-react'; +import moment from 'moment'; import { ActionGroup, - AlertExecutionStatusErrorReasons, + RuleExecutionStatusErrorReasons, AlertStatusValues, } from '../../../../../../alerting/common'; import { Rule, RuleSummary, AlertStatus, RuleType } from '../../../../types'; @@ -47,6 +49,7 @@ import { getIsExperimentalFeatureEnabled } from '../../../../common/get_experime import { suspendedComponentWithProps } from '../../../lib/suspended_component_with_props'; const RuleEventLogListWithApi = lazy(() => import('./rule_event_log_list')); +const RuleErrorLogWithApi = lazy(() => import('./rule_error_log')); const RuleAlertList = lazy(() => import('./rule_alert_list')); @@ -56,6 +59,7 @@ type RuleProps = { readOnly: boolean; ruleSummary: RuleSummary; requestRefresh: () => Promise; + refreshToken?: number; numberOfExecutions: number; onChangeDuration: (length: number) => void; durationEpoch?: number; @@ -64,6 +68,7 @@ type RuleProps = { const EVENT_LOG_LIST_TAB = 'rule_event_log_list'; const ALERT_LIST_TAB = 'rule_alert_list'; +const EVENT_ERROR_LOG_TAB = 'rule_error_log_list'; export function RuleComponent({ rule, @@ -73,6 +78,7 @@ export function RuleComponent({ muteAlertInstance, unmuteAlertInstance, requestRefresh, + refreshToken, numberOfExecutions, onChangeDuration, durationEpoch = Date.now(), @@ -96,7 +102,7 @@ export function RuleComponent({ const healthColor = getHealthColor(rule.executionStatus.status); const isLicenseError = - rule.executionStatus.error?.reason === AlertExecutionStatusErrorReasons.License; + rule.executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License; const statusMessage = isLicenseError ? ALERT_STATUS_LICENSE_ERROR : rulesStatusesTranslationsMapping[rule.executionStatus.status]; @@ -116,10 +122,13 @@ export function RuleComponent({ { id: EVENT_LOG_LIST_TAB, name: i18n.translate('xpack.triggersActionsUI.sections.ruleDetails.rule.eventLogTabText', { - defaultMessage: 'Execution History', + defaultMessage: 'Execution history', }), 'data-test-subj': 'eventLogListTab', - content: suspendedComponentWithProps(RuleEventLogListWithApi, 'xl')({ rule }), + content: suspendedComponentWithProps( + RuleEventLogListWithApi, + 'xl' + )({ requestRefresh, rule, refreshToken }), }, { id: ALERT_LIST_TAB, @@ -129,6 +138,17 @@ export function RuleComponent({ 'data-test-subj': 'ruleAlertListTab', content: renderRuleAlertList(), }, + { + id: EVENT_ERROR_LOG_TAB, + name: i18n.translate('xpack.triggersActionsUI.sections.ruleDetails.rule.errorLogTabText', { + defaultMessage: 'Error log', + }), + 'data-test-subj': 'errorLogTab', + content: suspendedComponentWithProps( + RuleErrorLogWithApi, + 'xl' + )({ requestRefresh, rule, refreshToken }), + }, ]; const renderTabs = () => { @@ -141,29 +161,51 @@ export function RuleComponent({ return ( <> - - + + - {statusMessage} - - } - description={i18n.translate( - 'xpack.triggersActionsUI.sections.ruleDetails.rulesList.ruleLastExecutionDescription', - { - defaultMessage: `Last response`, - } - )} - /> + titleSize="xs" + title={ + + {statusMessage} + + } + description={i18n.translate( + 'xpack.triggersActionsUI.sections.ruleDetails.rulesList.ruleLastExecutionDescription', + { + defaultMessage: `Last response`, + } + )} + /> + + +

+ + + + + {moment(rule.executionStatus.lastExecutionDate).fromNow()} + +

+ + @@ -217,6 +259,7 @@ export function RuleComponent({ /> + ({ @@ -64,6 +59,8 @@ const mockRuleApis = { disableRule: jest.fn(), requestRefresh: jest.fn(), refreshToken: Date.now(), + snoozeRule: jest.fn(), + unsnoozeRule: jest.fn(), }; const authorizedConsumers = { @@ -103,48 +100,44 @@ describe('rule_details', () => { ).toBeTruthy(); }); - it('renders the rule error banner with error message, when rule status is an error', () => { + it('renders the rule error banner with error message, when rule has a license error', () => { const rule = mockRule({ + enabled: true, executionStatus: { status: 'error', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { - reason: AlertExecutionStatusErrorReasons.Unknown, + reason: RuleExecutionStatusErrorReasons.License, message: 'test', }, }, }); - expect( - shallow( - - ).containsMatchingElement( - - {'test'} - - ) - ).toBeTruthy(); + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="ruleErrorBanner"]').first().text()).toMatchInlineSnapshot( + `" Cannot run rule, test "` + ); }); it('renders the rule warning banner with warning message, when rule status is a warning', () => { const rule = mockRule({ + enabled: true, executionStatus: { status: 'warning', lastExecutionDate: new Date('2020-08-20T19:23:38Z'), warning: { - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, message: 'warning message', }, }, }); + const wrapper = shallow( + + ); expect( - shallow( - - ).containsMatchingElement( - - {'warning message'} - - ) - ).toBeTruthy(); + wrapper.find('[data-test-subj="ruleWarningBanner"]').first().text() + ).toMatchInlineSnapshot(`" Action limit exceeded warning message"`); }); it('displays a toast message when interval is less than configured minimum', async () => { @@ -190,7 +183,7 @@ describe('rule_details', () => { ]; expect( - shallow( + mountWithIntl( { }, ]; - const details = shallow( + const details = mountWithIntl( ); @@ -302,63 +295,71 @@ describe('rule_details', () => { }); }); -describe('disable button', () => { - it('should render a disable button when rule is enabled', () => { +describe('disable/enable functionality', () => { + it('should show that the rule is enabled', () => { const rule = mockRule({ enabled: true, }); - const enableButton = shallow( + const wrapper = mountWithIntl( - ) - .find(EuiSwitch) - .find('[name="enable"]') - .first(); + ); + const actionsElem = wrapper.find('[data-test-subj="statusDropdown"]').first(); - expect(enableButton.props()).toMatchObject({ - checked: true, - disabled: false, - }); + expect(actionsElem.text()).toEqual('Enabled'); }); - it('should render a enable button and empty state when rule is disabled', async () => { + it('should show that the rule is disabled', async () => { const rule = mockRule({ enabled: false, }); const wrapper = mountWithIntl( ); + const actionsElem = wrapper.find('[data-test-subj="statusDropdown"]').first(); + + expect(actionsElem.text()).toEqual('Disabled'); + }); + + it('should disable the rule when picking disable in the dropdown', async () => { + const rule = mockRule({ + enabled: true, + }); + const disableRule = jest.fn(); + const wrapper = mountWithIntl( + + ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') + .first(); + actionsElem.simulate('click'); await act(async () => { await nextTick(); wrapper.update(); }); - const enableButton = wrapper.find(EuiSwitch).find('[name="enable"]').first(); - const disabledEmptyPrompt = wrapper.find('[data-test-subj="disabledEmptyPrompt"]'); - const disabledEmptyPromptAction = wrapper.find('[data-test-subj="disabledEmptyPromptAction"]'); - - expect(enableButton.props()).toMatchObject({ - checked: false, - disabled: false, - }); - expect(disabledEmptyPrompt.exists()).toBeTruthy(); - expect(disabledEmptyPromptAction.exists()).toBeTruthy(); - - disabledEmptyPromptAction.first().simulate('click'); await act(async () => { + const actionsMenuElem = wrapper.find('[data-test-subj="ruleStatusMenu"]'); + const actionsMenuItemElem = actionsMenuElem.first().find('.euiContextMenuItem'); + actionsMenuItemElem.at(1).simulate('click'); await nextTick(); - wrapper.update(); }); - expect(mockRuleApis.enableRule).toHaveBeenCalledTimes(1); + expect(disableRule).toHaveBeenCalledTimes(1); }); - it('should disable the rule when rule is enabled and button is clicked', () => { + it('if rule is already disable should do nothing when picking disable in the dropdown', async () => { const rule = mockRule({ - enabled: true, + enabled: false, }); const disableRule = jest.fn(); - const enableButton = shallow( + const wrapper = mountWithIntl( { {...mockRuleApis} disableRule={disableRule} /> - ) - .find(EuiSwitch) - .find('[name="enable"]') + ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') .first(); + actionsElem.simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + await act(async () => { + const actionsMenuElem = wrapper.find('[data-test-subj="ruleStatusMenu"]'); + const actionsMenuItemElem = actionsMenuElem.first().find('.euiContextMenuItem'); + actionsMenuItemElem.at(1).simulate('click'); + await nextTick(); + }); - enableButton.simulate('click'); - const handler = enableButton.prop('onChange'); - expect(typeof handler).toEqual('function'); expect(disableRule).toHaveBeenCalledTimes(0); - handler!({} as React.FormEvent); - expect(disableRule).toHaveBeenCalledTimes(1); }); - it('should enable the rule when rule is disabled and button is clicked', () => { + it('should enable the rule when picking enable in the dropdown', async () => { const rule = mockRule({ enabled: false, }); const enableRule = jest.fn(); - const enableButton = shallow( + const wrapper = mountWithIntl( { {...mockRuleApis} enableRule={enableRule} /> - ) - .find(EuiSwitch) - .find('[name="enable"]') + ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') .first(); + actionsElem.simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + await act(async () => { + const actionsMenuElem = wrapper.find('[data-test-subj="ruleStatusMenu"]'); + const actionsMenuItemElem = actionsMenuElem.first().find('.euiContextMenuItem'); + actionsMenuItemElem.at(0).simulate('click'); + await nextTick(); + }); - enableButton.simulate('click'); - const handler = enableButton.prop('onChange'); - expect(typeof handler).toEqual('function'); - expect(enableRule).toHaveBeenCalledTimes(0); - handler!({} as React.FormEvent); expect(enableRule).toHaveBeenCalledTimes(1); }); - it('should reset error banner dismissal after re-enabling the rule', async () => { + it('if rule is already enable should do nothing when picking enable in the dropdown', async () => { const rule = mockRule({ enabled: true, - executionStatus: { - status: 'error', - lastExecutionDate: new Date('2020-08-20T19:23:38Z'), - error: { - reason: AlertExecutionStatusErrorReasons.Execute, - message: 'Fail', - }, - }, }); - - const disableRule = jest.fn(); const enableRule = jest.fn(); const wrapper = mountWithIntl( { ruleType={ruleType} actionTypes={[]} {...mockRuleApis} - disableRule={disableRule} enableRule={enableRule} /> ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') + .first(); + actionsElem.simulate('click'); await act(async () => { await nextTick(); wrapper.update(); }); - // Dismiss the error banner - await act(async () => { - wrapper.find('[data-test-subj="dismiss-execution-error"]').first().simulate('click'); - await nextTick(); - }); - - // Disable the rule - await act(async () => { - wrapper.find('[data-test-subj="enableSwitch"] .euiSwitch__button').first().simulate('click'); - await nextTick(); - }); - expect(disableRule).toHaveBeenCalled(); - - await act(async () => { - await nextTick(); - wrapper.update(); - }); - - // Enable the rule await act(async () => { - wrapper.find('[data-test-subj="enableSwitch"] .euiSwitch__button').first().simulate('click'); + const actionsMenuElem = wrapper.find('[data-test-subj="ruleStatusMenu"]'); + const actionsMenuItemElem = actionsMenuElem.first().find('.euiContextMenuItem'); + actionsMenuItemElem.at(0).simulate('click'); await nextTick(); }); - expect(enableRule).toHaveBeenCalled(); - // Ensure error banner is back - expect(wrapper.find('[data-test-subj="dismiss-execution-error"]').length).toBeGreaterThan(0); + expect(enableRule).toHaveBeenCalledTimes(0); }); it('should show the loading spinner when the rule enabled switch was clicked and the server responded with some delay', async () => { const rule = mockRule({ enabled: true, - executionStatus: { - status: 'error', - lastExecutionDate: new Date('2020-08-20T19:23:38Z'), - error: { - reason: AlertExecutionStatusErrorReasons.Execute, - message: 'Fail', - }, - }, }); const disableRule = jest.fn(async () => { @@ -493,139 +476,53 @@ describe('disable button', () => { /> ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') + .first(); + actionsElem.simulate('click'); + await act(async () => { await nextTick(); wrapper.update(); }); - // Dismiss the error banner await act(async () => { - wrapper.find('[data-test-subj="dismiss-execution-error"]').first().simulate('click'); - await nextTick(); + const actionsMenuElem = wrapper.find('[data-test-subj="ruleStatusMenu"]'); + const actionsMenuItemElem = actionsMenuElem.first().find('.euiContextMenuItem'); + actionsMenuItemElem.at(1).simulate('click'); }); - // Disable the rule - await act(async () => { - wrapper.find('[data-test-subj="enableSwitch"] .euiSwitch__button').first().simulate('click'); - await nextTick(); - }); - expect(disableRule).toHaveBeenCalled(); - await act(async () => { await nextTick(); wrapper.update(); }); - // Enable the rule await act(async () => { - expect(wrapper.find('[data-test-subj="enableSpinner"]').length).toBeGreaterThan(0); - await nextTick(); + expect(disableRule).toHaveBeenCalled(); + expect( + wrapper.find('[data-test-subj="statusDropdown"] .euiBadge__childButton .euiLoadingSpinner') + .length + ).toBeGreaterThan(0); }); }); }); -describe('mute button', () => { - it('should render an mute button when rule is enabled', () => { - const rule = mockRule({ - enabled: true, - muteAll: false, - }); - const enableButton = shallow( - - ) - .find(EuiSwitch) - .find('[name="mute"]') - .first(); - expect(enableButton.props()).toMatchObject({ - checked: false, - disabled: false, - }); - }); - - it('should render an muted button when rule is muted', () => { +describe('snooze functionality', () => { + it('should render "Snooze Indefinitely" when rule is enabled and mute all', () => { const rule = mockRule({ enabled: true, muteAll: true, }); - const enableButton = shallow( - - ) - .find(EuiSwitch) - .find('[name="mute"]') - .first(); - expect(enableButton.props()).toMatchObject({ - checked: true, - disabled: false, - }); - }); - - it('should mute the rule when rule is unmuted and button is clicked', () => { - const rule = mockRule({ - enabled: true, - muteAll: false, - }); - const muteRule = jest.fn(); - const enableButton = shallow( - - ) - .find(EuiSwitch) - .find('[name="mute"]') - .first(); - enableButton.simulate('click'); - const handler = enableButton.prop('onChange'); - expect(typeof handler).toEqual('function'); - expect(muteRule).toHaveBeenCalledTimes(0); - handler!({} as React.FormEvent); - expect(muteRule).toHaveBeenCalledTimes(1); - }); - - it('should unmute the rule when rule is muted and button is clicked', () => { - const rule = mockRule({ - enabled: true, - muteAll: true, - }); - const unmuteRule = jest.fn(); - const enableButton = shallow( - - ) - .find(EuiSwitch) - .find('[name="mute"]') - .first(); - enableButton.simulate('click'); - const handler = enableButton.prop('onChange'); - expect(typeof handler).toEqual('function'); - expect(unmuteRule).toHaveBeenCalledTimes(0); - handler!({} as React.FormEvent); - expect(unmuteRule).toHaveBeenCalledTimes(1); - }); - - it('should disabled mute button when rule is disabled', () => { - const rule = mockRule({ - enabled: false, - muteAll: false, - }); - const enableButton = shallow( + const wrapper = mountWithIntl( - ) - .find(EuiSwitch) - .find('[name="mute"]') + ); + const actionsElem = wrapper + .find('[data-test-subj="statusDropdown"] .euiBadge__childButton') .first(); - expect(enableButton.props()).toMatchObject({ - checked: false, - disabled: true, - }); + expect(actionsElem.text()).toEqual('Snoozed'); + expect(wrapper.find('[data-test-subj="remainingSnoozeTime"]').first().text()).toEqual( + 'Indefinitely' + ); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx index 736178cc5ab3e..e8d4c0b089485 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.tsx @@ -16,19 +16,17 @@ import { EuiFlexItem, EuiBadge, EuiPageContentBody, - EuiSwitch, EuiCallOut, EuiSpacer, EuiButtonEmpty, EuiButton, - EuiLoadingSpinner, EuiIconTip, - EuiEmptyPrompt, - EuiPageTemplate, + EuiIcon, + EuiLink, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; -import { AlertExecutionStatusErrorReasons, parseDuration } from '../../../../../../alerting/common'; +import { RuleExecutionStatusErrorReasons, parseDuration } from '../../../../../../alerting/common'; import { hasAllPrivilege, hasExecuteActionsCapability } from '../../../lib/capabilities'; import { getAlertingSectionBreadcrumb, getRuleDetailsBreadcrumb } from '../../../lib/breadcrumb'; import { getCurrentDocTitle } from '../../../lib/doc_title'; @@ -38,6 +36,7 @@ import { ActionType, ActionConnector, TriggersActionsUiConfig, + RuleTableItem, } from '../../../../types'; import { ComponentOpts as BulkOperationsComponentOpts, @@ -55,6 +54,7 @@ import { useKibana } from '../../../../common/lib/kibana'; import { ruleReducer } from '../../rule_form/rule_reducer'; import { loadAllActions as loadConnectors } from '../../../lib/action_connector_api'; import { triggersActionsUiConfig } from '../../../../common/lib/config_api'; +import { RuleStatusDropdown } from '../../rules_list/components/rule_status_dropdown'; export type RuleDetailsProps = { rule: Rule; @@ -62,7 +62,7 @@ export type RuleDetailsProps = { actionTypes: ActionType[]; requestRefresh: () => Promise; refreshToken?: number; -} & Pick; +} & Pick; export const RuleDetails: React.FunctionComponent = ({ rule, @@ -70,8 +70,8 @@ export const RuleDetails: React.FunctionComponent = ({ actionTypes, disableRule, enableRule, - unmuteRule, - muteRule, + snoozeRule, + unsnoozeRule, requestRefresh, refreshToken, }) => { @@ -150,13 +150,7 @@ export const RuleDetails: React.FunctionComponent = ({ const ruleActions = rule.actions; const uniqueActions = Array.from(new Set(ruleActions.map((item: any) => item.actionTypeId))); - const [isEnabled, setIsEnabled] = useState(rule.enabled); - const [isEnabledUpdating, setIsEnabledUpdating] = useState(false); - const [isMutedUpdating, setIsMutedUpdating] = useState(false); - const [isMuted, setIsMuted] = useState(rule.muteAll); const [editFlyoutVisible, setEditFlyoutVisibility] = useState(false); - const [dismissRuleErrors, setDismissRuleErrors] = useState(false); - const [dismissRuleWarning, setDismissRuleWarning] = useState(false); // Check whether interval is below configured minium useEffect(() => { @@ -269,6 +263,96 @@ export const RuleDetails: React.FunctionComponent = ({ values={{ ruleName: rule.name }} /> } + description={ + + + + + +

+ +

+
+
+ + await disableRule(rule)} + enableRule={async () => await enableRule(rule)} + snoozeRule={async (snoozeEndTime: string | -1) => + await snoozeRule(rule, snoozeEndTime) + } + unsnoozeRule={async () => await unsnoozeRule(rule)} + item={rule as RuleTableItem} + onRuleChanged={requestRefresh} + direction="row" + isEditable={hasEditButton} + previousSnoozeInterval={null} + /> + +
+
+ + + + +

+ +

+
+
+ + {ruleType.name} + +
+
+ + {uniqueActions && uniqueActions.length ? ( + + + + {' '} + {hasActionsWithBrokenConnector && ( + + )} + + + + + {uniqueActions.map((action, index) => ( + + + {actionTypesByTypeId[action].name ?? action} + + + ))} + + + + ) : null} + +
+ } rightSideItems={[ , = ({ /> - - - -

- -

-
- - {ruleType.name} -
- - {uniqueActions && uniqueActions.length ? ( - <> - - {' '} - {hasActionsWithBrokenConnector && ( - - )} - - - - - {uniqueActions.map((action, index) => ( - - - {actionTypesByTypeId[action].name ?? action} - - - ))} - - - ) : null} - - - - - - {isEnabledUpdating ? ( - - - - - - - - - - - - ) : ( - { - setIsEnabledUpdating(true); - if (isEnabled) { - setIsEnabled(false); - await disableRule(rule); - // Reset dismiss if previously clicked - setDismissRuleErrors(false); - } else { - setIsEnabled(true); - await enableRule(rule); - } - requestRefresh(); - setIsEnabledUpdating(false); - }} - label={ - - } - /> - )} - - - {isMutedUpdating ? ( - - - - - - - - - - - - ) : ( - { - setIsMutedUpdating(true); - if (isMuted) { - setIsMuted(false); - await unmuteRule(rule); - } else { - setIsMuted(true); - await muteRule(rule); - } - requestRefresh(); - setIsMutedUpdating(false); - }} - label={ - - } - /> - )} - - - -
- {rule.enabled && !dismissRuleErrors && rule.executionStatus.status === 'error' ? ( + {rule.enabled && + rule.executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License ? ( - - + +

+ +   + {getRuleStatusErrorReasonText()},  {rule.executionStatus.error?.message} - - - - - setDismissRuleErrors(true)} - > - - - - {rule.executionStatus.error?.reason === - AlertExecutionStatusErrorReasons.License && ( - - - - - - )} - +   + + + +

) : null} - {rule.enabled && !dismissRuleWarning && rule.executionStatus.status === 'warning' ? ( + {rule.enabled && rule.executionStatus.status === 'warning' ? ( - +

+ +   + {getRuleStatusWarningReasonText()} +   {rule.executionStatus.warning?.message} - - - - - setDismissRuleWarning(true)} - > - - - - +

@@ -521,89 +427,41 @@ export const RuleDetails: React.FunctionComponent = ({ color="warning" data-test-subj="actionWithBrokenConnectorWarningBanner" size="s" - title={i18n.translate( - 'xpack.triggersActionsUI.sections.ruleDetails.actionWithBrokenConnectorWarningBannerTitle', - { - defaultMessage: - 'There is an issue with one of the connectors associated with this rule.', - } - )} > - {hasEditButton && ( - - - setEditFlyoutVisibility(true)} - > - - - - - )} +

+ +   + +   + {hasEditButton && ( + setEditFlyoutVisibility(true)} + > + + + )} +

)} - {rule.enabled ? ( - - ) : ( - <> - - - - - - } - body={ - <> -

- -

- - } - actions={[ - { - setIsEnabledUpdating(true); - setIsEnabled(true); - await enableRule(rule); - requestRefresh(); - setIsEnabledUpdating(false); - }} - > - Enable - , - ]} - /> -
- - )} +
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx new file mode 100644 index 0000000000000..e37f9abf67de3 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.test.tsx @@ -0,0 +1,312 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; +import { useKibana } from '../../../../common/lib/kibana'; + +import { EuiSuperDatePicker } from '@elastic/eui'; +import { Rule } from '../../../../types'; +import { RuleErrorLog } from './rule_error_log'; + +const useKibanaMock = useKibana as jest.Mocked; +jest.mock('../../../../common/lib/kibana'); + +const mockLogResponse: any = { + total: 8, + data: [], + totalErrors: 12, + errors: [ + { + id: '66b9c04a-d5d3-4ed4-aa7c-94ddaca3ac1d', + timestamp: '2022-03-31T18:03:33.133Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '14fcfe1c-5403-458f-8549-fa8ef59cdea3', + timestamp: '2022-03-31T18:02:30.119Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: 'd53a401e-2a3a-4abe-8913-26e08a5039fd', + timestamp: '2022-03-31T18:01:27.112Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '9cfeae08-24b4-4d5c-b870-a303418f14d6', + timestamp: '2022-03-31T18:00:24.113Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '66b9c04a-d5d3-4ed4-aa7c-94ddaca3ac23', + timestamp: '2022-03-31T18:03:21.133Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '14fcfe1c-5403-458f-8549-fa8ef59cde18', + timestamp: '2022-03-31T18:02:18.119Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: 'd53a401e-2a3a-4abe-8913-26e08a503915', + timestamp: '2022-03-31T18:01:15.112Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '9cfeae08-24b4-4d5c-b870-a303418f1412', + timestamp: '2022-03-31T18:00:12.113Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '66b9c04a-d5d3-4ed4-aa7c-94ddaca3ac09', + timestamp: '2022-03-31T18:03:09.133Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '14fcfe1c-5403-458f-8549-fa8ef59cde06', + timestamp: '2022-03-31T18:02:06.119Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: 'd53a401e-2a3a-4abe-8913-26e08a503903', + timestamp: '2022-03-31T18:01:03.112Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + { + id: '9cfeae08-24b4-4d5c-b870-a303418f1400', + timestamp: '2022-03-31T18:00:00.113Z', + type: 'alerting', + message: + "rule execution failure: .es-query:d87fcbd0-b11b-11ec-88f6-293354dba871: 'Mine' - x_content_parse_exception: [parsing_exception] Reason: unknown query [match_allxxxx] did you mean [match_all]?", + }, + ], +}; + +const mockRule: Rule = { + id: '56b61397-13d7-43d0-a583-0fa8c704a46f', + enabled: true, + name: 'rule-56b61397-13d7-43d0-a583-0fa8c704a46f', + tags: [], + ruleTypeId: '.noop', + consumer: 'consumer', + schedule: { interval: '1m' }, + actions: [], + params: {}, + createdBy: null, + updatedBy: null, + createdAt: new Date(), + updatedAt: new Date(), + apiKeyOwner: null, + throttle: null, + notifyWhen: null, + muteAll: false, + mutedInstanceIds: [], + executionStatus: { + status: 'unknown', + lastExecutionDate: new Date('2020-08-20T19:23:38Z'), + }, +}; + +const loadExecutionLogAggregationsMock = jest.fn(); + +describe('rule_error_log', () => { + beforeEach(() => { + jest.clearAllMocks(); + useKibanaMock().services.uiSettings.get = jest.fn().mockImplementation((value: string) => { + if (value === 'timepicker:quickRanges') { + return [ + { + from: 'now-15m', + to: 'now', + display: 'Last 15 minutes', + }, + ]; + } + }); + loadExecutionLogAggregationsMock.mockResolvedValue(mockLogResponse); + }); + + it('renders correctly', async () => { + const nowMock = jest.spyOn(Date, 'now').mockReturnValue(0); + const wrapper = mountWithIntl( + + ); + + // No data initially + expect(wrapper.find('.euiTableRow .euiTableCellContent__text').first().text()).toEqual( + 'No items found' + ); + + // Run the initial load fetch call + expect(loadExecutionLogAggregationsMock).toHaveBeenCalledTimes(1); + + expect(loadExecutionLogAggregationsMock).toHaveBeenCalledWith( + expect.objectContaining({ + dateEnd: '1969-12-31T19:00:00-05:00', + dateStart: '1969-12-30T19:00:00-05:00', + id: '56b61397-13d7-43d0-a583-0fa8c704a46f', + page: 0, + perPage: 1, + sort: { timestamp: { order: 'desc' } }, + }) + ); + + // Loading + expect(wrapper.find(EuiSuperDatePicker).props().isLoading).toBeTruthy(); + + expect(wrapper.find('[data-test-subj="tableHeaderCell_timestamp_0"]').exists()).toBeTruthy(); + + // Let the load resolve + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find(EuiSuperDatePicker).props().isLoading).toBeFalsy(); + expect(wrapper.find('.euiTableRow').length).toEqual(10); + + nowMock.mockRestore(); + }); + + it('can sort on timestamp columns', async () => { + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + expect( + wrapper.find('.euiTableRow').first().find('.euiTableCellContent').first().text() + ).toEqual('Mar 31, 2022 @ 14:03:33.133'); + + wrapper.find('button[data-test-subj="tableHeaderSortButton"]').first().simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect( + wrapper.find('.euiTableRow').first().find('.euiTableCellContent').first().text() + ).toEqual('Mar 31, 2022 @ 14:00:00.113'); + }); + + it('can paginate', async () => { + loadExecutionLogAggregationsMock.mockResolvedValue({ + ...mockLogResponse, + total: 100, + }); + + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find('.euiPagination').exists()).toBeTruthy(); + + // Paginate to the next page + wrapper.find('[data-test-subj="pagination-button-next"]').first().simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find('.euiTableRow').length).toEqual(2); + }); + + it('can filter by start and end date', async () => { + const nowMock = jest.spyOn(Date, 'now').mockReturnValue(0); + + const wrapper = mountWithIntl( + + ); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(loadExecutionLogAggregationsMock).toHaveBeenLastCalledWith( + expect.objectContaining({ + dateEnd: '1969-12-31T19:00:00-05:00', + dateStart: '1969-12-30T19:00:00-05:00', + id: '56b61397-13d7-43d0-a583-0fa8c704a46f', + page: 0, + perPage: 1, + sort: { timestamp: { order: 'desc' } }, + }) + ); + + wrapper + .find('[data-test-subj="superDatePickerToggleQuickMenuButton"] button') + .simulate('click'); + + wrapper + .find('[data-test-subj="superDatePickerCommonlyUsed_Last_15 minutes"] button') + .simulate('click'); + + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(loadExecutionLogAggregationsMock).toHaveBeenLastCalledWith( + expect.objectContaining({ + dateStart: '1969-12-31T18:45:00-05:00', + dateEnd: '1969-12-31T19:00:00-05:00', + id: '56b61397-13d7-43d0-a583-0fa8c704a46f', + page: 0, + perPage: 1, + sort: { timestamp: { order: 'desc' } }, + }) + ); + + nowMock.mockRestore(); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx new file mode 100644 index 0000000000000..e47c65ff4e3e9 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx @@ -0,0 +1,266 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react'; +import { i18n } from '@kbn/i18n'; +import datemath from '@elastic/datemath'; +import { + EuiFlexItem, + EuiFlexGroup, + EuiProgress, + EuiSpacer, + Pagination, + EuiSuperDatePicker, + OnTimeChangeProps, + EuiBasicTable, + EuiTableSortingType, + EuiBasicTableColumn, +} from '@elastic/eui'; +import { useKibana } from '../../../../common/lib/kibana'; + +import { LoadExecutionLogAggregationsProps } from '../../../lib/rule_api'; +import { Rule } from '../../../../types'; +import { IExecutionErrors } from '../../../../../../alerting/common'; +import { + ComponentOpts as RuleApis, + withBulkRuleOperations, +} from '../../common/components/with_bulk_rule_api_operations'; +import { RuleEventLogListCellRenderer } from './rule_event_log_list_cell_renderer'; + +const getParsedDate = (date: string) => { + if (date.includes('now')) { + return datemath.parse(date)?.format() || date; + } + return date; +}; + +const API_FAILED_MESSAGE = i18n.translate( + 'xpack.triggersActionsUI.sections.ruleDetails.errorLogColumn.apiError', + { + defaultMessage: 'Failed to fetch error log', + } +); + +const updateButtonProps = { + iconOnly: true, + fill: false, +}; + +const sortErrorLog = ( + a: IExecutionErrors, + b: IExecutionErrors, + direction: 'desc' | 'asc' = 'desc' +) => + direction === 'desc' + ? new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime() + : new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime(); + +export type RuleErrorLogProps = { + rule: Rule; + refreshToken?: number; + requestRefresh?: () => Promise; +} & Pick; + +export const RuleErrorLog = (props: RuleErrorLogProps) => { + const { rule, loadExecutionLogAggregations, refreshToken } = props; + + const { uiSettings, notifications } = useKibana().services; + + // Data grid states + const [logs, setLogs] = useState([]); + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 10, + totalItemCount: 0, + }); + const [sort, setSort] = useState['sort']>({ + field: 'timestamp', + direction: 'desc', + }); + + // Date related states + const [isLoading, setIsLoading] = useState(false); + const [dateStart, setDateStart] = useState('now-24h'); + const [dateEnd, setDateEnd] = useState('now'); + const [dateFormat] = useState(() => uiSettings?.get('dateFormat')); + const [commonlyUsedRanges] = useState(() => { + return ( + uiSettings + ?.get('timepicker:quickRanges') + ?.map(({ from, to, display }: { from: string; to: string; display: string }) => ({ + start: from, + end: to, + label: display, + })) || [] + ); + }); + + const isInitialized = useRef(false); + + const loadEventLogs = async () => { + setIsLoading(true); + try { + const result = await loadExecutionLogAggregations({ + id: rule.id, + sort: { + [sort?.field || 'timestamp']: { order: sort?.direction || 'desc' }, + } as unknown as LoadExecutionLogAggregationsProps['sort'], + dateStart: getParsedDate(dateStart), + dateEnd: getParsedDate(dateEnd), + page: 0, + perPage: 1, + }); + setLogs(result.errors); + setPagination({ + ...pagination, + totalItemCount: result.totalErrors, + }); + } catch (e) { + notifications.toasts.addDanger({ + title: API_FAILED_MESSAGE, + text: e.body.message, + }); + } + setIsLoading(false); + }; + + const onTimeChange = useCallback( + ({ start, end, isInvalid }: OnTimeChangeProps) => { + if (isInvalid) { + return; + } + setDateStart(start); + setDateEnd(end); + }, + [setDateStart, setDateEnd] + ); + + const onRefresh = () => { + loadEventLogs(); + }; + + const columns: Array> = useMemo( + () => [ + { + field: 'timestamp', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.ruleDetails.errorLogColumn.timestamp', + { + defaultMessage: 'Timestamp', + } + ), + render: (date: string) => ( + + ), + sortable: true, + width: '250px', + }, + { + field: 'type', + name: i18n.translate('xpack.triggersActionsUI.sections.ruleDetails.errorLogColumn.type', { + defaultMessage: 'Type', + }), + sortable: false, + width: '100px', + }, + { + field: 'message', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.ruleDetails.errorLogColumn.message', + { + defaultMessage: 'Message', + } + ), + sortable: false, + }, + ], + [dateFormat] + ); + + const logList = useMemo(() => { + const start = pagination.pageIndex * pagination.pageSize; + const logsSortDesc = logs.sort((a, b) => sortErrorLog(a, b, sort?.direction)); + return logsSortDesc.slice(start, start + pagination.pageSize); + }, [logs, pagination.pageIndex, pagination.pageSize, sort?.direction]); + + useEffect(() => { + loadEventLogs(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dateStart, dateEnd]); + + useEffect(() => { + if (isInitialized.current) { + loadEventLogs(); + } + isInitialized.current = true; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [refreshToken]); + + return ( +
+ + + + + + + + {isLoading && ( + + )} + { + if (changedPage) { + setPagination((prevPagination) => { + if ( + prevPagination.pageIndex !== changedPage.index || + prevPagination.pageSize !== changedPage.size + ) { + return { + ...prevPagination, + pageIndex: changedPage.index, + pageSize: changedPage.size, + }; + } + return prevPagination; + }); + } + if (changedSort) { + setSort((prevSort) => { + if (prevSort?.direction !== changedSort.direction) { + return changedSort; + } + return prevSort; + }); + } + }} + /> +
+ ); +}; + +export const RuleErrorLogWithApi = withBulkRuleOperations(RuleErrorLog); + +// eslint-disable-next-line import/no-default-export +export { RuleErrorLogWithApi as default }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx index 7b9ade9b5f192..cc3bb0b20a203 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useEffect, useState, useMemo } from 'react'; +import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react'; import { i18n } from '@kbn/i18n'; import datemath from '@elastic/datemath'; import { @@ -233,6 +233,8 @@ const updateButtonProps = { export type RuleEventLogListProps = { rule: Rule; localStorageKey?: string; + refreshToken?: number; + requestRefresh?: () => Promise; } & Pick; export const RuleEventLogList = (props: RuleEventLogListProps) => { @@ -240,6 +242,7 @@ export const RuleEventLogList = (props: RuleEventLogListProps) => { rule, localStorageKey = RULE_EVENT_LOG_LIST_STORAGE_KEY, loadExecutionLogAggregations, + refreshToken, } = props; const { uiSettings, notifications } = useKibana().services; @@ -277,6 +280,8 @@ export const RuleEventLogList = (props: RuleEventLogListProps) => { ); }); + const isInitialized = useRef(false); + // Main cell renderer, renders durations, statuses, etc. const renderCell = ({ rowIndex, columnId }: EuiDataGridCellValueElementProps) => { const { pageIndex, pageSize } = pagination; @@ -406,6 +411,14 @@ export const RuleEventLogList = (props: RuleEventLogListProps) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [sortingColumns, dateStart, dateEnd, filter, pagination.pageIndex, pagination.pageSize]); + useEffect(() => { + if (isInitialized.current) { + loadEventLogs(); + } + isInitialized.current = true; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [refreshToken]); + useEffect(() => { localStorage.setItem(localStorageKey, JSON.stringify(visibleColumns)); }, [localStorageKey, visibleColumns]); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.tsx index 393cdc404db9e..3e11f987138d2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.tsx @@ -77,6 +77,7 @@ export const RuleRoute: React.FunctionComponent = ({ return ruleSummary ? ( & diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx index 72e4acc2e64fe..098d7c08a78f5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_dropdown.tsx @@ -45,6 +45,7 @@ export interface ComponentOpts { unsnoozeRule: () => Promise; isEditable: boolean; previousSnoozeInterval: string | null; + direction?: 'column' | 'row'; } const COMMON_SNOOZE_TIMES: Array<[number, SnoozeUnit]> = [ @@ -63,6 +64,7 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ unsnoozeRule, isEditable, previousSnoozeInterval, + direction = 'column', }: ComponentOpts) => { const [isEnabled, setIsEnabled] = useState(item.enabled); const [isSnoozed, setIsSnoozed] = useState(isItemSnoozed(item)); @@ -80,6 +82,9 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ const onChangeEnabledStatus = useCallback( async (enable: boolean) => { + if (item.enabled === enable) { + return; + } setIsUpdating(true); try { if (enable) { @@ -93,7 +98,7 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ setIsUpdating(false); } }, - [setIsUpdating, isEnabled, setIsEnabled, onRuleChanged, enableRule, disableRule] + [item.enabled, isEnabled, onRuleChanged, enableRule, disableRule] ); const onChangeSnooze = useCallback( async (value: number, unit?: SnoozeUnit) => { @@ -152,10 +157,11 @@ export const RuleStatusDropdown: React.FunctionComponent = ({ return ( {isEditable ? ( @@ -279,7 +285,7 @@ const RuleStatusMenu: React.FunctionComponent = ({ }, ]; - return ; + return ; }; interface SnoozePanelProps { @@ -340,7 +346,6 @@ const SnoozePanel: React.FunctionComponent = ({ ); - return ( @@ -374,7 +379,7 @@ const SnoozePanel: React.FunctionComponent = ({ /> - + {i18n.translate('xpack.triggersActionsUI.sections.rulesList.applySnooze', { defaultMessage: 'Apply', })} @@ -405,7 +410,7 @@ const SnoozePanel: React.FunctionComponent = ({ - + {i18n.translate('xpack.triggersActionsUI.sections.rulesList.snoozeIndefinitely', { defaultMessage: 'Snooze indefinitely', })} @@ -417,7 +422,7 @@ const SnoozePanel: React.FunctionComponent = ({ - + Cancel snooze diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_filter.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_filter.tsx index 185d18f605d42..65a4654b6ac29 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_filter.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rule_status_filter.tsx @@ -15,8 +15,8 @@ import { EuiHealth, } from '@elastic/eui'; import { - AlertExecutionStatuses, - AlertExecutionStatusValues, + RuleExecutionStatuses, + RuleExecutionStatusValues, } from '../../../../../../alerting/common'; import { rulesStatusesTranslationsMapping } from '../translations'; @@ -65,7 +65,7 @@ export const RuleStatusFilter: React.FunctionComponent = } >
- {[...AlertExecutionStatusValues].sort().map((item: AlertExecutionStatuses) => { + {[...RuleExecutionStatusValues].sort().map((item: RuleExecutionStatuses) => { const healthColor = getHealthColor(item); return ( = ); }; -export function getHealthColor(status: AlertExecutionStatuses) { +export function getHealthColor(status: RuleExecutionStatuses) { switch (status) { case 'active': return 'success'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx index a018b73eeeed9..7a73919b4dfec 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.test.tsx @@ -14,8 +14,8 @@ import { ruleTypeRegistryMock } from '../../../rule_type_registry.mock'; import { RulesList, percentileFields } from './rules_list'; import { RuleTypeModel, ValidationResult, Percentiles } from '../../../../types'; import { - AlertExecutionStatusErrorReasons, - AlertExecutionStatusWarningReasons, + RuleExecutionStatusErrorReasons, + RuleExecutionStatusWarningReasons, ALERTS_FEATURE_ID, parseDuration, } from '../../../../../../alerting/common'; @@ -305,7 +305,7 @@ describe('rules_list component with items', () => { lastDuration: 122000, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { - reason: AlertExecutionStatusErrorReasons.Unknown, + reason: RuleExecutionStatusErrorReasons.Unknown, message: 'test', }, }, @@ -331,7 +331,7 @@ describe('rules_list component with items', () => { lastDuration: 500, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), error: { - reason: AlertExecutionStatusErrorReasons.License, + reason: RuleExecutionStatusErrorReasons.License, message: 'test', }, }, @@ -357,7 +357,7 @@ describe('rules_list component with items', () => { lastDuration: 500, lastExecutionDate: new Date('2020-08-20T19:23:38Z'), warning: { - reason: AlertExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, + reason: RuleExecutionStatusWarningReasons.MAX_EXECUTABLE_ACTIONS, message: 'test', }, }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx index 9d56462670b67..fa74c957d35e4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx @@ -79,10 +79,10 @@ import { routeToRuleDetails, DEFAULT_SEARCH_PAGE_SIZE } from '../../../constants import { DeleteModalConfirmation } from '../../../components/delete_modal_confirmation'; import { EmptyPrompt } from '../../../components/prompts/empty_prompt'; import { - AlertExecutionStatus, - AlertExecutionStatusValues, + RuleExecutionStatus, + RuleExecutionStatusValues, ALERTS_FEATURE_ID, - AlertExecutionStatusErrorReasons, + RuleExecutionStatusErrorReasons, formatDuration, parseDuration, MONITORING_HISTORY_LIMIT, @@ -191,7 +191,7 @@ export const RulesList: React.FunctionComponent = () => { ruleTypeId: string; } | null>(null); const [rulesStatusesTotal, setRulesStatusesTotal] = useState>( - AlertExecutionStatusValues.reduce( + RuleExecutionStatusValues.reduce( (prev: Record, status: string) => ({ ...prev, @@ -366,15 +366,12 @@ export const RulesList: React.FunctionComponent = () => { ); }; - const renderAlertExecutionStatus = ( - executionStatus: AlertExecutionStatus, - item: RuleTableItem - ) => { + const renderRuleExecutionStatus = (executionStatus: RuleExecutionStatus, item: RuleTableItem) => { const healthColor = getHealthColor(executionStatus.status); const tooltipMessage = executionStatus.status === 'error' ? `Error: ${executionStatus?.error?.message}` : null; const isLicenseError = - executionStatus.error?.reason === AlertExecutionStatusErrorReasons.License; + executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License; const statusMessage = isLicenseError ? ALERT_STATUS_LICENSE_ERROR : rulesStatusesTranslationsMapping[executionStatus.status]; @@ -468,11 +465,11 @@ export const RulesList: React.FunctionComponent = () => { }; }; - const buildErrorListItems = (_executionStatus: AlertExecutionStatus) => { + const buildErrorListItems = (_executionStatus: RuleExecutionStatus) => { const hasErrorMessage = _executionStatus.status === 'error'; const errorMessage = _executionStatus?.error?.message; const isLicenseError = - _executionStatus.error?.reason === AlertExecutionStatusErrorReasons.License; + _executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License; const statusMessage = isLicenseError ? ALERT_STATUS_LICENSE_ERROR : null; return [ @@ -494,7 +491,7 @@ export const RulesList: React.FunctionComponent = () => { ]; }; - const toggleErrorMessage = (_executionStatus: AlertExecutionStatus, ruleItem: RuleTableItem) => { + const toggleErrorMessage = (_executionStatus: RuleExecutionStatus, ruleItem: RuleTableItem) => { setItemIdToExpandedRowMap((itemToExpand) => { const _itemToExpand = { ...itemToExpand }; if (_itemToExpand[ruleItem.id]) { @@ -828,13 +825,16 @@ export const RulesList: React.FunctionComponent = () => { truncateText: false, width: '120px', 'data-test-subj': 'rulesTableCell-lastResponse', - render: (_executionStatus: AlertExecutionStatus, item: RuleTableItem) => { - return renderAlertExecutionStatus(item.executionStatus, item); + render: (_executionStatus: RuleExecutionStatus, item: RuleTableItem) => { + return renderRuleExecutionStatus(item.executionStatus, item); }, }, { field: 'enabled', - name: '', + name: i18n.translate( + 'xpack.triggersActionsUI.sections.rulesList.rulesListTable.columns.triggerActionsTitle', + { defaultMessage: 'Trigger actions' } + ), sortable: true, truncateText: false, width: '10%', @@ -917,7 +917,7 @@ export const RulesList: React.FunctionComponent = () => { const _executionStatus = item.executionStatus; const hasErrorMessage = _executionStatus.status === 'error'; const isLicenseError = - _executionStatus.error?.reason === AlertExecutionStatusErrorReasons.License; + _executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License; return isLicenseError || hasErrorMessage ? ( ` // so the `Params` is a black-box of Record type SanitizedRule = Omit< - SanitizedAlert, + AlertingSanitizedRule, 'alertTypeId' > & { - ruleTypeId: SanitizedAlert['alertTypeId']; + ruleTypeId: AlertingSanitizedRule['alertTypeId']; }; type Rule = SanitizedRule; type ResolvedRule = Omit, 'alertTypeId'> & { ruleTypeId: ResolvedSanitizedRule['alertTypeId']; }; -type RuleAggregations = Omit & { - ruleExecutionStatus: AlertAggregations['alertExecutionStatus']; +type RuleAggregations = Omit & { + ruleExecutionStatus: AlertingRuleAggregations['alertExecutionStatus']; }; export type { @@ -120,7 +120,7 @@ export enum RuleFlyoutCloseReason { export interface ActionParamsProps { actionParams: Partial; index: number; - editAction: (key: string, value: AlertActionParam, index: number) => void; + editAction: (key: string, value: RuleActionParam, index: number) => void; errors: IErrorObject; messageVariables?: ActionVariable[]; defaultMessage?: string; diff --git a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts index fb4879fa9ba39..c27d14b70c33f 100644 --- a/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts +++ b/x-pack/plugins/triggers_actions_ui/server/data/lib/time_series_query.test.ts @@ -29,7 +29,7 @@ const DefaultQueryParams: TimeSeriesQuery = { }; describe('timeSeriesQuery', () => { - const esClient = alertsMock.createAlertServices().scopedClusterClient.asCurrentUser; + const esClient = alertsMock.createRuleExecutorServices().scopedClusterClient.asCurrentUser; const logger = loggingSystemMock.create().get() as jest.Mocked; const params = { logger, diff --git a/x-pack/plugins/uptime/public/state/api/alerts.ts b/x-pack/plugins/uptime/public/state/api/alerts.ts index d19b9688b21d0..49df4f390611b 100644 --- a/x-pack/plugins/uptime/public/state/api/alerts.ts +++ b/x-pack/plugins/uptime/public/state/api/alerts.ts @@ -12,7 +12,7 @@ import { ActionConnector } from '../alerts/alerts'; import { AlertsResult, MonitorIdParam } from '../actions/types'; import type { ActionType, AsApiContract, Rule } from '../../../../triggers_actions_ui/public'; import { API_URLS } from '../../../common/constants'; -import { AlertTypeParams } from '../../../../alerting/common'; +import { RuleTypeParams } from '../../../../alerting/common'; import { AtomicStatusCheckParams } from '../../../common/runtime_types/alerts'; import { populateAlertActions, RuleAction } from './alert_actions'; @@ -42,7 +42,7 @@ export const fetchConnectors = async (): Promise => { ); }; -export interface NewAlertParams extends AlertTypeParams { +export interface NewAlertParams extends RuleTypeParams { selectedMonitor: Ping; defaultActions: ActionConnector[]; defaultEmail?: DefaultEmail; diff --git a/x-pack/plugins/uptime/server/lib/alerts/test_utils/index.ts b/x-pack/plugins/uptime/server/lib/alerts/test_utils/index.ts index 374719172405f..e1a5da32c5fe4 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/test_utils/index.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/test_utils/index.ts @@ -61,7 +61,7 @@ export const createRuleTypeMocks = ( const services = { ...getUptimeESMockClient(), - ...alertsMock.createAlertServices(), + ...alertsMock.createRuleExecutorServices(), alertWithLifecycle: jest.fn().mockReturnValue({ scheduleActions, replaceState }), getAlertStartedDate: jest.fn().mockReturnValue('2022-03-17T13:13:33.755Z'), logger: loggerMock, diff --git a/x-pack/plugins/uptime/server/lib/alerts/types.ts b/x-pack/plugins/uptime/server/lib/alerts/types.ts index 5275cddae9d24..b100965db7a73 100644 --- a/x-pack/plugins/uptime/server/lib/alerts/types.ts +++ b/x-pack/plugins/uptime/server/lib/alerts/types.ts @@ -7,7 +7,7 @@ import { UptimeCorePluginsSetup, UptimeServerSetup } from '../adapters'; import { UMServerLibs } from '../lib'; import { AlertTypeWithExecutor } from '../../../../rule_registry/server'; -import { AlertInstanceContext, AlertTypeState } from '../../../../alerting/common'; +import { AlertInstanceContext, RuleTypeState } from '../../../../alerting/common'; import { LifecycleAlertService } from '../../../../rule_registry/server'; /** @@ -21,11 +21,7 @@ export type DefaultUptimeAlertInstance = AlertTy Record, AlertInstanceContext, { - alertWithLifecycle: LifecycleAlertService< - AlertTypeState, - AlertInstanceContext, - TActionGroupIds - >; + alertWithLifecycle: LifecycleAlertService; getAlertStartedDate: (alertId: string) => string | null; } >; diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts index dd37f0cc8b67e..9acc0d791b886 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/alerts/server/alert_types.ts @@ -14,8 +14,8 @@ import { RuleType, AlertInstanceState, AlertInstanceContext, - AlertTypeState, - AlertTypeParams, + RuleTypeState, + RuleTypeParams, } from '../../../../../../../plugins/alerting/server'; export const EscapableStrings = { @@ -53,7 +53,7 @@ function getAlwaysFiringAlertType() { groupsToScheduleActionsInSeries: schema.maybe(schema.arrayOf(schema.nullable(schema.string()))), }); type ParamsType = TypeOf; - interface State extends AlertTypeState { + interface State extends RuleTypeState { groupInSeriesIndex?: number; } interface InstanceState extends AlertInstanceState { @@ -63,7 +63,7 @@ function getAlwaysFiringAlertType() { instanceContextValue: boolean; } const result: RuleType< - ParamsType & AlertTypeParams, + ParamsType & RuleTypeParams, never, // Only use if defining useSavedObjectReferences hook State, InstanceState, @@ -153,7 +153,7 @@ async function alwaysFiringExecutor(alertExecutorOptions: any) { } function getCumulativeFiringAlertType() { - interface State extends AlertTypeState { + interface State extends RuleTypeState { runCount?: number; } interface InstanceState extends AlertInstanceState { @@ -197,7 +197,7 @@ function getNeverFiringAlertType() { reference: schema.string(), }); type ParamsType = TypeOf; - interface State extends AlertTypeState { + interface State extends RuleTypeState { globalStateValue: boolean; } const result: RuleType = { @@ -401,7 +401,7 @@ function getPatternFiringAlertType() { reference: schema.maybe(schema.string()), }); type ParamsType = TypeOf; - interface State extends AlertTypeState { + interface State extends RuleTypeState { patternIndex?: number; } const result: RuleType = { @@ -470,7 +470,7 @@ function getPatternSuccessOrFailureAlertType() { pattern: schema.arrayOf(schema.oneOf([schema.boolean(), schema.string()])), }); type ParamsType = TypeOf; - interface State extends AlertTypeState { + interface State extends RuleTypeState { patternIndex?: number; } const result: RuleType = { @@ -510,7 +510,7 @@ function getLongRunningPatternRuleType(cancelAlertsOnRuleTimeout: boolean = true pattern: schema.arrayOf(schema.boolean()), }); type ParamsType = TypeOf; - interface State extends AlertTypeState { + interface State extends RuleTypeState { patternIndex?: number; } const result: RuleType = { @@ -675,23 +675,32 @@ export function defineAlertTypes( throw new Error('this alert is intended to fail'); }, }; - const longRunningAlertType: RuleType<{}, {}, {}, {}, {}, 'default'> = { - id: 'test.longRunning', - name: 'Test: Long Running', - actionGroups: [ - { - id: 'default', - name: 'Default', + function getLongRunningRuleType() { + const paramsSchema = schema.object({ + delay: schema.maybe(schema.number({ defaultValue: 5000 })), + }); + type ParamsType = TypeOf; + + const result: RuleType = { + id: 'test.longRunning', + name: 'Test: Long Running', + actionGroups: [ + { + id: 'default', + name: 'Default', + }, + ], + producer: 'alertsFixture', + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + async executor(ruleExecutorOptions) { + const { params } = ruleExecutorOptions; + await new Promise((resolve) => setTimeout(resolve, params.delay ?? 5000)); }, - ], - producer: 'alertsFixture', - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - async executor() { - await new Promise((resolve) => setTimeout(resolve, 5000)); - }, - }; + }; + return result; + } const exampleAlwaysFiringAlertType: RuleType<{}, {}, {}, {}, {}, 'small' | 'medium' | 'large'> = { id: 'example.always-firing', name: 'Always firing', @@ -769,7 +778,7 @@ export function defineAlertTypes( alerting.registerType(onlyStateVariablesAlertType); alerting.registerType(getPatternFiringAlertType()); alerting.registerType(throwAlertType); - alerting.registerType(longRunningAlertType); + alerting.registerType(getLongRunningRuleType()); alerting.registerType(goldNoopAlertType); alerting.registerType(exampleAlwaysFiringAlertType); alerting.registerType(multipleSearchesRuleType); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts index dba73cba184dd..2eb33d95fa4ea 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/alerting/execution_status.ts @@ -6,7 +6,7 @@ */ import expect from '@kbn/expect'; -import { AlertExecutionStatusErrorReasons } from '../../../../../plugins/alerting/common'; +import { RuleExecutionStatusErrorReasons } from '../../../../../plugins/alerting/common'; import { Spaces } from '../../scenarios'; import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -54,7 +54,7 @@ export default function executionStatusAlertTests({ getService }: FtrProviderCon executionStatus = await waitForStatus(alertId, new Set(['error'])); expect(executionStatus.error).to.be.ok(); - expect(executionStatus.error.reason).to.be(AlertExecutionStatusErrorReasons.Decrypt); + expect(executionStatus.error.reason).to.be(RuleExecutionStatusErrorReasons.Decrypt); expect(executionStatus.error.message).to.be('Unable to decrypt attribute "apiKey"'); }); }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/telemetry/alerting_telemetry.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/telemetry/alerting_telemetry.ts index 3b768b563b999..2773d137f25a4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/telemetry/alerting_telemetry.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/telemetry/alerting_telemetry.ts @@ -176,13 +176,7 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider throttle: null, enabled: false, params: {}, - actions: [ - { - id: noopConnectorId, - group: 'default', - params: {}, - }, - ], + actions: [], }, }); @@ -190,20 +184,25 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider space: space.id, ruleOverwrites: { rule_type_id: 'test.multipleSearches', - schedule: { interval: '29s' }, + schedule: { interval: '40s' }, throttle: '1m', params: { numSearches: 2, delay: `2s` }, + actions: [], + }, + }); + + await createRule({ + space: space.id, + ruleOverwrites: { + rule_type_id: 'test.cumulative-firing', + schedule: { interval: '61s' }, + throttle: '2s', actions: [ { id: noopConnectorId, group: 'default', params: {}, }, - { - id: noopConnectorId, - group: 'default', - params: {}, - }, ], }, }); @@ -242,10 +241,10 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider const telemetry = JSON.parse(taskState!); // total number of rules - expect(telemetry.count_total).to.equal(18); + expect(telemetry.count_total).to.equal(21); // total number of enabled rules - expect(telemetry.count_active_total).to.equal(15); + expect(telemetry.count_active_total).to.equal(18); // total number of disabled rules expect(telemetry.count_disabled_total).to.equal(3); @@ -256,6 +255,7 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect(telemetry.count_by_type.test__throw).to.equal(3); expect(telemetry.count_by_type.test__noop).to.equal(6); expect(telemetry.count_by_type.test__multipleSearches).to.equal(3); + expect(telemetry.count_by_type['test__cumulative-firing']).to.equal(3); // total number of enabled rules broken down by rule type expect(telemetry.count_active_by_type.test__onlyContextVariables).to.equal(3); @@ -263,13 +263,14 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect(telemetry.count_active_by_type.test__throw).to.equal(3); expect(telemetry.count_active_by_type.test__noop).to.equal(3); expect(telemetry.count_active_by_type.test__multipleSearches).to.equal(3); + expect(telemetry.count_active_by_type['test__cumulative-firing']).to.equal(3); // throttle time stats expect(telemetry.throttle_time.min).to.equal('0s'); - expect(telemetry.throttle_time.avg).to.equal('138.2s'); + expect(telemetry.throttle_time.avg).to.equal('115.5s'); expect(telemetry.throttle_time.max).to.equal('600s'); expect(telemetry.throttle_time_number_s.min).to.equal(0); - expect(telemetry.throttle_time_number_s.avg).to.equal(138.2); + expect(telemetry.throttle_time_number_s.avg).to.equal(115.5); expect(telemetry.throttle_time_number_s.max).to.equal(600); // schedule interval stats @@ -281,8 +282,8 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect(telemetry.schedule_time_number_s.max).to.equal(300); // attached connectors stats - expect(telemetry.connectors_per_alert.min).to.equal(1); - expect(telemetry.connectors_per_alert.avg).to.equal(1.5); + expect(telemetry.connectors_per_alert.min).to.equal(0); + expect(telemetry.connectors_per_alert.avg).to.equal(1); expect(telemetry.connectors_per_alert.max).to.equal(3); // number of spaces with rules @@ -290,7 +291,7 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider // number of rule executions - just checking for non-zero as we can't set an exact number // each rule should have had a chance to execute once - expect(telemetry.count_rules_executions_per_day >= 18).to.be(true); + expect(telemetry.count_rules_executions_per_day >= 21).to.be(true); // number of rule executions broken down by rule type expect(telemetry.count_by_type.test__onlyContextVariables >= 3).to.be(true); @@ -298,6 +299,7 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect(telemetry.count_by_type.test__throw >= 3).to.be(true); expect(telemetry.count_by_type.test__noop >= 3).to.be(true); expect(telemetry.count_by_type.test__multipleSearches >= 3).to.be(true); + expect(telemetry.count_by_type['test__cumulative-firing'] >= 3).to.be(true); // average execution time - just checking for non-zero as we can't set an exact number expect(telemetry.avg_execution_time_per_day > 0).to.be(true); @@ -312,6 +314,9 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect(telemetry.avg_execution_time_by_type_per_day.test__throw > 0).to.be(true); expect(telemetry.avg_execution_time_by_type_per_day.test__noop > 0).to.be(true); expect(telemetry.avg_execution_time_by_type_per_day.test__multipleSearches > 0).to.be(true); + expect(telemetry.avg_execution_time_by_type_per_day['test__cumulative-firing'] > 0).to.be( + true + ); // average es search time - just checking for non-zero as we can't set an exact number expect(telemetry.avg_es_search_duration_per_day > 0).to.be(true); @@ -325,6 +330,9 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider ).to.be(true); expect(telemetry.avg_es_search_duration_by_type_per_day.test__throw === 0).to.be(true); expect(telemetry.avg_es_search_duration_by_type_per_day.test__noop === 0).to.be(true); + expect( + telemetry.avg_es_search_duration_by_type_per_day['test__cumulative-firing'] === 0 + ).to.be(true); // rule type that performs ES search expect(telemetry.avg_es_search_duration_by_type_per_day.test__multipleSearches > 0).to.be( @@ -343,6 +351,9 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider ).to.be(true); expect(telemetry.avg_total_search_duration_by_type_per_day.test__throw === 0).to.be(true); expect(telemetry.avg_total_search_duration_by_type_per_day.test__noop === 0).to.be(true); + expect( + telemetry.avg_total_search_duration_by_type_per_day['test__cumulative-firing'] === 0 + ).to.be(true); // rule type that performs ES search expect(telemetry.avg_total_search_duration_by_type_per_day.test__multipleSearches > 0).to.be( @@ -368,6 +379,70 @@ export default function createAlertingTelemetryTests({ getService }: FtrProvider expect( telemetry.count_failed_and_unrecognized_rule_tasks_by_status_by_type_per_day ).to.be.empty(); + + // percentile calculations for number of scheduled actions + expect(telemetry.percentile_num_scheduled_actions_per_day.p50 >= 0).to.be(true); + expect(telemetry.percentile_num_scheduled_actions_per_day.p90 > 0).to.be(true); + expect(telemetry.percentile_num_scheduled_actions_per_day.p99 > 0).to.be(true); + + // percentile calculations by rule type. most of these rule types don't schedule actions so they should all be 0 + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p50['example__always-firing'] + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p90['example__always-firing'] + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p99['example__always-firing'] + ).to.equal(0); + + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p50.test__onlyContextVariables + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p90.test__onlyContextVariables + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p99.test__onlyContextVariables + ).to.equal(0); + + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p50.test__noop).to.equal(0); + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p90.test__noop).to.equal(0); + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p99.test__noop).to.equal(0); + + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p50.test__throw).to.equal( + 0 + ); + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p90.test__throw).to.equal( + 0 + ); + expect(telemetry.percentile_num_scheduled_actions_by_type_per_day.p99.test__throw).to.equal( + 0 + ); + + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p50.test__multipleSearches + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p90.test__multipleSearches + ).to.equal(0); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p99.test__multipleSearches + ).to.equal(0); + + // this rule type does schedule actions so should be least 1 action scheduled + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p50['test__cumulative-firing'] >= + 1 + ).to.be(true); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p90['test__cumulative-firing'] >= + 1 + ).to.be(true); + expect( + telemetry.percentile_num_scheduled_actions_by_type_per_day.p99['test__cumulative-firing'] >= + 1 + ).to.be(true); }); }); } diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_execution_log.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_execution_log.ts index 17e2a4c395989..7b4463996edf3 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_execution_log.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/get_execution_log.ts @@ -126,6 +126,32 @@ export default function createGetExecutionLogTests({ getService }: FtrProviderCo expect(response.body.errors).to.eql([]); }); + it('gets execution log for rule that is currently running', async () => { + const { body: createdRule } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData({ rule_type_id: 'test.longRunning', params: { delay: 120000 } })) + .expect(200); + objectRemover.add(Spaces.space1.id, createdRule.id, 'rule', 'alerting'); + + // wait for execute-start event that signals rule has started running + await waitForEvents(createdRule.id, 'alerting', new Map([['execute-start', { gte: 1 }]])); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rule/${ + createdRule.id + }/_execution_log?date_start=${dateStart}` + ); + + expect(response.status).to.eql(200); + + // since these events should have been excluded from the agg, should return empty + expect(response.body.total).to.eql(0); + expect(response.body.data).to.eql([]); + expect(response.body.totalErrors).to.eql(0); + expect(response.body.errors).to.eql([]); + }); + it('gets execution log for rule that performs ES searches', async () => { const { body: createdRule } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts index 9bcce86b57fe6..23200cdab110a 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/migrations.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { getUrlPrefix } from '../../../common/lib'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import type { RawRule, RawAlertAction } from '../../../../../plugins/alerting/server/types'; +import type { RawRule, RawRuleAction } from '../../../../../plugins/alerting/server/types'; import { FILEBEAT_7X_INDICATOR_PATH } from '../../../../../plugins/alerting/server/saved_objects/migrations'; // eslint-disable-next-line import/no-default-export @@ -243,7 +243,7 @@ export default function createGetTests({ getService }: FtrProviderContext) { expect(searchResult.statusCode).to.equal(200); expect((searchResult.body.hits.total as estypes.SearchTotalHits).value).to.equal(1); const hit = searchResult.body.hits.hits[0]; - expect((hit!._source!.alert! as RawRule).actions! as RawAlertAction[]).to.eql([ + expect((hit!._source!.alert! as RawRule).actions! as RawRuleAction[]).to.eql([ { actionRef: 'action_0', actionTypeId: 'test.noop', diff --git a/x-pack/test/api_integration/apis/lens/field_stats.ts b/x-pack/test/api_integration/apis/lens/field_stats.ts index 5090fe14576d5..4d38b54b02252 100644 --- a/x-pack/test/api_integration/apis/lens/field_stats.ts +++ b/x-pack/test/api_integration/apis/lens/field_stats.ts @@ -17,6 +17,7 @@ const COMMON_HEADERS = { export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const supertest = getService('supertest'); describe('index stats apis', () => { @@ -29,10 +30,13 @@ export default ({ getService }: FtrProviderContext) => { describe('field distribution', () => { before(async () => { - await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/default' + ); }); after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('should return a 404 for missing index patterns', async () => { diff --git a/x-pack/test/api_integration/apis/lens/legacy_existing_fields.ts b/x-pack/test/api_integration/apis/lens/legacy_existing_fields.ts index 370807c99d806..6963df17ddedd 100644 --- a/x-pack/test/api_integration/apis/lens/legacy_existing_fields.ts +++ b/x-pack/test/api_integration/apis/lens/legacy_existing_fields.ts @@ -165,6 +165,10 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/default' + ); await kibanaServer.uiSettings.update({ 'lens:useFieldExistenceSampling': true, }); @@ -172,6 +176,7 @@ export default ({ getService }: FtrProviderContext) => { after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await esArchiver.unload('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.uiSettings.update({ 'lens:useFieldExistenceSampling': false, }); diff --git a/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts b/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts index 456d69d90ad45..75869e37199c5 100644 --- a/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts +++ b/x-pack/test/api_integration/apis/metrics_ui/inventory_threshold_alert.ts @@ -93,7 +93,7 @@ export default function ({ getService }: FtrProviderContext) { source, logQueryFields: void 0, compositeSize: 10000, - startTime: DATES['8.0.0'].hosts_only.max, + executionTimestamp: new Date(DATES['8.0.0'].hosts_only.max), logger, }; @@ -451,7 +451,7 @@ export default function ({ getService }: FtrProviderContext) { it('should work FOR LAST 1 minute', async () => { const results = await evaluateCondition({ ...baseOptions, - startTime: DATES['8.0.0'].pods_only.max, + executionTimestamp: new Date(DATES['8.0.0'].pods_only.max), nodeType: 'pod' as InventoryItemType, condition: { ...baseCondition, @@ -492,7 +492,7 @@ export default function ({ getService }: FtrProviderContext) { it('should work FOR LAST 5 minute', async () => { const results = await evaluateCondition({ ...baseOptions, - startTime: DATES['8.0.0'].pods_only.max, + executionTimestamp: new Date(DATES['8.0.0'].pods_only.max), logQueryFields: { indexPattern: 'metricbeat-*' }, nodeType: 'pod', condition: { diff --git a/x-pack/test/api_integration/apis/security_solution/authentications.ts b/x-pack/test/api_integration/apis/security_solution/authentications.ts index 8254ce034d2a5..920be90ba4227 100644 --- a/x-pack/test/api_integration/apis/security_solution/authentications.ts +++ b/x-pack/test/api_integration/apis/security_solution/authentications.ts @@ -7,8 +7,11 @@ import expect from '@kbn/expect'; import { - HostAuthenticationsStrategyResponse, - HostsQueries, + AuthStackByField, + Direction, + UserAuthenticationsRequestOptions, + UserAuthenticationsStrategyResponse, + UsersQueries, } from '../../../../plugins/security_solution/common/search_strategy'; import { FtrProviderContext } from '../../ftr_provider_context'; @@ -35,25 +38,29 @@ export default function ({ getService }: FtrProviderContext) { ); it('Make sure that we get Authentication data', async () => { - const authentications = await bsearch.send({ - supertest, - options: { - factoryQueryType: HostsQueries.authentications, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 0, - cursorStart: 0, - fakePossibleCount: 3, - querySize: 1, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, + const requestOptions: UserAuthenticationsRequestOptions = { + factoryQueryType: UsersQueries.authentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + pagination: { + activePage: 0, + cursorStart: 0, + fakePossibleCount: 3, + querySize: 1, }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + stackByField: AuthStackByField.userName, + sort: { field: 'timestamp', direction: Direction.asc }, + filterQuery: '', + }; + + const authentications = await bsearch.send({ + supertest, + options: requestOptions, strategy: 'securitySolutionSearchStrategy', }); @@ -63,25 +70,29 @@ export default function ({ getService }: FtrProviderContext) { }); it('Make sure that pagination is working in Authentications query', async () => { - const authentications = await bsearch.send({ - supertest, - options: { - factoryQueryType: HostsQueries.authentications, - timerange: { - interval: '12h', - to: TO, - from: FROM, - }, - pagination: { - activePage: 2, - cursorStart: 1, - fakePossibleCount: 5, - querySize: 2, - }, - defaultIndex: ['auditbeat-*'], - docValueFields: [], - inspect: false, + const requestOptions: UserAuthenticationsRequestOptions = { + factoryQueryType: UsersQueries.authentications, + timerange: { + interval: '12h', + to: TO, + from: FROM, + }, + pagination: { + activePage: 2, + cursorStart: 1, + fakePossibleCount: 5, + querySize: 2, }, + defaultIndex: ['auditbeat-*'], + docValueFields: [], + stackByField: AuthStackByField.userName, + sort: { field: 'timestamp', direction: Direction.asc }, + filterQuery: '', + }; + + const authentications = await bsearch.send({ + supertest, + options: requestOptions, strategy: 'securitySolutionSearchStrategy', }); diff --git a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts index bd4be58e2bb1c..5c1efcf5311b8 100644 --- a/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts +++ b/x-pack/test/apm_api_integration/tests/alerts/anomaly_alert.spec.ts @@ -20,7 +20,8 @@ export default function ApiTest({ getService }: FtrProviderContext) { const supertest = getService('supertest'); const log = getService('log'); - registry.when( + // FLAKY: https://github.com/elastic/kibana/issues/129224 + registry.when.skip( 'fetching service anomalies with a trial license', { config: 'trial', archives: ['apm_mappings_only_8.0.0'] }, () => { diff --git a/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts b/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts index 08137f167badf..85b9a31e2d361 100644 --- a/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts +++ b/x-pack/test/functional/apps/visualize/feature_controls/visualize_security.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const security = getService('security'); const config = getService('config'); const PageObjects = getPageObjects([ @@ -30,7 +31,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { describe('visualize feature controls security', () => { before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/default' + ); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); // ensure we're logged out so we can login as the appropriate users await PageObjects.security.forceLogout(); @@ -40,8 +44,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // logout, so the other tests don't accidentally run as the custom users we're testing below // NOTE: Logout needs to happen before anything else to avoid flaky behavior await PageObjects.security.forceLogout(); - - await esArchiver.unload('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); }); describe('global visualize all privileges', () => { diff --git a/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts b/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts index fe2456afafbf4..80aff8d27c77d 100644 --- a/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts +++ b/x-pack/test/functional/apps/visualize/feature_controls/visualize_spaces.ts @@ -11,32 +11,41 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const config = getService('config'); const spacesService = getService('spaces'); const PageObjects = getPageObjects(['common', 'visualize', 'security', 'spaceSelector', 'error']); const testSubjects = getService('testSubjects'); const appsMenu = getService('appsMenu'); - describe('visualize', () => { + describe('visualize spaces', () => { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/visualize/default'); }); describe('space with no features disabled', () => { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/default' + ); await spacesService.create({ id: 'custom_space', name: 'custom_space', disabledFeatures: [], }); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/custom_space', + { space: 'custom_space' } + ); }); after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); }); it('shows visualize navlink', async () => { @@ -50,7 +59,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it(`can view existing Visualization`, async () => { await PageObjects.common.navigateToActualUrl( 'visualize', - `${VisualizeConstants.EDIT_PATH}/i-exist`, + `${VisualizeConstants.EDIT_PATH}/custom_i-exist`, { basePath: '/s/custom_space', ensureCurrentUrl: false, @@ -67,7 +76,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { // we need to load the following in every situation as deleting // a space deletes all of the associated saved objects - await esArchiver.load('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/visualize/default' + ); await spacesService.create({ id: 'custom_space', name: 'custom_space', @@ -77,7 +89,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await spacesService.delete('custom_space'); - await esArchiver.unload('x-pack/test/functional/es_archives/visualize/default'); + await kibanaServer.savedObjects.cleanStandardList(); }); it(`doesn't show visualize navlink`, async () => { diff --git a/x-pack/test/functional/es_archives/visualize/default/data.json b/x-pack/test/functional/es_archives/visualize/default/data.json index a16e1676611ce..b47d504242b7a 100644 --- a/x-pack/test/functional/es_archives/visualize/default/data.json +++ b/x-pack/test/functional/es_archives/visualize/default/data.json @@ -1,26 +1,3 @@ -{ - "type": "doc", - "value": { - "id": "space:default", - "index": ".kibana_1", - "source": { - "migrationVersion": { - "space": "6.6.0" - }, - "references": [ - ], - "space": { - "_reserved": true, - "description": "This is the default space!", - "disabledFeatures": [ - ], - "name": "Default" - }, - "type": "space" - } - } -} - { "type": "doc", "value": { @@ -99,209 +76,3 @@ } } - -{ - "type": "doc", - "value": { - "id": "index-pattern:metricbeat-*", - "index": ".kibana_1", - "source": { - "index-pattern": { - "fieldFormatMap": "{\"aerospike.namespace.device.available.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.device.free.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.device.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.device.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.free.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.memory.used.data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.index.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.sindex.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"aws.rds.disk_usage.bin_log.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.free_local_storage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.free_storage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.freeable_memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.latency.commit\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.ddl\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.dml\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.insert\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.read\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.select\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.update\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.write\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.replica_lag.sec\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.swap_usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.volume_used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_daily_storage.bucket.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.downloaded.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.latency.first_byte.ms\":{\"id\":\"duration\",\"params\":{}},\"aws.s3_request.latency.total_request.ms\":{\"id\":\"duration\",\"params\":{}},\"aws.s3_request.requests.select_returned.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.requests.select_scanned.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.uploaded.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.sqs.oldest_message_age.sec\":{\"id\":\"duration\",\"params\":{}},\"aws.sqs.sent_message_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.degraded.ratio\":{\"id\":\"percent\",\"params\":{}},\"ceph.cluster_status.misplace.ratio\":{\"id\":\"percent\",\"params\":{}},\"ceph.cluster_status.pg.avail_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.data_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.total_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.used_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.traffic.read_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.traffic.write_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.log.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.misc.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.sst.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.total.byte\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.used.byte\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.used.pct\":{\"id\":\"percent\",\"params\":{}},\"ceph.pool_disk.stats.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.pool_disk.stats.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"client.bytes\":{\"id\":\"bytes\",\"params\":{}},\"client.nat.port\":{\"id\":\"string\",\"params\":{}},\"client.port\":{\"id\":\"string\",\"params\":{}},\"coredns.stats.dns.request.duration.ns.sum\":{\"id\":\"duration\",\"params\":{}},\"couchbase.bucket.data.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.disk.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.quota.ram.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.quota.use.pct\":{\"id\":\"percent\",\"params\":{}},\"couchbase.cluster.hdd.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.quota.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.used.by_data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.total.per_node.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.total.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.used.per_node.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.used.by_data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.couch.docs.data_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.couch.docs.disk_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.mcd_memory.allocated.bytes\":{\"id\":\"bytes\",\"params\":{}},\"destination.bytes\":{\"id\":\"bytes\",\"params\":{}},\"destination.nat.port\":{\"id\":\"string\",\"params\":{}},\"destination.port\":{\"id\":\"string\",\"params\":{}},\"docker.cpu.core.*.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.kernel.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.system.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.user.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.diskio.summary.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.commit.peak\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.commit.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.limit\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.private_working_set.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.rss.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.memory.rss.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.usage.max\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.usage.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.memory.usage.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.inbound.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.outbound.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.primaries.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.primaries.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.total.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.total.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.total.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.total.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.heap.init.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.heap.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.nonheap.init.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.nonheap.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.indices.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.disk.mvcc_db_total_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.memory.go_memstats_alloc.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.network.client_grpc_received.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.network.client_grpc_sent.bytes\":{\"id\":\"bytes\",\"params\":{}},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\",\"params\":{}},\"event.severity\":{\"id\":\"string\",\"params\":{}},\"golang.heap.allocations.active\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.allocated\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.idle\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.total\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.gc.next_gc_limit\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.obtained\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.released\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.stack\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.total\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.info.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"haproxy.info.memory.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.info.ssl.frontend.session_reuse.pct\":{\"id\":\"percent\",\"params\":{}},\"haproxy.stat.compressor.bypassed.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.response.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.throttle.pct\":{\"id\":\"percent\",\"params\":{}},\"http.request.body.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.request.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.body.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.status_code\":{\"id\":\"string\",\"params\":{}},\"kibana.stats.process.memory.heap.size_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kibana.stats.process.memory.heap.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kibana.stats.process.memory.heap.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.cpu.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.cpu.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.logs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.logs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.logs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.request.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.memory.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.allocatable.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.network.rx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.network.tx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.cpu.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.cpu.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.working_set.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.network.rx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.network.tx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.avg_obj_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.data_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.extent_free_list.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.file_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.index_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.storage_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.replstatus.headroom.max\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.headroom.min\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.lag.max\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.lag.min\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.oplog.size.allocated\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.replstatus.oplog.size.used\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.extra_info.heap_usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.dirty.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.maximum.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.max_file_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mysql.status.bytes.received\":{\"id\":\"bytes\",\"params\":{}},\"mysql.status.bytes.sent\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.cpu\":{\"id\":\"percent\",\"params\":{}},\"nats.stats.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.mem.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.uptime\":{\"id\":\"duration\",\"params\":{}},\"nats.subscriptions.cache.hit_rate\":{\"id\":\"percent\",\"params\":{}},\"network.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"process.pgid\":{\"id\":\"string\",\"params\":{}},\"process.pid\":{\"id\":\"string\",\"params\":{}},\"process.ppid\":{\"id\":\"string\",\"params\":{}},\"process.thread.id\":{\"id\":\"string\",\"params\":{}},\"rabbitmq.connection.frame_max\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.disk.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.disk.free.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.gc.reclaimed.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.io.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.io.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.mem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.queue.consumers.utilisation.pct\":{\"id\":\"percent\",\"params\":{}},\"rabbitmq.queue.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.active\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.allocated\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.fragmentation.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.resident\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.fragmentation.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.max.value\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.dataset\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.lua\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.peak\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.rss\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.value\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.buffer.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.copy_on_write.last_size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.rewrite.buffer.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.rewrite.current_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.aof.rewrite.last_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.aof.size.base\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.size.current\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.rdb.bgsave.current_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.rdb.bgsave.last_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.rdb.copy_on_write.last_size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.replication.backlog.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.replication.master.last_io_seconds_ago\":{\"id\":\"duration\",\"params\":{}},\"redis.info.replication.master.sync.last_io_seconds_ago\":{\"id\":\"duration\",\"params\":{}},\"redis.info.replication.master.sync.left_bytes\":{\"id\":\"bytes\",\"params\":{}},\"server.bytes\":{\"id\":\"bytes\",\"params\":{}},\"server.nat.port\":{\"id\":\"string\",\"params\":{}},\"server.port\":{\"id\":\"string\",\"params\":{}},\"source.bytes\":{\"id\":\"bytes\",\"params\":{}},\"source.nat.port\":{\"id\":\"string\",\"params\":{}},\"source.port\":{\"id\":\"string\",\"params\":{}},\"system.core.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.iowait.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.irq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.nice.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.softirq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.steal.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.system.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.user.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.idle.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.iowait.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.iowait.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.irq.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.irq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.nice.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.nice.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.softirq.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.softirq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.steal.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.steal.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.system.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.system.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.total.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.user.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.user.pct\":{\"id\":\"percent\",\"params\":{}},\"system.diskio.iostat.read.per_sec.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.iostat.write.per_sec.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.entropy.pct\":{\"id\":\"percent\",\"params\":{}},\"system.filesystem.available\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.free\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.total\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.fsstat.total_size.free\":{\"id\":\"bytes\",\"params\":{}},\"system.fsstat.total_size.total\":{\"id\":\"bytes\",\"params\":{}},\"system.fsstat.total_size.used\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.default_size\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.free\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.reserved\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.surplus\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.total\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.swap.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.total\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.total\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.blkio.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.active_anon.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.active_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.cache.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.hierarchical_memory_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.hierarchical_memsw_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.inactive_anon.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.inactive_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.mapped_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.rss_huge.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.swap.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.unevictable.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.memory.rss.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.memory.share\":{\"id\":\"bytes\",\"params\":{}},\"system.process.memory.size\":{\"id\":\"bytes\",\"params\":{}},\"system.socket.summary.tcp.memory\":{\"id\":\"bytes\",\"params\":{}},\"system.socket.summary.udp.memory\":{\"id\":\"bytes\",\"params\":{}},\"system.uptime.duration.ms\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\"}},\"url.port\":{\"id\":\"string\",\"params\":{}},\"vsphere.datastore.capacity.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.used.pct\":{\"id\":\"percent\",\"params\":{}},\"vsphere.host.memory.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.host.memory.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.host.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.free.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.total.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.used.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.used.host.bytes\":{\"id\":\"bytes\",\"params\":{}},\"windows.service.uptime.ms\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\"}}}", - "timeFieldName": "@timestamp", - "title": "metricbeat-*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern", - "updated_at": "2020-01-22T15:34:59.061Z" - } - } -} - -{ - "type": "doc", - "value": { - "index": ".kibana", - "type": "doc", - "id": "index-pattern:logstash-*", - "index": ".kibana_1", - "source": { - "index-pattern": { - "timeFieldName": "@timestamp", - "title": "logstash-*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern", - "updated_at": "2018-12-21T00:43:07.096Z" - } - } -} - -{ - "type": "doc", - "value": { - "index": ".kibana", - "type": "doc", - "id": "index-pattern:logstash-2015.09.22", - "index": ".kibana_1", - "source": { - "index-pattern": { - "timeFieldName": "@timestamp", - "title": "logstash-2015.09.22", - "fields":"[{\"name\":\"scripted_date\",\"type\":\"date\",\"count\":0,\"scripted\":true,\"script\":\"1234\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"scripted_string\",\"type\":\"string\",\"count\":0,\"scripted\":true,\"script\":\"return 'hello'\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]", - "runtimeFieldMap":"{\"runtime_string_field\":{\"type\":\"keyword\",\"script\":{\"source\":\"emit('hello world!')\"}},\"runtime_number_field\":{\"type\":\"double\",\"script\":{\"source\":\"emit(5)\"}}}" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "references": [ - ], - "type": "index-pattern", - "updated_at": "2018-12-21T00:43:07.096Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "custom_space:index-pattern:logstash-*", - "index": ".kibana_1", - "source": { - "index-pattern": { - "timeFieldName": "@timestamp", - "title": "logstash-*" - }, - "migrationVersion": { - "index-pattern": "7.11.0" - }, - "namespace": "custom_space", - "references": [ - ], - "type": "index-pattern", - "updated_at": "2018-12-21T00:43:07.096Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "visualization:i-exist", - "index": ".kibana_1", - "source": { - "migrationVersion": { - "visualization": "7.12.0" - }, - "references": [ - { - "id": "logstash-*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "updated_at": "2019-01-22T19:32:31.206Z", - "visualization": { - "description": "", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "A Pie", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "custom_space:visualization:i-exist", - "index": ".kibana_1", - "source": { - "migrationVersion": { - "visualization": "7.12.0" - }, - "namespace": "custom_space", - "references": [ - { - "id": "logstash-*", - "name": "kibanaSavedObjectMeta.searchSourceJSON.index", - "type": "index-pattern" - } - ], - "type": "visualization", - "updated_at": "2019-01-22T19:32:31.206Z", - "visualization": { - "description": "", - "kibanaSavedObjectMeta": { - "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" - }, - "title": "A Pie", - "uiStateJSON": "{}", - "version": 1, - "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}}},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}" - } - } - } -} - -{ - "type": "doc", - "value": { - "id": "query:OKJpgs", - "index": ".kibana_1", - "source": { - "query": { - "description": "Ok responses for jpg files", - "filters": [ - { - "$state": { - "store": "appState" - }, - "meta": { - "alias": null, - "disabled": false, - "index": "b15b1d40-a8bb-11e9-98cf-2bb06ef63e0b", - "key": "extension.raw", - "negate": false, - "params": { - "query": "jpg" - }, - "type": "phrase", - "value": "jpg" - }, - "query": { - "match": { - "extension.raw": { - "query": "jpg", - "type": "phrase" - } - } - } - } - ], - "query": { - "language": "kuery", - "query": "response:200" - }, - "title": "OKJpgs" - }, - "references": [ - ], - "type": "query", - "updated_at": "2019-07-17T17:54:26.378Z" - } - } -} diff --git a/x-pack/test/functional/fixtures/kbn_archiver/visualize/custom_space.json b/x-pack/test/functional/fixtures/kbn_archiver/visualize/custom_space.json new file mode 100644 index 0000000000000..6247f2548dfd3 --- /dev/null +++ b/x-pack/test/functional/fixtures/kbn_archiver/visualize/custom_space.json @@ -0,0 +1,43 @@ +{ + "attributes": { + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "coreMigrationVersion": "7.17.2", + "id": "custom_logstash-*", + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2018-12-21T00:43:07.096Z", + "version": "WzEyLDJd" +} + +{ + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "A Pie", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}},\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"distinctColors\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}" + }, + "coreMigrationVersion": "7.17.2", + "id": "custom_i-exist", + "migrationVersion": { + "visualization": "7.17.0" + }, + "references": [ + { + "id": "custom_logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2019-01-22T19:32:31.206Z", + "version": "WzE0LDJd" +} \ No newline at end of file diff --git a/x-pack/test/functional/fixtures/kbn_archiver/visualize/default.json b/x-pack/test/functional/fixtures/kbn_archiver/visualize/default.json new file mode 100644 index 0000000000000..243cfede1308b --- /dev/null +++ b/x-pack/test/functional/fixtures/kbn_archiver/visualize/default.json @@ -0,0 +1,147 @@ +{ + "attributes": { + "description": "Ok responses for jpg files", + "filters": [ + { + "$state": { + "store": "appState" + }, + "meta": { + "alias": null, + "disabled": false, + "index": "6afbb87f-5e4b-4514-9d73-a2b40188f7ff", + "key": "extension.raw", + "negate": false, + "params": { + "query": "jpg" + }, + "type": "phrase", + "value": "jpg" + }, + "query": { + "match": { + "extension.raw": { + "query": "jpg", + "type": "phrase" + } + } + } + } + ], + "query": { + "language": "kuery", + "query": "response:200" + }, + "title": "OKJpgs" + }, + "coreMigrationVersion": "7.17.2", + "id": "OKJpgs", + "migrationVersion": { + "query": "7.16.0" + }, + "references": [ + { + "id": "b15b1d40-a8bb-11e9-98cf-2bb06ef63e0b", + "name": "6afbb87f-5e4b-4514-9d73-a2b40188f7ff", + "type": "index-pattern" + } + ], + "type": "query", + "updated_at": "2019-07-17T17:54:26.378Z", + "version": "WzE1LDJd" +} + +{ + "attributes": { + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "coreMigrationVersion": "7.17.2", + "id": "logstash-*", + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2018-12-21T00:43:07.096Z", + "version": "WzEwLDJd" +} + +{ + "attributes": { + "timeFieldName": "@timestamp", + "title": "logs*" + }, + "coreMigrationVersion": "7.17.2", + "id": "b15b1d40-a8bb-11e9-98cf-2bb06ef63e0b", + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2018-12-21T00:43:07.096Z", + "version": "WzEwLDJd" +} + +{ + "attributes": { + "description": "", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" + }, + "title": "A Pie", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"A Pie\",\"type\":\"pie\",\"params\":{\"type\":\"pie\",\"addTooltip\":true,\"addLegend\":true,\"legendPosition\":\"right\",\"isDonut\":true,\"labels\":{\"show\":false,\"values\":true,\"last_level\":true,\"truncate\":100},\"dimensions\":{\"metric\":{\"accessor\":0,\"format\":{\"id\":\"number\"},\"params\":{},\"aggType\":\"count\"}},\"palette\":{\"type\":\"palette\",\"name\":\"kibana_palette\"},\"distinctColors\":true},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.src\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"otherBucket\":false,\"otherBucketLabel\":\"Other\",\"missingBucket\":false,\"missingBucketLabel\":\"Missing\"}}]}" + }, + "coreMigrationVersion": "7.17.2", + "id": "i-exist", + "migrationVersion": { + "visualization": "7.17.0" + }, + "references": [ + { + "id": "logstash-*", + "name": "kibanaSavedObjectMeta.searchSourceJSON.index", + "type": "index-pattern" + } + ], + "type": "visualization", + "updated_at": "2019-01-22T19:32:31.206Z", + "version": "WzEzLDJd" +} + +{ + "attributes": { + "fields": "[{\"name\":\"scripted_date\",\"type\":\"date\",\"count\":0,\"scripted\":true,\"script\":\"1234\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false},{\"name\":\"scripted_string\",\"type\":\"string\",\"count\":0,\"scripted\":true,\"script\":\"return 'hello'\",\"lang\":\"painless\",\"searchable\":true,\"aggregatable\":true,\"readFromDocValues\":false}]", + "runtimeFieldMap": "{\"runtime_string_field\":{\"type\":\"keyword\",\"script\":{\"source\":\"emit('hello world!')\"}},\"runtime_number_field\":{\"type\":\"double\",\"script\":{\"source\":\"emit(5)\"}}}", + "timeFieldName": "@timestamp", + "title": "logstash-2015.09.22" + }, + "coreMigrationVersion": "7.17.2", + "id": "logstash-2015.09.22", + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2018-12-21T00:43:07.096Z", + "version": "WzExLDJd" +} + +{ + "attributes": { + "fieldFormatMap": "{\"aerospike.namespace.device.available.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.device.free.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.device.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.device.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.free.pct\":{\"id\":\"percent\",\"params\":{}},\"aerospike.namespace.memory.used.data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.index.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.sindex.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aerospike.namespace.memory.used.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.ec2.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"aws.rds.disk_usage.bin_log.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.free_local_storage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.free_storage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.freeable_memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.latency.commit\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.ddl\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.dml\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.insert\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.read\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.select\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.update\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.latency.write\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.replica_lag.sec\":{\"id\":\"duration\",\"params\":{}},\"aws.rds.swap_usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.rds.volume_used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_daily_storage.bucket.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.downloaded.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.latency.first_byte.ms\":{\"id\":\"duration\",\"params\":{}},\"aws.s3_request.latency.total_request.ms\":{\"id\":\"duration\",\"params\":{}},\"aws.s3_request.requests.select_returned.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.requests.select_scanned.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.s3_request.uploaded.bytes\":{\"id\":\"bytes\",\"params\":{}},\"aws.sqs.oldest_message_age.sec\":{\"id\":\"duration\",\"params\":{}},\"aws.sqs.sent_message_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_disk.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.degraded.ratio\":{\"id\":\"percent\",\"params\":{}},\"ceph.cluster_status.misplace.ratio\":{\"id\":\"percent\",\"params\":{}},\"ceph.cluster_status.pg.avail_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.data_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.total_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.pg.used_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.traffic.read_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.cluster_status.traffic.write_bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.log.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.misc.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.sst.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.monitor_health.store_stats.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.total.byte\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.used.byte\":{\"id\":\"bytes\",\"params\":{}},\"ceph.osd_df.used.pct\":{\"id\":\"percent\",\"params\":{}},\"ceph.pool_disk.stats.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"ceph.pool_disk.stats.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"client.bytes\":{\"id\":\"bytes\",\"params\":{}},\"client.nat.port\":{\"id\":\"string\",\"params\":{}},\"client.port\":{\"id\":\"string\",\"params\":{}},\"coredns.stats.dns.request.duration.ns.sum\":{\"id\":\"duration\",\"params\":{}},\"couchbase.bucket.data.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.disk.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.quota.ram.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.bucket.quota.use.pct\":{\"id\":\"percent\",\"params\":{}},\"couchbase.cluster.hdd.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.quota.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.used.by_data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.hdd.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.total.per_node.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.total.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.used.per_node.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.quota.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.used.by_data.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.cluster.ram.used.value.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.couch.docs.data_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.couch.docs.disk_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"couchbase.node.mcd_memory.allocated.bytes\":{\"id\":\"bytes\",\"params\":{}},\"destination.bytes\":{\"id\":\"bytes\",\"params\":{}},\"destination.nat.port\":{\"id\":\"string\",\"params\":{}},\"destination.port\":{\"id\":\"string\",\"params\":{}},\"docker.cpu.core.*.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.kernel.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.system.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.cpu.user.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.diskio.summary.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.commit.peak\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.commit.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.limit\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.private_working_set.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.rss.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.memory.rss.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.usage.max\":{\"id\":\"bytes\",\"params\":{}},\"docker.memory.usage.pct\":{\"id\":\"percent\",\"params\":{}},\"docker.memory.usage.total\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.inbound.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"docker.network.outbound.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.primaries.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.primaries.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.total.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.summary.total.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.total.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.index.total.store.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.heap.init.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.heap.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.nonheap.init.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.jvm.memory.nonheap.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.fs.summary.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.indices.segments.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.old.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.survivor.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.peak.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.peak_max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"elasticsearch.node.stats.jvm.mem.pools.young.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.disk.mvcc_db_total_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.memory.go_memstats_alloc.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.network.client_grpc_received.bytes\":{\"id\":\"bytes\",\"params\":{}},\"etcd.network.client_grpc_sent.bytes\":{\"id\":\"bytes\",\"params\":{}},\"event.duration\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"nanoseconds\",\"outputFormat\":\"asMilliseconds\",\"outputPrecision\":1}},\"event.sequence\":{\"id\":\"string\",\"params\":{}},\"event.severity\":{\"id\":\"string\",\"params\":{}},\"golang.heap.allocations.active\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.allocated\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.idle\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.allocations.total\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.gc.next_gc_limit\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.obtained\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.released\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.stack\":{\"id\":\"bytes\",\"params\":{}},\"golang.heap.system.total\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.info.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"haproxy.info.memory.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.info.ssl.frontend.session_reuse.pct\":{\"id\":\"percent\",\"params\":{}},\"haproxy.stat.compressor.bypassed.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.compressor.response.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"haproxy.stat.throttle.pct\":{\"id\":\"percent\",\"params\":{}},\"http.request.body.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.request.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.body.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.bytes\":{\"id\":\"bytes\",\"params\":{}},\"http.response.status_code\":{\"id\":\"string\",\"params\":{}},\"kibana.stats.process.memory.heap.size_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kibana.stats.process.memory.heap.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kibana.stats.process.memory.heap.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.apiserver.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.cpu.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.cpu.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.logs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.logs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.logs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.request.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.memory.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.memory.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.container.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.container.rootfs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.controllermanager.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.fs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.allocatable.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.network.rx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.network.tx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.node.runtime.imagefs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.cpu.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.cpu.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.memory.usage.limit.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.usage.node.pct\":{\"id\":\"percent\",\"params\":{}},\"kubernetes.pod.memory.working_set.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.network.rx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.pod.network.tx.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.proxy.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.http.request.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.http.response.size.bytes.sum\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.process.memory.resident.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.scheduler.process.memory.virtual.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.system.memory.workingset.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.available.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.capacity.bytes\":{\"id\":\"bytes\",\"params\":{}},\"kubernetes.volume.fs.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.avg_obj_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.data_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.extent_free_list.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.file_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.index_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.dbstats.storage_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.replstatus.headroom.max\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.headroom.min\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.lag.max\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.lag.min\":{\"id\":\"duration\",\"params\":{}},\"mongodb.replstatus.oplog.size.allocated\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.replstatus.oplog.size.used\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.extra_info.heap_usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.dirty.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.maximum.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.cache.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.max_file_size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mongodb.status.wired_tiger.log.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"mysql.status.bytes.received\":{\"id\":\"bytes\",\"params\":{}},\"mysql.status.bytes.sent\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.cpu\":{\"id\":\"percent\",\"params\":{}},\"nats.stats.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.mem.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"nats.stats.uptime\":{\"id\":\"duration\",\"params\":{}},\"nats.subscriptions.cache.hit_rate\":{\"id\":\"percent\",\"params\":{}},\"network.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.data_file.size.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"oracle.tablespace.space.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"process.pgid\":{\"id\":\"string\",\"params\":{}},\"process.pid\":{\"id\":\"string\",\"params\":{}},\"process.ppid\":{\"id\":\"string\",\"params\":{}},\"process.thread.id\":{\"id\":\"string\",\"params\":{}},\"rabbitmq.connection.frame_max\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.disk.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.disk.free.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.gc.reclaimed.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.io.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.io.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.node.mem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"rabbitmq.queue.consumers.utilisation.pct\":{\"id\":\"percent\",\"params\":{}},\"rabbitmq.queue.memory.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.active\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.allocated\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.fragmentation.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.resident\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.allocator_stats.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.fragmentation.bytes\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.max.value\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.dataset\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.lua\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.peak\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.rss\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.memory.used.value\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.buffer.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.copy_on_write.last_size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.rewrite.buffer.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.rewrite.current_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.aof.rewrite.last_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.aof.size.base\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.aof.size.current\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.persistence.rdb.bgsave.current_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.rdb.bgsave.last_time.sec\":{\"id\":\"duration\",\"params\":{}},\"redis.info.persistence.rdb.copy_on_write.last_size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.replication.backlog.size\":{\"id\":\"bytes\",\"params\":{}},\"redis.info.replication.master.last_io_seconds_ago\":{\"id\":\"duration\",\"params\":{}},\"redis.info.replication.master.sync.last_io_seconds_ago\":{\"id\":\"duration\",\"params\":{}},\"redis.info.replication.master.sync.left_bytes\":{\"id\":\"bytes\",\"params\":{}},\"server.bytes\":{\"id\":\"bytes\",\"params\":{}},\"server.nat.port\":{\"id\":\"string\",\"params\":{}},\"server.port\":{\"id\":\"string\",\"params\":{}},\"source.bytes\":{\"id\":\"bytes\",\"params\":{}},\"source.nat.port\":{\"id\":\"string\",\"params\":{}},\"source.port\":{\"id\":\"string\",\"params\":{}},\"system.core.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.iowait.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.irq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.nice.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.softirq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.steal.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.system.pct\":{\"id\":\"percent\",\"params\":{}},\"system.core.user.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.idle.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.idle.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.iowait.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.iowait.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.irq.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.irq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.nice.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.nice.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.softirq.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.softirq.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.steal.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.steal.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.system.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.system.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.total.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.user.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.cpu.user.pct\":{\"id\":\"percent\",\"params\":{}},\"system.diskio.iostat.read.per_sec.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.iostat.write.per_sec.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.read.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.diskio.write.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.entropy.pct\":{\"id\":\"percent\",\"params\":{}},\"system.filesystem.available\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.free\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.total\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.filesystem.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.fsstat.total_size.free\":{\"id\":\"bytes\",\"params\":{}},\"system.fsstat.total_size.total\":{\"id\":\"bytes\",\"params\":{}},\"system.fsstat.total_size.used\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.actual.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.default_size\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.free\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.reserved\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.surplus\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.total\":{\"id\":\"number\",\"params\":{}},\"system.memory.hugepages.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.hugepages.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.swap.free\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.total\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.swap.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.memory.total\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.memory.used.pct\":{\"id\":\"percent\",\"params\":{}},\"system.network.in.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.network.out.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.blkio.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.kmem_tcp.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.mem.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.usage.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.memsw.usage.max.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.active_anon.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.active_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.cache.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.hierarchical_memory_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.hierarchical_memsw_limit.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.inactive_anon.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.inactive_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.mapped_file.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.rss_huge.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.swap.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cgroup.memory.stats.unevictable.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.cpu.total.norm.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.cpu.total.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.memory.rss.bytes\":{\"id\":\"bytes\",\"params\":{}},\"system.process.memory.rss.pct\":{\"id\":\"percent\",\"params\":{}},\"system.process.memory.share\":{\"id\":\"bytes\",\"params\":{}},\"system.process.memory.size\":{\"id\":\"bytes\",\"params\":{}},\"system.socket.summary.tcp.memory\":{\"id\":\"bytes\",\"params\":{}},\"system.socket.summary.udp.memory\":{\"id\":\"bytes\",\"params\":{}},\"system.uptime.duration.ms\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\"}},\"url.port\":{\"id\":\"string\",\"params\":{}},\"vsphere.datastore.capacity.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.datastore.capacity.used.pct\":{\"id\":\"percent\",\"params\":{}},\"vsphere.host.memory.free.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.host.memory.total.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.host.memory.used.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.free.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.total.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.used.guest.bytes\":{\"id\":\"bytes\",\"params\":{}},\"vsphere.virtualmachine.memory.used.host.bytes\":{\"id\":\"bytes\",\"params\":{}},\"windows.service.uptime.ms\":{\"id\":\"duration\",\"params\":{\"inputFormat\":\"milliseconds\"}}}", + "timeFieldName": "@timestamp", + "title": "metricbeat-*" + }, + "coreMigrationVersion": "7.17.2", + "id": "metricbeat-*", + "migrationVersion": { + "index-pattern": "7.11.0" + }, + "references": [], + "type": "index-pattern", + "updated_at": "2020-01-22T15:34:59.061Z", + "version": "WzksMl0=" +} \ No newline at end of file diff --git a/x-pack/test/functional/services/ml/alerting.ts b/x-pack/test/functional/services/ml/alerting.ts index 45c4c9ba39ed1..0acda99622443 100644 --- a/x-pack/test/functional/services/ml/alerting.ts +++ b/x-pack/test/functional/services/ml/alerting.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; import { MlApi } from './api'; import { MlCommonUI } from './common_ui'; import { ML_ALERT_TYPES } from '../../../../plugins/ml/common/constants/alerts'; -import { Alert } from '../../../../plugins/alerting/common'; +import { Rule } from '../../../../plugins/alerting/common'; import { MlAnomalyDetectionAlertParams } from '../../../../plugins/ml/common/types/alerts'; export function MachineLearningAlertingProvider( @@ -161,9 +161,7 @@ export function MachineLearningAlertingProvider( .set('kbn-xsrf', 'foo'); mlApi.assertResponseStatusCode(200, findResponseStatus, anomalyDetectionRules); - for (const rule of anomalyDetectionRules.data as Array< - Alert - >) { + for (const rule of anomalyDetectionRules.data as Array>) { const { body, status } = await supertest .delete(`/api/alerting/rule/${rule.id}`) .set('kbn-xsrf', 'foo'); diff --git a/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts b/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts index 8c14e7e1263ee..8fd5821ffdef1 100644 --- a/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts +++ b/x-pack/test/functional_with_es_ssl/apps/cases/view_case.ts @@ -19,7 +19,8 @@ export default ({ getPageObject, getService }: FtrProviderContext) => { const retry = getService('retry'); const comboBox = getService('comboBox'); - describe('View case', () => { + // Failing: See https://github.com/elastic/kibana/issues/129248 + describe.skip('View case', () => { describe('properties', () => { // create the case to test on before(async () => { diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index 22c98b189a590..3813a8686826e 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -180,75 +180,90 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should disable the rule', async () => { - const enableSwitch = await testSubjects.find('enableSwitch'); + const actionsDropdown = await testSubjects.find('statusDropdown'); - const isChecked = await enableSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('true'); + expect(await actionsDropdown.getVisibleText()).to.eql('Enabled'); - await enableSwitch.click(); + await actionsDropdown.click(); + const actionsMenuElem = await testSubjects.find('ruleStatusMenu'); + const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem'); - const disableSwitchAfterDisabling = await testSubjects.find('enableSwitch'); - const isCheckedAfterDisabling = await disableSwitchAfterDisabling.getAttribute( - 'aria-checked' - ); - expect(isCheckedAfterDisabling).to.eql('false'); + await actionsMenuItemElem.at(1)?.click(); + + await retry.try(async () => { + expect(await actionsDropdown.getVisibleText()).to.eql('Disabled'); + }); }); - it('shouldnt allow you to mute a disabled rule', async () => { - const disabledEnableSwitch = await testSubjects.find('enableSwitch'); - expect(await disabledEnableSwitch.getAttribute('aria-checked')).to.eql('false'); + it('shouldnt allow you to snooze a disabled rule', async () => { + const actionsDropdown = await testSubjects.find('statusDropdown'); - const muteSwitch = await testSubjects.find('muteSwitch'); - expect(await muteSwitch.getAttribute('aria-checked')).to.eql('false'); + expect(await actionsDropdown.getVisibleText()).to.eql('Disabled'); - await muteSwitch.click(); + await actionsDropdown.click(); + const actionsMenuElem = await testSubjects.find('ruleStatusMenu'); + const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem'); - const muteSwitchAfterTryingToMute = await testSubjects.find('muteSwitch'); - const isDisabledMuteAfterDisabling = await muteSwitchAfterTryingToMute.getAttribute( - 'aria-checked' - ); - expect(isDisabledMuteAfterDisabling).to.eql('false'); + expect(await actionsMenuItemElem.at(2)?.getVisibleText()).to.eql('Snooze'); + expect(await actionsMenuItemElem.at(2)?.getAttribute('disabled')).to.eql('true'); + // close the dropdown + await actionsDropdown.click(); }); it('should reenable a disabled the rule', async () => { - const enableSwitch = await testSubjects.find('enableSwitch'); + const actionsDropdown = await testSubjects.find('statusDropdown'); - const isChecked = await enableSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('false'); + expect(await actionsDropdown.getVisibleText()).to.eql('Disabled'); - await enableSwitch.click(); + await actionsDropdown.click(); + const actionsMenuElem = await testSubjects.find('ruleStatusMenu'); + const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem'); - const disableSwitchAfterReenabling = await testSubjects.find('enableSwitch'); - const isCheckedAfterDisabling = await disableSwitchAfterReenabling.getAttribute( - 'aria-checked' - ); - expect(isCheckedAfterDisabling).to.eql('true'); + await actionsMenuItemElem.at(0)?.click(); + + await retry.try(async () => { + expect(await actionsDropdown.getVisibleText()).to.eql('Enabled'); + }); }); - it('should mute the rule', async () => { - const muteSwitch = await testSubjects.find('muteSwitch'); + it('should snooze the rule', async () => { + const actionsDropdown = await testSubjects.find('statusDropdown'); - const isChecked = await muteSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('false'); + expect(await actionsDropdown.getVisibleText()).to.eql('Enabled'); - await muteSwitch.click(); + await actionsDropdown.click(); + const actionsMenuElem = await testSubjects.find('ruleStatusMenu'); + const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem'); - const muteSwitchAfterDisabling = await testSubjects.find('muteSwitch'); - const isCheckedAfterDisabling = await muteSwitchAfterDisabling.getAttribute('aria-checked'); - expect(isCheckedAfterDisabling).to.eql('true'); + await actionsMenuItemElem.at(2)?.click(); + + const snoozeIndefinite = await testSubjects.find('ruleSnoozeIndefiniteApply'); + await snoozeIndefinite.click(); + + await retry.try(async () => { + expect(await actionsDropdown.getVisibleText()).to.eql('Snoozed'); + const remainingSnoozeTime = await testSubjects.find('remainingSnoozeTime'); + expect(await remainingSnoozeTime.getVisibleText()).to.eql('Indefinitely'); + }); }); - it('should unmute the rule', async () => { - const muteSwitch = await testSubjects.find('muteSwitch'); + it('should unsnooze the rule', async () => { + const actionsDropdown = await testSubjects.find('statusDropdown'); - const isChecked = await muteSwitch.getAttribute('aria-checked'); - expect(isChecked).to.eql('true'); + expect(await actionsDropdown.getVisibleText()).to.eql('Snoozed'); - await muteSwitch.click(); + await actionsDropdown.click(); + const actionsMenuElem = await testSubjects.find('ruleStatusMenu'); + const actionsMenuItemElem = await actionsMenuElem.findAllByClassName('euiContextMenuItem'); - const muteSwitchAfterUnmuting = await testSubjects.find('muteSwitch'); - const isCheckedAfterDisabling = await muteSwitchAfterUnmuting.getAttribute('aria-checked'); - expect(isCheckedAfterDisabling).to.eql('false'); + await actionsMenuItemElem.at(2)?.click(); + + const snoozeCancel = await testSubjects.find('ruleSnoozeCancel'); + await snoozeCancel.click(); + + await retry.try(async () => { + expect(await actionsDropdown.getVisibleText()).to.eql('Enabled'); + }); }); }); diff --git a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/public/plugin.ts b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/public/plugin.ts index a5fa20fca25ef..d3eff0b60955e 100644 --- a/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/public/plugin.ts +++ b/x-pack/test/functional_with_es_ssl/fixtures/plugins/alerts/public/plugin.ts @@ -8,7 +8,7 @@ import React from 'react'; import { Plugin, CoreSetup, AppMountParameters } from 'kibana/public'; import { PluginSetupContract as AlertingSetup } from '../../../../../../plugins/alerting/public'; -import { SanitizedAlert } from '../../../../../../plugins/alerting/common'; +import { SanitizedRule } from '../../../../../../plugins/alerting/common'; import { TriggersAndActionsUIPublicPluginSetup } from '../../../../../../plugins/triggers_actions_ui/public'; export type Setup = void; @@ -24,7 +24,7 @@ export class AlertingFixturePlugin implements Plugin `/rule/${alert.id}` + (alert: SanitizedRule) => `/rule/${alert.id}` ); triggersActionsUi.ruleTypeRegistry.register({ diff --git a/x-pack/test/rule_registry/common/lib/helpers/wait_until_next_execution.ts b/x-pack/test/rule_registry/common/lib/helpers/wait_until_next_execution.ts index 8bc325c4a6bb7..64999aafd2f60 100644 --- a/x-pack/test/rule_registry/common/lib/helpers/wait_until_next_execution.ts +++ b/x-pack/test/rule_registry/common/lib/helpers/wait_until_next_execution.ts @@ -7,18 +7,18 @@ import { GetService } from '../../types'; import { getAlertsTargetIndices } from './get_alerts_target_indices'; import { BULK_INDEX_DELAY, MAX_POLLS } from '../../constants'; -import { Alert } from '../../../../../plugins/alerting/common'; +import { Rule } from '../../../../../plugins/alerting/common'; import { getSpaceUrlPrefix } from '../authentication/spaces'; import { User } from '../authentication/types'; export async function waitUntilNextExecution( getService: GetService, user: User, - alert: Alert, + alert: Rule, spaceId: string, intervalInSeconds: number = 1, count: number = 0 -): Promise { +): Promise { const supertest = getService('supertestWithoutAuth'); const es = getService('es'); @@ -48,7 +48,7 @@ export async function waitUntilNextExecution( throw error; } - const nextAlert = body as Alert; + const nextAlert = body as Rule; if (nextAlert.executionStatus.lastExecutionDate !== alert.executionStatus.lastExecutionDate) { await new Promise((resolve) => { diff --git a/x-pack/test/rule_registry/common/types.ts b/x-pack/test/rule_registry/common/types.ts index c773a19b6d95d..bd457d17a92df 100644 --- a/x-pack/test/rule_registry/common/types.ts +++ b/x-pack/test/rule_registry/common/types.ts @@ -6,13 +6,13 @@ */ import { GenericFtrProviderContext } from '@kbn/test'; import { - Alert as Rule, - AlertTypeParams as RuleTypeParams, + Rule, + RuleTypeParams, ActionGroupIdsOf, AlertInstanceState as AlertState, AlertInstanceContext as AlertContext, } from '../../../plugins/alerting/common'; -import { AlertTypeState as RuleTypeState } from '../../../plugins/alerting/server'; +import { RuleTypeState } from '../../../plugins/alerting/server'; import { services } from './services'; export type GetService = GenericFtrProviderContext['getService']; diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts b/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts index 4df3ff6b20649..4e9c9c1475388 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/create_rule.ts @@ -29,7 +29,7 @@ import { deleteAlert, } from '../../../common/lib/helpers'; import { AlertDef, AlertParams } from '../../../common/types'; -import { Alert } from '../../../../../plugins/alerting/common'; +import { Rule } from '../../../../../plugins/alerting/common'; import { APM_METRIC_INDEX_NAME } from '../../../common/constants'; import { obsOnly } from '../../../common/lib/authentication/users'; @@ -58,7 +58,7 @@ export default function registryRulesApiTest({ getService }: FtrProviderContext) describe('when creating a rule', () => { let createResponse: { - alert: Alert; + alert: Rule; status: number; }; before(async () => { diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts b/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts index 8fabaf9151d53..689144791b048 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/lifecycle_executor.ts @@ -31,7 +31,7 @@ import { MockAlertState, MockAllowedActionGroups, } from '../../../common/types'; -import { AlertExecutorOptions as RuleExecutorOptions } from '../../../../../plugins/alerting/server'; +import { RuleExecutorOptions } from '../../../../../plugins/alerting/server'; import { cleanupRegistryIndices } from '../../../common/lib/helpers/cleanup_registry_indices'; // eslint-disable-next-line import/no-default-export diff --git a/yarn.lock b/yarn.lock index cb4bbea65b4a2..eca2c6c07f4ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1485,10 +1485,10 @@ dependencies: "@elastic/ecs-helpers" "^1.1.0" -"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.2.0-canary.1": - version "8.2.0-canary.1" - resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.2.0-canary.1.tgz#da547aaf0a39846cda4484bc021dea2117acaf0c" - integrity sha512-MxDCQjcKgxQulX+PJiPWdwFJwYq5J1EVycU5EaE1sDODLnnJp5dvQFPtRRla9MM5Elyy52swtfzQA5ktGixyRg== +"@elastic/elasticsearch@npm:@elastic/elasticsearch-canary@8.2.0-canary.2": + version "8.2.0-canary.2" + resolved "https://registry.yarnpkg.com/@elastic/elasticsearch-canary/-/elasticsearch-canary-8.2.0-canary.2.tgz#2513926cdbfe7c070e1fa6926f7829171b27cdba" + integrity sha512-Ki2lQ3/UlOnBaf5EjNw0WmCdXiW+J020aYtdVnIuCNhPSLoNPKoM7P+MlggdfeRnENvINlStrMy4bkYF/h6Vbw== dependencies: "@elastic/transport" "^8.0.2" tslib "^2.3.0" @@ -9974,10 +9974,10 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^99.0.0: - version "99.0.0" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-99.0.0.tgz#fbfcc7e74991dd50962e7dd456d78eaf49f56774" - integrity sha512-pyB+5LuyZdb7EBPL3i5D5yucZUD+SlkdiUtmpjaEnLd9zAXp+SvD/hP5xF4l/ZmWvUo/1ZLxAI1YBdhazGTpgA== +chromedriver@^100.0.0: + version "100.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-100.0.0.tgz#1b4bf5c89cea12c79f53bc94d8f5bb5aa79ed7be" + integrity sha512-oLfB0IgFEGY9qYpFQO/BNSXbPw7bgfJUN5VX8Okps9W2qNT4IqKh5hDwKWtpUIQNI6K3ToWe2/J5NdpurTY02g== dependencies: "@testim/chrome-version" "^1.1.2" axios "^0.24.0"