diff --git a/dev_docs/tutorials/debugging.mdx b/dev_docs/tutorials/debugging.mdx
new file mode 100644
index 0000000000000..c0efd249be066
--- /dev/null
+++ b/dev_docs/tutorials/debugging.mdx
@@ -0,0 +1,61 @@
+---
+id: kibDevTutorialDebugging
+slug: /kibana-dev-docs/tutorial/debugging
+title: Debugging in development
+summary: Learn how to debug Kibana while running from source
+date: 2021-04-26
+tags: ['kibana', 'onboarding', 'dev', 'tutorials', 'debugging']
+---
+
+There are multiple ways to go about debugging Kibana when running from source.
+
+## Debugging using Chrome DevTools
+
+You will need to run Node using `--inspect` or `--inspect-brk` in order to enable the inspector. Additional information can be found in the [Node.js docs](https://nodejs.org/en/docs/guides/debugging-getting-started/).
+
+Once Node is running with the inspector enabled, you can open `chrome://inspect` in your Chrome browser. You should see a remote target for the inspector running. Click "inspect". You can now begin using the debugger.
+
+Next we will go over how to exactly enable the inspector for different aspects of the codebase.
+
+### Jest Unit Tests
+
+You will need to run Jest directly from the Node script:
+
+`node --inspect-brk scripts/jest [TestPathPattern]`
+
+### Functional Test Runner
+
+`node --inspect-brk scripts/functional_test_runner`
+
+### Development Server
+
+`node --inspect-brk scripts/kibana`
+
+## Debugging using logging
+
+When running Kibana, it's sometimes helpful to enable verbose logging.
+
+`yarn start --verbose`
+
+Using verbose logging usually results in much more information than you're interested in. The [logging documentation](https://www.elastic.co/guide/en/kibana/current/logging-settings.html) covers ways to change the log level of certain types.
+
+In the following example of a configuration stored in `config/kibana.dev.yml` we are logging all Elasticsearch queries and any logs created by the Management plugin.
+
+```
+logging:
+ appenders:
+ console:
+ type: console
+ layout:
+ type: pattern
+ highlight: true
+ root:
+ appenders: [default, console]
+ level: info
+
+ loggers:
+ - name: plugins.management
+ level: debug
+ - name: elasticsearch.query
+ level: debug
+```
\ No newline at end of file
diff --git a/docs/discover/search-sessions.asciidoc b/docs/discover/search-sessions.asciidoc
index b503e8cfba3b4..652583db785ad 100644
--- a/docs/discover/search-sessions.asciidoc
+++ b/docs/discover/search-sessions.asciidoc
@@ -72,15 +72,28 @@ behaves differently:
[float]
==== Limitations
-Certain visualization features do not fully support background search sessions yet. If a dashboard using these features gets restored,
-all panels using unsupported features won't load immediately, but instead send out additional data requests which can take a while to complete.
-In this case a warning *Your search session is still running* will be shown.
+Certain visualization features do not fully support background search sessions. If a dashboard
+using these features is restored,
+all panels using unsupported features won't load immediately, but instead send out additional
+data requests, which can take a while to complete.
+The warning *Your search session is still running* is shown.
-You can either wait for these additional requests to complete or come back to the dashboard later when all data requests have been finished.
+You can either wait for these additional requests to complete or come back to the dashboard later
+when all data requests have finished.
A panel on a dashboard can behave like this if one of the following features is used:
-* *Lens* - A *top values* dimension with an enabled setting *Group other values as "Other"* (configurable in the *Advanced* section of the dimension)
-* *Lens* - An *intervals* dimension is used
-* *Aggregation based* visualizations - A *terms* aggregation is used with an enabled setting *Group other values in separate bucket*
-* *Aggregation based* visualizations - A *histogram* aggregation is used
-* *Maps* - Layers using joins, blended layers or tracks layers are used
+
+**Lens**
+
+* A *top values* dimension with an enabled *Group other values as "Other"* setting.
+This is configurable in the *Advanced* section of the dimension.
+* An *intervals* dimension.
+
+**Aggregation based** visualizations
+
+* A *terms* aggregation with an enabled *Group other values in separate bucket* setting.
+* A *histogram* aggregation.
+
+**Maps**
+
+* Layers using joins, blended layers, or tracks layers.
diff --git a/package.json b/package.json
index 8f56d80c584ea..22eedde59c5e7 100644
--- a/package.json
+++ b/package.json
@@ -114,6 +114,7 @@
"@elastic/safer-lodash-set": "link:bazel-bin/packages/elastic-safer-lodash-set",
"@elastic/search-ui-app-search-connector": "^1.6.0",
"@elastic/ui-ace": "0.2.3",
+ "@emotion/react": "^11.4.0",
"@hapi/accept": "^5.0.2",
"@hapi/boom": "^9.1.1",
"@hapi/cookie": "^11.0.2",
@@ -454,6 +455,8 @@
"@elastic/eslint-plugin-eui": "0.0.2",
"@elastic/github-checks-reporter": "0.0.20b3",
"@elastic/makelogs": "^6.0.0",
+ "@emotion/babel-preset-css-prop": "^11.2.0",
+ "@emotion/jest": "^11.3.0",
"@istanbuljs/schema": "^0.1.2",
"@jest/reporters": "^26.6.2",
"@kbn/babel-code-parser": "link:bazel-bin/packages/kbn-babel-code-parser",
diff --git a/packages/elastic-eslint-config-kibana/.eslintrc.js b/packages/elastic-eslint-config-kibana/.eslintrc.js
index 3220a01184004..d3cf7cf964a60 100644
--- a/packages/elastic-eslint-config-kibana/.eslintrc.js
+++ b/packages/elastic-eslint-config-kibana/.eslintrc.js
@@ -1,3 +1,5 @@
+const { USES_STYLED_COMPONENTS } = require('@kbn/dev-utils');
+
module.exports = {
extends: [
'./javascript.js',
@@ -79,7 +81,13 @@ module.exports = {
from: 'react-intl',
to: '@kbn/i18n/react',
disallowedMessage: `import from @kbn/i18n/react instead`
- }
+ },
+ {
+ from: 'styled-components',
+ to: false,
+ exclude: USES_STYLED_COMPONENTS,
+ disallowedMessage: `Prefer using @emotion/react instead. To use styled-components, ensure you plugin is enabled in @kbn/dev-utils/src/babel.ts.`
+ },
],
],
},
diff --git a/packages/kbn-babel-preset/BUILD.bazel b/packages/kbn-babel-preset/BUILD.bazel
index f5ebc153b9e1a..11eae8bc55ca9 100644
--- a/packages/kbn-babel-preset/BUILD.bazel
+++ b/packages/kbn-babel-preset/BUILD.bazel
@@ -32,6 +32,7 @@ DEPS = [
"@npm//@babel/preset-env",
"@npm//@babel/preset-react",
"@npm//@babel/preset-typescript",
+ "@npm//@emotion/babel-preset-css-prop",
"@npm//babel-plugin-add-module-exports",
"@npm//babel-plugin-styled-components",
"@npm//babel-plugin-transform-react-remove-prop-types",
diff --git a/packages/kbn-babel-preset/webpack_preset.js b/packages/kbn-babel-preset/webpack_preset.js
index ca7ea40ff0fe1..186ce87478828 100644
--- a/packages/kbn-babel-preset/webpack_preset.js
+++ b/packages/kbn-babel-preset/webpack_preset.js
@@ -6,6 +6,8 @@
* Side Public License, v 1.
*/
+const { USES_STYLED_COMPONENTS } = require.resolve('@kbn/dev-utils');
+
module.exports = () => {
return {
presets: [
@@ -21,14 +23,6 @@ module.exports = () => {
],
require('./common_preset'),
],
- plugins: [
- [
- require.resolve('babel-plugin-styled-components'),
- {
- fileName: false,
- },
- ],
- ],
env: {
production: {
plugins: [
@@ -42,5 +36,29 @@ module.exports = () => {
],
},
},
+ overrides: [
+ {
+ include: USES_STYLED_COMPONENTS,
+ plugins: [
+ [
+ require.resolve('babel-plugin-styled-components'),
+ {
+ fileName: false,
+ },
+ ],
+ ],
+ },
+ {
+ exclude: USES_STYLED_COMPONENTS,
+ presets: [
+ [
+ require.resolve('@emotion/babel-preset-css-prop'),
+ {
+ labelFormat: '[local]',
+ },
+ ],
+ ],
+ },
+ ],
};
};
diff --git a/packages/kbn-crypto/BUILD.bazel b/packages/kbn-crypto/BUILD.bazel
index 20793e27de629..bf1ed3f778975 100644
--- a/packages/kbn-crypto/BUILD.bazel
+++ b/packages/kbn-crypto/BUILD.bazel
@@ -38,7 +38,8 @@ TYPES_DEPS = [
"@npm//@types/node",
"@npm//@types/node-forge",
"@npm//@types/testing-library__jest-dom",
- "@npm//resize-observer-polyfill"
+ "@npm//resize-observer-polyfill",
+ "@npm//@emotion/react",
]
DEPS = SRC_DEPS + TYPES_DEPS
diff --git a/packages/kbn-dev-utils/src/babel.ts b/packages/kbn-dev-utils/src/babel.ts
index 9daa7d9fe8d7a..5570055a21d15 100644
--- a/packages/kbn-dev-utils/src/babel.ts
+++ b/packages/kbn-dev-utils/src/babel.ts
@@ -46,3 +46,14 @@ export async function transformFileWithBabel(file: File) {
file.extname = '.js';
transformedFiles.add(file);
}
+
+/**
+ * Synchronized regex list of files that use `styled-components`.
+ * Used by `kbn-babel-preset` and `elastic-eslint-config-kibana`.
+ */
+export const USES_STYLED_COMPONENTS = [
+ /packages[\/\\]kbn-ui-shared-deps[\/\\]/,
+ /src[\/\\]plugins[\/\\](data|kibana_react)[\/\\]/,
+ /x-pack[\/\\]plugins[\/\\](apm|beats_management|cases|fleet|infra|lists|observability|osquery|security_solution|timelines|uptime)[\/\\]/,
+ /x-pack[\/\\]test[\/\\]plugin_functional[\/\\]plugins[\/\\]resolver_test[\/\\]/,
+];
diff --git a/packages/kbn-eslint-plugin-eslint/rules/module_migration.js b/packages/kbn-eslint-plugin-eslint/rules/module_migration.js
index 87a1bae8eac1a..3175210eccb10 100644
--- a/packages/kbn-eslint-plugin-eslint/rules/module_migration.js
+++ b/packages/kbn-eslint-plugin-eslint/rules/module_migration.js
@@ -78,6 +78,12 @@ module.exports = {
disallowedMessage: {
type: 'string',
},
+ include: {
+ type: 'array',
+ },
+ exclude: {
+ type: 'array',
+ },
},
anyOf: [
{
@@ -95,7 +101,22 @@ module.exports = {
],
},
create: (context) => {
- const mappings = context.options[0];
+ const filename = path.relative(KIBANA_ROOT, context.getFilename());
+
+ const mappings = context.options[0].filter((mapping) => {
+ // exclude mapping rule if it is explicitly excluded from this file
+ if (mapping.exclude && mapping.exclude.some((p) => p.test(filename))) {
+ return false;
+ }
+
+ // if this mapping rule is only included in specific files, optionally include it
+ if (mapping.include) {
+ return mapping.include.some((p) => p.test(filename));
+ }
+
+ // include all mapping rules by default
+ return true;
+ });
return {
ImportDeclaration(node) {
diff --git a/packages/kbn-storybook/lib/default_config.ts b/packages/kbn-storybook/lib/default_config.ts
index e194c9789daab..989f707b06fed 100644
--- a/packages/kbn-storybook/lib/default_config.ts
+++ b/packages/kbn-storybook/lib/default_config.ts
@@ -6,8 +6,11 @@
* Side Public License, v 1.
*/
+import * as path from 'path';
import { StorybookConfig } from '@storybook/core/types';
+import { REPO_ROOT } from './constants';
+const toPath = (_path: string) => path.join(REPO_ROOT, _path);
export const defaultConfig: StorybookConfig = {
addons: ['@kbn/storybook/preset', '@storybook/addon-a11y', '@storybook/addon-essentials'],
stories: ['../**/*.stories.tsx'],
@@ -22,6 +25,21 @@ export const defaultConfig: StorybookConfig = {
config.node = { fs: 'empty' };
- return config;
+ // Remove when @storybook has moved to @emotion v11
+ // https://github.com/storybookjs/storybook/issues/13145
+ const emotion11CompatibleConfig = {
+ ...config,
+ resolve: {
+ ...config.resolve,
+ alias: {
+ ...config.resolve?.alias,
+ '@emotion/core': toPath('node_modules/@emotion/react'),
+ '@emotion/styled': toPath('node_modules/@emotion/styled'),
+ 'emotion-theming': toPath('node_modules/@emotion/react'),
+ },
+ },
+ };
+
+ return emotion11CompatibleConfig;
},
};
diff --git a/packages/kbn-storybook/lib/theme_switcher.tsx b/packages/kbn-storybook/lib/theme_switcher.tsx
index da62bc7010c4b..24ddec1fdf51c 100644
--- a/packages/kbn-storybook/lib/theme_switcher.tsx
+++ b/packages/kbn-storybook/lib/theme_switcher.tsx
@@ -54,6 +54,7 @@ export function ThemeSwitcher() {
closeOnClick
tooltip={({ onHide }) =>
}
>
+ {/* @ts-ignore Remove when @storybook has moved to @emotion v11 */}
diff --git a/packages/kbn-telemetry-tools/BUILD.bazel b/packages/kbn-telemetry-tools/BUILD.bazel
index d394b0c93d45f..ef1316cec75a3 100644
--- a/packages/kbn-telemetry-tools/BUILD.bazel
+++ b/packages/kbn-telemetry-tools/BUILD.bazel
@@ -47,7 +47,8 @@ TYPES_DEPS = [
"@npm//@types/node",
"@npm//@types/normalize-path",
"@npm//@types/testing-library__jest-dom",
- "@npm//resize-observer-polyfill"
+ "@npm//resize-observer-polyfill",
+ "@npm//@emotion/react",
]
DEPS = SRC_DEPS + TYPES_DEPS
diff --git a/packages/kbn-test/jest-preset.js b/packages/kbn-test/jest-preset.js
index c84fe3f7a55b0..abc5cfa8efaa8 100644
--- a/packages/kbn-test/jest-preset.js
+++ b/packages/kbn-test/jest-preset.js
@@ -66,6 +66,7 @@ module.exports = {
snapshotSerializers: [
'/src/plugins/kibana_react/public/util/test_helpers/react_mount_serializer.ts',
'/node_modules/enzyme-to-json/serializer',
+ '/node_modules/@emotion/jest/serializer',
],
// The test environment that will be used for testing
diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts
new file mode 100644
index 0000000000000..bb2f923ad1f01
--- /dev/null
+++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.test.ts
@@ -0,0 +1,35 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+import { pathWithSpace } from './kbn_client_requester';
+
+describe('pathWithSpace()', () => {
+ it('adds a space to the path', () => {
+ expect(pathWithSpace('hello')`/foo/bar`).toMatchInlineSnapshot(`"/s/hello/foo/bar"`);
+ });
+
+ it('ignores the space when it is empty', () => {
+ expect(pathWithSpace(undefined)`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`);
+ expect(pathWithSpace('')`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`);
+ });
+
+ it('ignores the space when it is the default space', () => {
+ expect(pathWithSpace('default')`/foo/bar`).toMatchInlineSnapshot(`"/foo/bar"`);
+ });
+
+ it('uriencodes variables in the path', () => {
+ expect(pathWithSpace('space')`hello/${'funky/username🏴☠️'}`).toMatchInlineSnapshot(
+ `"/s/space/hello/funky%2Fusername%F0%9F%8F%B4%E2%80%8D%E2%98%A0%EF%B8%8F"`
+ );
+ });
+
+ it('ensures the path always starts with a slash', () => {
+ expect(pathWithSpace('foo')`hello/world`).toMatchInlineSnapshot(`"/s/foo/hello/world"`);
+ expect(pathWithSpace()`hello/world`).toMatchInlineSnapshot(`"/hello/world"`);
+ });
+});
diff --git a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts
index a194b593b3863..c2e4247df1ab0 100644
--- a/packages/kbn-test/src/kbn_client/kbn_client_requester.ts
+++ b/packages/kbn-test/src/kbn_client/kbn_client_requester.ts
@@ -23,6 +23,19 @@ const isIgnorableError = (error: any, ignorableErrors: number[] = []) => {
return isAxiosResponseError(error) && ignorableErrors.includes(error.response.status);
};
+/**
+ * Creates a template literal tag which will uriencode the variables in a template literal
+ * as well as prefix the path with a specific space if one is defined
+ */
+export const pathWithSpace = (space?: string) => {
+ const prefix = !space || space === 'default' ? '' : uriencode`/s/${space}`;
+
+ return (strings: TemplateStringsArray, ...args: Array) => {
+ const path = uriencode(strings, ...args);
+ return path.startsWith('/') || path === '' ? `${prefix}${path}` : `${prefix}/${path}`;
+ };
+};
+
export const uriencode = (
strings: TemplateStringsArray,
...values: Array
diff --git a/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts b/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts
index 78155098ef038..7ea685667d48b 100644
--- a/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts
+++ b/packages/kbn-test/src/kbn_client/kbn_client_ui_settings.ts
@@ -8,7 +8,7 @@
import { ToolingLog } from '@kbn/dev-utils';
-import { KbnClientRequester, uriencode } from './kbn_client_requester';
+import { KbnClientRequester, pathWithSpace } from './kbn_client_requester';
export type UiSettingValues = Record;
interface UiSettingsApiResponse {
@@ -27,8 +27,8 @@ export class KbnClientUiSettings {
private readonly defaults?: UiSettingValues
) {}
- async get(setting: string) {
- const all = await this.getAll();
+ async get(setting: string, { space }: { space?: string } = {}) {
+ const all = await this.getAll({ space });
const value = all[setting]?.userValue;
this.log.verbose('uiSettings.value: %j', value);
@@ -45,9 +45,9 @@ export class KbnClientUiSettings {
/**
* Unset a uiSetting
*/
- async unset(setting: string) {
+ async unset(setting: string, { space }: { space?: string } = {}) {
const { data } = await this.requester.request({
- path: uriencode`/api/kibana/settings/${setting}`,
+ path: pathWithSpace(space)`/api/kibana/settings/${setting}`,
method: 'DELETE',
});
return data;
@@ -57,7 +57,10 @@ export class KbnClientUiSettings {
* Replace all uiSettings with the `doc` values, `doc` is merged
* with some defaults
*/
- async replace(doc: UiSettingValues, { retries = 5 }: { retries?: number } = {}) {
+ async replace(
+ doc: UiSettingValues,
+ { retries = 5, space }: { retries?: number; space?: string } = {}
+ ) {
this.log.debug('replacing kibana config doc: %j', doc);
const changes: Record = {
@@ -73,7 +76,7 @@ export class KbnClientUiSettings {
await this.requester.request({
method: 'POST',
- path: '/api/kibana/settings',
+ path: pathWithSpace(space)`/api/kibana/settings`,
body: { changes },
retries,
});
@@ -82,11 +85,11 @@ export class KbnClientUiSettings {
/**
* Add fields to the config doc (like setting timezone and defaultIndex)
*/
- async update(updates: UiSettingValues) {
+ async update(updates: UiSettingValues, { space }: { space?: string } = {}) {
this.log.debug('applying update to kibana config: %j', updates);
await this.requester.request({
- path: '/api/kibana/settings',
+ path: pathWithSpace(space)`/api/kibana/settings`,
method: 'POST',
body: {
changes: updates,
@@ -95,9 +98,9 @@ export class KbnClientUiSettings {
});
}
- private async getAll() {
+ private async getAll({ space }: { space?: string } = {}) {
const { data } = await this.requester.request({
- path: '/api/kibana/settings',
+ path: pathWithSpace(space)`/api/kibana/settings`,
method: 'GET',
});
diff --git a/packages/kbn-ui-shared-deps/BUILD.bazel b/packages/kbn-ui-shared-deps/BUILD.bazel
index 9096905a2586b..f92049292f373 100644
--- a/packages/kbn-ui-shared-deps/BUILD.bazel
+++ b/packages/kbn-ui-shared-deps/BUILD.bazel
@@ -40,6 +40,7 @@ SRC_DEPS = [
"@npm//@elastic/charts",
"@npm//@elastic/eui",
"@npm//@elastic/numeral",
+ "@npm//@emotion/react",
"@npm//abortcontroller-polyfill",
"@npm//angular",
"@npm//babel-loader",
diff --git a/packages/kbn-ui-shared-deps/src/entry.js b/packages/kbn-ui-shared-deps/src/entry.js
index 0e91c45ae6392..20e26ca6a2864 100644
--- a/packages/kbn-ui-shared-deps/src/entry.js
+++ b/packages/kbn-ui-shared-deps/src/entry.js
@@ -18,6 +18,7 @@ export const KbnI18n = require('@kbn/i18n');
export const KbnI18nAngular = require('@kbn/i18n/angular');
export const KbnI18nReact = require('@kbn/i18n/react');
export const Angular = require('angular');
+export const EmotionReact = require('@emotion/react');
export const Moment = require('moment');
export const MomentTimezone = require('moment-timezone/moment-timezone');
export const KbnMonaco = require('@kbn/monaco');
diff --git a/packages/kbn-ui-shared-deps/src/index.js b/packages/kbn-ui-shared-deps/src/index.js
index 36c2e6b02879e..291c7c471d27c 100644
--- a/packages/kbn-ui-shared-deps/src/index.js
+++ b/packages/kbn-ui-shared-deps/src/index.js
@@ -57,6 +57,7 @@ exports.externals = {
'@kbn/i18n': '__kbnSharedDeps__.KbnI18n',
'@kbn/i18n/angular': '__kbnSharedDeps__.KbnI18nAngular',
'@kbn/i18n/react': '__kbnSharedDeps__.KbnI18nReact',
+ '@emotion/react': '__kbnSharedDeps__.EmotionReact',
jquery: '__kbnSharedDeps__.Jquery',
moment: '__kbnSharedDeps__.Moment',
'moment-timezone': '__kbnSharedDeps__.MomentTimezone',
diff --git a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
index 82353a96dc33c..6e33e39b148c4 100644
--- a/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
+++ b/src/core/public/chrome/ui/header/__snapshots__/collapsible_nav.test.tsx.snap
@@ -746,9 +746,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
onResize={[Function]}
>
-
+
@@ -1021,9 +1019,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
onResize={[Function]}
>
-
+
@@ -1315,9 +1311,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
onResize={[Function]}
>
-
+
@@ -1570,9 +1564,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
onResize={[Function]}
>
-
+
@@ -1786,9 +1778,7 @@ exports[`CollapsibleNav renders links grouped by category 1`] = `
onResize={[Function]}
>
-
+
diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md
index 66d81d058fc77..b8af7c12d57fc 100644
--- a/src/plugins/data/public/public.api.md
+++ b/src/plugins/data/public/public.api.md
@@ -17,7 +17,6 @@ import { CoreSetup } from 'src/core/public';
import { CoreSetup as CoreSetup_2 } from 'kibana/public';
import { CoreStart } from 'kibana/public';
import { CoreStart as CoreStart_2 } from 'src/core/public';
-import * as CSS from 'csstype';
import { Datatable as Datatable_2 } from 'src/plugins/expressions';
import { Datatable as Datatable_3 } from 'src/plugins/expressions/common';
import { DatatableColumn as DatatableColumn_2 } from 'src/plugins/expressions';
@@ -72,13 +71,12 @@ import { Plugin } from 'src/core/public';
import { PluginInitializerContext as PluginInitializerContext_2 } from 'src/core/public';
import { PluginInitializerContext as PluginInitializerContext_3 } from 'kibana/public';
import { PopoverAnchorPosition } from '@elastic/eui';
-import * as PropTypes from 'prop-types';
import { PublicContract } from '@kbn/utility-types';
import { PublicMethodsOf } from '@kbn/utility-types';
import { PublicUiSettingsParams } from 'src/core/server/types';
import { RangeFilter as RangeFilter_2 } from 'src/plugins/data/public';
import React from 'react';
-import * as React_3 from 'react';
+import * as React_2 from 'react';
import { RecursiveReadonly } from '@kbn/utility-types';
import { Request as Request_2 } from '@hapi/hapi';
import { RequestAdapter } from 'src/plugins/inspector/common';
diff --git a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap
index 0ab3f8a4e3466..1e7b59d8a9e76 100644
--- a/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap
+++ b/src/plugins/data/public/utils/table_inspector_view/components/__snapshots__/data_view.test.tsx.snap
@@ -1169,7 +1169,6 @@ exports[`Inspector Data View component should render single table without select
>
{
- // Warning: (ae-forgotten-export) The symbol "React" needs to be exported by the entry point index.d.ts
- constructor(getFactory: EmbeddableStart_2['getEmbeddableFactory'], getAllFactories: EmbeddableStart_2['getEmbeddableFactories'], overlays: OverlayStart_2, notifications: NotificationsStart_2, SavedObjectFinder: React_2.ComponentType, reportUiCounter?: ((appName: string, type: import("@kbn/analytics").UiCounterMetricType, eventNames: string | string[], count?: number | undefined) => void) | undefined);
+ constructor(getFactory: EmbeddableStart_2['getEmbeddableFactory'], getAllFactories: EmbeddableStart_2['getEmbeddableFactories'], overlays: OverlayStart_2, notifications: NotificationsStart_2, SavedObjectFinder: React.ComponentType, reportUiCounter?: ((appName: string, type: import("@kbn/analytics").UiCounterMetricType, eventNames: string | string[], count?: number | undefined) => void) | undefined);
// (undocumented)
execute(context: ActionExecutionContext_2): Promise;
// (undocumented)
diff --git a/src/plugins/expression_reveal_image/.i18nrc.json b/src/plugins/expression_reveal_image/.i18nrc.json
deleted file mode 100755
index 5b073e4374519..0000000000000
--- a/src/plugins/expression_reveal_image/.i18nrc.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "prefix": "expressionRevealImage",
- "paths": {
- "expressionRevealImage": "."
- },
- "translations": ["translations/ja-JP.json"]
-}
diff --git a/src/plugins/kibana_react/common/eui_styled_components.tsx b/src/plugins/kibana_react/common/eui_styled_components.tsx
index 10cd168da6faa..62876a03c7d83 100644
--- a/src/plugins/kibana_react/common/eui_styled_components.tsx
+++ b/src/plugins/kibana_react/common/eui_styled_components.tsx
@@ -6,15 +6,14 @@
* Side Public License, v 1.
*/
+import type { DecoratorFn } from '@storybook/react';
import React from 'react';
import * as styledComponents from 'styled-components';
import { ThemedStyledComponentsModule, ThemeProvider, ThemeProviderProps } from 'styled-components';
-
-import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
-import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
+import { euiThemeVars, euiLightVars, euiDarkVars } from '@kbn/ui-shared-deps/theme';
export interface EuiTheme {
- eui: typeof euiLightVars | typeof euiDarkVars;
+ eui: typeof euiThemeVars;
darkMode: boolean;
}
@@ -36,6 +35,16 @@ const EuiThemeProvider = <
/>
);
+/**
+ * Storybook decorator using the EUI theme provider. Uses the value from
+ * `globals` provided by the Storybook theme switcher.
+ */
+export const EuiThemeProviderDecorator: DecoratorFn = (storyFn, { globals }) => {
+ const darkMode = globals.euiTheme === 'v8.dark' || globals.euiTheme === 'v7.dark';
+
+ return {storyFn()};
+};
+
const {
default: euiStyled,
css,
diff --git a/src/plugins/screenshot_mode/.i18nrc.json b/src/plugins/screenshot_mode/.i18nrc.json
deleted file mode 100644
index 79643fbb63d30..0000000000000
--- a/src/plugins/screenshot_mode/.i18nrc.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "prefix": "screenshotMode",
- "paths": {
- "screenshotMode": "."
- },
- "translations": ["translations/ja-JP.json"]
-}
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
index f167bc35c06e9..a232a1dc03ae3 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/cumulative_sum.js
@@ -23,6 +23,7 @@ import {
EuiFormRow,
EuiSpacer,
} from '@elastic/eui';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
export function CumulativeSumAgg(props) {
const { model, siblings, fields, indexPattern } = props;
@@ -70,7 +71,7 @@ export function CumulativeSumAgg(props) {
onChange={handleSelectChange('field')}
metrics={siblings}
metric={model}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
value={model.field}
exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
index 9bed7015b0245..616f40128ff22 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/derivative.js
@@ -25,6 +25,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
export const DerivativeAgg = (props) => {
const { siblings, fields, indexPattern } = props;
@@ -80,7 +81,7 @@ export const DerivativeAgg = (props) => {
onChange={handleSelectChange('field')}
metrics={siblings}
metric={model}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
value={model.field}
exclude={[METRIC_TYPES.TOP_HIT]}
fullWidth
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
index 79f70f45d6256..a3ce43f97a36a 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/moving_average.js
@@ -26,6 +26,7 @@ import {
EuiFieldNumber,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
const DEFAULTS = {
model_type: MODEL_TYPES.UNWEIGHTED,
@@ -141,7 +142,7 @@ export const MovingAverageAgg = (props) => {
onChange={handleSelectChange('field')}
metrics={siblings}
metric={model}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
value={model.field}
exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
index 156a042abb4e2..c974f5d5f05f5 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/positive_only.js
@@ -23,6 +23,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
export const PositiveOnlyAgg = (props) => {
const { siblings, fields, indexPattern } = props;
@@ -74,7 +75,7 @@ export const PositiveOnlyAgg = (props) => {
onChange={handleSelectChange('field')}
metrics={siblings}
metric={model}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
value={model.field}
exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
index a553b1a4c6671..efc2a72c3dd67 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/serial_diff.js
@@ -24,6 +24,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
export const SerialDiffAgg = (props) => {
const { siblings, fields, indexPattern, model } = props;
@@ -74,7 +75,7 @@ export const SerialDiffAgg = (props) => {
onChange={handleSelectChange('field')}
metrics={siblings}
metric={model}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
value={model.field}
exclude={[METRIC_TYPES.TOP_HIT]}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
index 9a30988d252e5..d2b3f45a70164 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/std_sibling.js
@@ -27,6 +27,7 @@ import {
EuiSpacer,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
const StandardSiblingAggUi = (props) => {
const { siblings, intl, fields, indexPattern } = props;
@@ -147,7 +148,7 @@ const StandardSiblingAggUi = (props) => {
onChange={handleSelectChange('field')}
exclude={[METRIC_TYPES.PERCENTILE, METRIC_TYPES.TOP_HIT]}
metrics={siblings}
- fields={fields[indexPattern]}
+ fields={fields[getIndexPatternKey(indexPattern)]}
metric={model}
value={model.field}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js
index b9d554e254bcc..ba06b0fffd307 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/vars.js
@@ -15,6 +15,7 @@ import { AddDeleteButtons } from '../add_delete_buttons';
import { collectionActions } from '../lib/collection_actions';
import { MetricSelect } from './metric_select';
import { EuiFlexGroup, EuiFlexItem, EuiFieldText } from '@elastic/eui';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
export const newVariable = (opts) => ({ id: uuid.v1(), name: '', field: '', ...opts });
@@ -59,7 +60,7 @@ export class CalculationVars extends Component {
metrics={this.props.metrics}
metric={this.props.model}
value={row.field}
- fields={this.props.fields[this.props.indexPattern]}
+ fields={this.props.fields[getIndexPatternKey(this.props.indexPattern)]}
includeSiblings={this.props.includeSiblings}
exclude={this.props.exclude}
/>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx b/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx
index 9ba0822402562..3633f8add7457 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx
+++ b/src/plugins/vis_type_timeseries/public/application/components/panel_config/table.tsx
@@ -207,6 +207,7 @@ export class TablePanelConfig extends Component<
diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap b/src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap
index 562c463f6c83c..ce381a0e539d0 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap
+++ b/src/plugins/vis_type_timeseries/public/application/components/splits/__snapshots__/terms.test.js.snap
@@ -78,6 +78,7 @@ exports[`src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
labelType="label"
>
@@ -100,6 +101,7 @@ exports[`src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
labelType="label"
>
diff --git a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js b/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js
index 7db6a75e2392c..9c097de38d56a 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/splits/terms.js
@@ -27,6 +27,7 @@ import {
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { KBN_FIELD_TYPES } from '../../../../../data/public';
import { STACKED_OPTIONS } from '../../visualizations/constants';
+import { getIndexPatternKey } from '../../../../common/index_patterns_utils';
const DEFAULTS = { terms_direction: 'desc', terms_size: 10, terms_order_by: '_count' };
@@ -75,10 +76,11 @@ export const SplitByTermsUI = ({
}),
},
];
+ const fieldsSelector = getIndexPatternKey(indexPattern);
const selectedDirectionOption = dirOptions.find((option) => {
return model.terms_direction === option.value;
});
- const selectedField = find(fields[indexPattern], ({ name }) => name === model.terms_field);
+ const selectedField = find(fields[fieldsSelector], ({ name }) => name === model.terms_field);
const selectedFieldType = get(selectedField, 'type');
if (
@@ -144,6 +146,7 @@ export const SplitByTermsUI = ({
@@ -160,6 +163,7 @@ export const SplitByTermsUI = ({
@@ -198,7 +202,7 @@ export const SplitByTermsUI = ({
metrics={metrics}
clearable={false}
additionalOptions={[defaultCount, terms]}
- fields={fields[indexPattern]}
+ fields={fields[fieldsSelector]}
onChange={handleSelectChange('terms_order_by')}
restrict="basic"
value={model.terms_order_by}
diff --git a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js b/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js
index 4dd8f672c9ea3..4db038de912f5 100644
--- a/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js
+++ b/src/plugins/vis_type_timeseries/public/application/components/vis_types/table/vis.js
@@ -58,7 +58,11 @@ class TableVis extends Component {
renderRow = (row) => {
const { model } = this.props;
- let rowDisplay = model.pivot_type === 'date' ? this.dateFormatter.convert(row.key) : row.key;
+
+ let rowDisplay = getValueOrEmpty(
+ model.pivot_type === 'date' ? this.dateFormatter.convert(row.key) : row.key
+ );
+
if (model.drilldown_url) {
const url = replaceVars(model.drilldown_url, {}, { key: row.key });
rowDisplay = {rowDisplay};
@@ -98,7 +102,7 @@ class TableVis extends Component {
});
return (
- {getValueOrEmpty(rowDisplay)} |
+ {rowDisplay} |
{columns}
);
diff --git a/test/functional/apps/discover/_field_data.ts b/test/functional/apps/discover/_field_data.ts
index 5ab6495686726..ec9f9cf65e0fa 100644
--- a/test/functional/apps/discover/_field_data.ts
+++ b/test/functional/apps/discover/_field_data.ts
@@ -33,8 +33,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings();
await PageObjects.common.navigateToApp('discover');
});
- // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/104466
- describe.skip('field data', function () {
+
+ describe('field data', function () {
it('search php should show the correct hit count', async function () {
const expectedHitCount = '445';
await retry.try(async function () {
diff --git a/test/functional/apps/discover/index.ts b/test/functional/apps/discover/index.ts
index b396f172f6961..a17bf53e7f478 100644
--- a/test/functional/apps/discover/index.ts
+++ b/test/functional/apps/discover/index.ts
@@ -12,7 +12,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const browser = getService('browser');
- describe('discover app', function () {
+ // FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/104466
+ describe.skip('discover app', function () {
this.tags('ciGroup6');
before(function () {
diff --git a/test/functional/apps/visualize/_tsvb_table.ts b/test/functional/apps/visualize/_tsvb_table.ts
index abe3b799e4711..de0771d3c8ec5 100644
--- a/test/functional/apps/visualize/_tsvb_table.ts
+++ b/test/functional/apps/visualize/_tsvb_table.ts
@@ -10,12 +10,14 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
-export default function ({ getPageObjects }: FtrProviderContext) {
+export default function ({ getPageObjects, getService }: FtrProviderContext) {
const { visualBuilder, visualize, visChart } = getPageObjects([
'visualBuilder',
'visualize',
'visChart',
]);
+ const findService = getService('find');
+ const retry = getService('retry');
describe('visual builder', function describeIndexTests() {
before(async () => {
@@ -43,6 +45,19 @@ export default function ({ getPageObjects }: FtrProviderContext) {
expect(tableData).to.be(EXPECTED);
});
+ it('should display drilldown urls', async () => {
+ const baseURL = 'http://elastic.co/foo/';
+
+ await visualBuilder.clickPanelOptions('table');
+ await visualBuilder.setDrilldownUrl(`${baseURL}{{key}}`);
+
+ await retry.try(async () => {
+ const links = await findService.allByCssSelector(`a[href="${baseURL}ios"]`);
+
+ expect(links.length).to.be(1);
+ });
+ });
+
it('should display correct values on changing metrics aggregation', async () => {
const EXPECTED = 'OS Cardinality\nwin 8 12\nwin xp 9\nwin 7 8\nios 5\nosx 3';
diff --git a/test/functional/apps/visualize/_tsvb_time_series.ts b/test/functional/apps/visualize/_tsvb_time_series.ts
index a0c9d806facc6..cc57d58348180 100644
--- a/test/functional/apps/visualize/_tsvb_time_series.ts
+++ b/test/functional/apps/visualize/_tsvb_time_series.ts
@@ -155,7 +155,10 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
describe('Clicking on the chart', () => {
it(`should create a filter`, async () => {
- await visualBuilder.setMetricsGroupByTerms('machine.os.raw');
+ await visualBuilder.setMetricsGroupByTerms('machine.os.raw', {
+ include: 'win 7',
+ exclude: 'ios',
+ });
await visualBuilder.clickSeriesOption();
await testSubjects.click('visualizeSaveButton');
diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts
index ea11560e37b6f..8e28ffab6c9c3 100644
--- a/test/functional/page_objects/visual_builder_page.ts
+++ b/test/functional/page_objects/visual_builder_page.ts
@@ -277,6 +277,13 @@ export class VisualBuilderPageObject extends FtrService {
await this.comboBox.setElement(formatterEl, formatter, { clickWithMouse: true });
}
+ public async setDrilldownUrl(value: string) {
+ const drilldownEl = await this.testSubjects.find('drilldownUrl');
+
+ await drilldownEl.clearValue();
+ await drilldownEl.type(value);
+ }
+
/**
* set duration formatter additional settings
*
@@ -628,7 +635,10 @@ export class VisualBuilderPageObject extends FtrService {
return await this.find.allByCssSelector('.tvbSeriesEditor');
}
- public async setMetricsGroupByTerms(field: string) {
+ public async setMetricsGroupByTerms(
+ field: string,
+ filtering: { include?: string; exclude?: string } = {}
+ ) {
const groupBy = await this.find.byCssSelector(
'.tvbAggRow--split [data-test-subj="comboBoxInput"]'
);
@@ -636,6 +646,22 @@ export class VisualBuilderPageObject extends FtrService {
await this.common.sleep(1000);
const byField = await this.testSubjects.find('groupByField');
await this.comboBox.setElement(byField, field);
+
+ await this.setMetricsGroupByFiltering(filtering.include, filtering.exclude);
+ }
+
+ public async setMetricsGroupByFiltering(include?: string, exclude?: string) {
+ const setFilterValue = async (value: string | undefined, subjectKey: string) => {
+ if (typeof value === 'string') {
+ const valueSubject = await this.testSubjects.find(subjectKey);
+
+ await valueSubject.clearValue();
+ await valueSubject.type(value);
+ }
+ };
+
+ await setFilterValue(include, 'groupByInclude');
+ await setFilterValue(exclude, 'groupByExclude');
}
public async checkSelectedMetricsGroupByValue(value: string) {
diff --git a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json
index b704274a58aa4..e92dc717ae25e 100644
--- a/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json
+++ b/test/plugin_functional/plugins/kbn_tp_custom_visualizations/tsconfig.json
@@ -6,7 +6,8 @@
"types": [
"node",
"jest",
- "react"
+ "react",
+ "@emotion/react/types/css-prop"
]
},
"include": [
diff --git a/test/tsconfig.json b/test/tsconfig.json
index 8cf33d93a4067..dccbe8d715c51 100644
--- a/test/tsconfig.json
+++ b/test/tsconfig.json
@@ -6,7 +6,7 @@
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true,
- "types": ["node", "resize-observer-polyfill"]
+ "types": ["node", "resize-observer-polyfill", "@emotion/react/types/css-prop"]
},
"include": [
"**/*",
diff --git a/tsconfig.base.json b/tsconfig.base.json
index cc8b66848a394..0c8fec7c88cda 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -12,7 +12,10 @@
// Allows for importing from `kibana` package for the exported types.
"kibana": ["./kibana"],
"kibana/public": ["src/core/public"],
- "kibana/server": ["src/core/server"]
+ "kibana/server": ["src/core/server"],
+ "@emotion/core": [
+ "typings/@emotion"
+ ],
},
// Support .tsx files and transform JSX into calls to React.createElement
"jsx": "react",
@@ -62,7 +65,8 @@
"flot",
"jest-styled-components",
"@testing-library/jest-dom",
- "resize-observer-polyfill"
+ "resize-observer-polyfill",
+ "@emotion/react/types/css-prop"
]
}
}
diff --git a/typings/@emotion/index.d.ts b/typings/@emotion/index.d.ts
new file mode 100644
index 0000000000000..2a5e63a3e29ef
--- /dev/null
+++ b/typings/@emotion/index.d.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.
+ */
+
+// Stub @emotion/core
+// Remove when @storybook has moved to @emotion v11
+// https://github.com/storybookjs/storybook/issues/13145
+export {};
diff --git a/x-pack/plugins/apm/.storybook/jest_setup.js b/x-pack/plugins/apm/.storybook/jest_setup.js
new file mode 100644
index 0000000000000..32071b8aa3f62
--- /dev/null
+++ b/x-pack/plugins/apm/.storybook/jest_setup.js
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { setGlobalConfig } from '@storybook/testing-react';
+import * as globalStorybookConfig from './preview';
+
+setGlobalConfig(globalStorybookConfig);
diff --git a/x-pack/plugins/apm/.storybook/preview.js b/x-pack/plugins/apm/.storybook/preview.js
new file mode 100644
index 0000000000000..18343c15a6465
--- /dev/null
+++ b/x-pack/plugins/apm/.storybook/preview.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiThemeProviderDecorator } from '../../../../src/plugins/kibana_react/common';
+
+export const decorators = [EuiThemeProviderDecorator];
diff --git a/x-pack/plugins/apm/jest.config.js b/x-pack/plugins/apm/jest.config.js
index caa8256cdb7ea..5bce9bbfb5b1b 100644
--- a/x-pack/plugins/apm/jest.config.js
+++ b/x-pack/plugins/apm/jest.config.js
@@ -11,4 +11,6 @@ module.exports = {
preset: '@kbn/test',
rootDir: path.resolve(__dirname, '../../..'),
roots: ['/x-pack/plugins/apm'],
+ setupFiles: ['/x-pack/plugins/apm/.storybook/jest_setup.js'],
+ testPathIgnorePatterns: ['/x-pack/plugins/apm/e2e/'],
};
diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json
index ae4510b10acd4..9f661f13a491e 100644
--- a/x-pack/plugins/apm/kibana.json
+++ b/x-pack/plugins/apm/kibana.json
@@ -7,7 +7,6 @@
"data",
"embeddable",
"features",
- "fleet",
"infra",
"licensing",
"observability",
@@ -24,11 +23,15 @@
"security",
"spaces",
"taskManager",
- "usageCollection"
+ "usageCollection",
+ "fleet"
],
"server": true,
"ui": true,
- "configPath": ["xpack", "apm"],
+ "configPath": [
+ "xpack",
+ "apm"
+ ],
"requiredBundles": [
"fleet",
"home",
@@ -38,4 +41,4 @@
"ml",
"observability"
]
-}
+}
\ No newline at end of file
diff --git a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.stories.tsx b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.stories.tsx
index 83874e9584510..23afb9646dea7 100644
--- a/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.stories.tsx
+++ b/x-pack/plugins/apm/public/components/alerting/error_count_alert_trigger/index.stories.tsx
@@ -8,7 +8,6 @@
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { ErrorCountAlertTrigger } from '.';
-import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common';
import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context';
import {
mockApmPluginContextValue,
@@ -20,19 +19,15 @@ export default {
component: ErrorCountAlertTrigger,
decorators: [
(Story: React.ComponentClass) => (
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
),
],
};
diff --git a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__stories__/MapTooltip.stories.tsx b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__stories__/MapTooltip.stories.tsx
index 1aad25fc89c0b..8263db648cd39 100644
--- a/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__stories__/MapTooltip.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/RumDashboard/VisitorBreakdownMap/__stories__/MapTooltip.stories.tsx
@@ -7,53 +7,50 @@
import { storiesOf } from '@storybook/react';
import React from 'react';
-import { EuiThemeProvider } from '../../../../../../../../../src/plugins/kibana_react/common';
import { MapToolTip } from '../MapToolTip';
import { COUNTRY_NAME, TRANSACTION_DURATION_COUNTRY } from '../useLayerList';
-storiesOf('app/RumDashboard/VisitorsRegionMap', module)
- .addDecorator((storyFn) => {storyFn()})
- .add(
- 'Tooltip',
- () => {
- const loadFeatureProps = async () => {
- return [
+storiesOf('app/RumDashboard/VisitorsRegionMap', module).add(
+ 'Tooltip',
+ () => {
+ const loadFeatureProps = async () => {
+ return [
+ {
+ getPropertyKey: () => COUNTRY_NAME,
+ getRawValue: () => 'United States',
+ },
+ {
+ getPropertyKey: () => TRANSACTION_DURATION_COUNTRY,
+ getRawValue: () => 2434353,
+ },
+ ];
+ };
+ return (
+ COUNTRY_NAME,
- getRawValue: () => 'United States',
- },
- {
- getPropertyKey: () => TRANSACTION_DURATION_COUNTRY,
- getRawValue: () => 2434353,
- },
- ];
- };
- return (
-
- );
+ actions: [],
+ },
+ ]}
+ />
+ );
+ },
+ {
+ info: {
+ propTables: false,
+ source: false,
},
- {
- info: {
- propTables: false,
- source: false,
- },
- }
- );
+ }
+);
diff --git a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/AgentConfigurationCreateEdit/index.stories.tsx b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/AgentConfigurationCreateEdit/index.stories.tsx
index cd5fa5db89a31..02ecf902f00a3 100644
--- a/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/AgentConfigurationCreateEdit/index.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/Settings/agent_configurations/AgentConfigurationCreateEdit/index.stories.tsx
@@ -8,7 +8,6 @@
import { storiesOf } from '@storybook/react';
import React from 'react';
import { CoreStart } from 'kibana/public';
-import { EuiThemeProvider } from '../../../../../../../../../src/plugins/kibana_react/common';
import { AgentConfiguration } from '../../../../../../common/agent_configuration/configuration_types';
import { FETCH_STATUS } from '../../../../../hooks/use_fetcher';
import { createCallApmApi } from '../../../../../services/rest/createCallApmApi';
@@ -37,13 +36,11 @@ storiesOf(
};
return (
-
-
- {storyFn()}
-
-
+
+ {storyFn()}
+
);
})
.add(
@@ -67,7 +64,6 @@ storiesOf(
propTablesExclude: [
AgentConfigurationCreateEdit,
ApmPluginContext.Provider,
- EuiThemeProvider,
],
source: false,
},
diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.stories.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.stories.tsx
index 8cc16dd801c25..d434a155c9cf4 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/error_group_details/Distribution/index.stories.tsx
@@ -11,7 +11,6 @@ import {
ApmPluginContext,
ApmPluginContextValue,
} from '../../../../context/apm_plugin/apm_plugin_context';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { ErrorDistribution } from './';
export default {
@@ -28,13 +27,11 @@ export default {
};
return (
-
-
-
-
-
-
-
+
+
+
+
+
);
},
],
diff --git a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/exception_stacktrace.stories.tsx b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/exception_stacktrace.stories.tsx
index f21c189584d31..9468202edf4d6 100644
--- a/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/exception_stacktrace.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/error_group_details/detail_view/exception_stacktrace.stories.tsx
@@ -7,7 +7,6 @@
import { Story } from '@storybook/react';
import React, { ComponentProps, ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { ExceptionStacktrace } from './exception_stacktrace';
type Args = ComponentProps;
@@ -15,13 +14,6 @@ type Args = ComponentProps;
export default {
title: 'app/ErrorGroupDetails/DetailView/ExceptionStacktrace',
component: ExceptionStacktrace,
- decorators: [
- (StoryComponent: ComponentType) => (
-
-
-
- ),
- ],
};
export const JavaWithLongLines: Story = (args) => (
diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/Popover.stories.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/Popover.stories.tsx
index 6b7626514d03f..324a38ea5db39 100644
--- a/x-pack/plugins/apm/public/components/app/service_map/Popover/Popover.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/Popover.stories.tsx
@@ -8,7 +8,6 @@
import cytoscape from 'cytoscape';
import { CoreStart } from 'kibana/public';
import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context';
import { MockUrlParamsContextProvider } from '../../../../context/url_params_context/mock_url_params_context_provider';
import { createCallApmApi } from '../../../../services/rest/createCallApmApi';
@@ -38,15 +37,13 @@ export default {
createCallApmApi(coreMock);
return (
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
);
},
],
diff --git a/x-pack/plugins/apm/public/components/app/service_map/Popover/service_stats_list.stories.tsx b/x-pack/plugins/apm/public/components/app/service_map/Popover/service_stats_list.stories.tsx
index a8f004a7295d9..f1a89043f826e 100644
--- a/x-pack/plugins/apm/public/components/app/service_map/Popover/service_stats_list.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_map/Popover/service_stats_list.stories.tsx
@@ -5,20 +5,12 @@
* 2.0.
*/
-import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
import { ServiceStatsList } from './ServiceStatsList';
export default {
title: 'app/ServiceMap/Popover/ServiceStatsList',
component: ServiceStatsList,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function Example() {
diff --git a/x-pack/plugins/apm/public/components/app/service_map/__stories__/Cytoscape.stories.tsx b/x-pack/plugins/apm/public/components/app/service_map/__stories__/Cytoscape.stories.tsx
index 8bc0d7239e9c5..7ce9c3e943613 100644
--- a/x-pack/plugins/apm/public/components/app/service_map/__stories__/Cytoscape.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_map/__stories__/Cytoscape.stories.tsx
@@ -6,21 +6,13 @@
*/
import cytoscape from 'cytoscape';
-import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
import { Cytoscape } from '../Cytoscape';
import { Centerer } from './centerer';
export default {
title: 'app/ServiceMap/Cytoscape',
component: Cytoscape,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function Example() {
diff --git a/x-pack/plugins/apm/public/components/app/service_map/__stories__/cytoscape_example_data.stories.tsx b/x-pack/plugins/apm/public/components/app/service_map/__stories__/cytoscape_example_data.stories.tsx
index 45de632a152d4..192447ef7591a 100644
--- a/x-pack/plugins/apm/public/components/app/service_map/__stories__/cytoscape_example_data.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/service_map/__stories__/cytoscape_example_data.stories.tsx
@@ -16,8 +16,7 @@ import {
EuiSpacer,
EuiToolTip,
} from '@elastic/eui';
-import React, { ComponentType, useEffect, useState } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
+import React, { useEffect, useState } from 'react';
import { Cytoscape } from '../Cytoscape';
import { Centerer } from './centerer';
import exampleResponseHipsterStore from './example_response_hipster_store.json';
@@ -42,13 +41,6 @@ function getHeight() {
export default {
title: 'app/ServiceMap/Example data',
component: Cytoscape,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function GenerateMap() {
diff --git a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx
index 5ea2fca2dfa32..20ca3194fbfdf 100644
--- a/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx
+++ b/x-pack/plugins/apm/public/components/app/transaction_details/waterfall_with_summary/waterfall_container/WaterfallContainer.stories.tsx
@@ -7,7 +7,6 @@
import React, { ComponentType } from 'react';
import { MemoryRouter } from 'react-router-dom';
-import { EuiThemeProvider } from '../../../../../../../../../src/plugins/kibana_react/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { TraceAPIResponse } from '../../../../../../server/lib/traces/get_trace';
import { MockApmPluginContextWrapper } from '../../../../../context/apm_plugin/mock_apm_plugin_context';
@@ -27,11 +26,9 @@ export default {
decorators: [
(Story: ComponentType) => (
-
-
-
-
-
+
+
+
),
],
diff --git a/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx b/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx
index bc41fd58ea5d2..68c3edabfa44e 100644
--- a/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx
+++ b/x-pack/plugins/apm/public/components/shared/agent_icon/agent_icon.stories.tsx
@@ -7,30 +7,22 @@
import {
EuiCard,
+ EuiCodeBlock,
EuiFlexGroup,
- EuiImage,
EuiFlexItem,
+ EuiImage,
EuiSpacer,
EuiToolTip,
- EuiCodeBlock,
} from '@elastic/eui';
-import React, { ComponentType } from 'react';
-import { AgentIcon } from './index';
-import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
import { AGENT_NAMES } from '../../../../common/agent_name';
-import { getAgentIcon } from './get_agent_icon';
import { useTheme } from '../../../hooks/use_theme';
+import { getAgentIcon } from './get_agent_icon';
+import { AgentIcon } from './index';
export default {
title: 'shared/icons',
component: AgentIcon,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function AgentIcons() {
diff --git a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx
index 0eb5b0e84ff39..6128526c577e4 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/custom_tooltip.stories.tsx
@@ -6,8 +6,7 @@
*/
import { TooltipInfo } from '@elastic/charts';
-import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
import { getDurationFormatter } from '../../../../../common/utils/formatters';
import { MainStatsServiceInstanceItem } from '../../../app/service_overview/service_overview_instances_chart_and_table';
import { CustomTooltip } from './custom_tooltip';
@@ -25,13 +24,6 @@ function getLatencyFormatter(props: TooltipInfo) {
export default {
title: 'shared/charts/InstancesLatencyDistributionChart/CustomTooltip',
component: CustomTooltip,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function Example(props: TooltipInfo) {
diff --git a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/instances_latency_distribution_chart.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/instances_latency_distribution_chart.stories.tsx
index c574645d485d5..80bfcca05aabc 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/instances_latency_distribution_chart.stories.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/instances_latency_distribution_chart/instances_latency_distribution_chart.stories.tsx
@@ -5,8 +5,7 @@
* 2.0.
*/
-import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
import { FETCH_STATUS } from '../../../../hooks/use_fetcher';
import {
InstancesLatencyDistributionChart,
@@ -16,13 +15,6 @@ import {
export default {
title: 'shared/charts/InstancesLatencyDistributionChart',
component: InstancesLatencyDistributionChart,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function Example({ items }: InstancesLatencyDistributionChartProps) {
diff --git a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx
index d1dcd831eadd7..ff2b95667a63a 100644
--- a/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx
+++ b/x-pack/plugins/apm/public/components/shared/charts/latency_chart/latency_chart.stories.tsx
@@ -8,7 +8,6 @@
import { StoryContext } from '@storybook/react';
import React, { ComponentType } from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public';
import { LatencyAggregationType } from '../../../../../common/latency_aggregation_types';
import {
@@ -76,20 +75,18 @@ export default {
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/x-pack/plugins/apm/public/components/shared/span_icon/span_icon.stories.tsx b/x-pack/plugins/apm/public/components/shared/span_icon/span_icon.stories.tsx
index b053f441e9632..7d2e2fbefc359 100644
--- a/x-pack/plugins/apm/public/components/shared/span_icon/span_icon.stories.tsx
+++ b/x-pack/plugins/apm/public/components/shared/span_icon/span_icon.stories.tsx
@@ -6,32 +6,23 @@
*/
import {
- EuiImage,
EuiCard,
+ EuiCodeBlock,
EuiFlexGroup,
EuiFlexItem,
+ EuiImage,
EuiSpacer,
- EuiCodeBlock,
EuiToolTip,
} from '@elastic/eui';
-import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../../src/plugins/kibana_react/common';
+import React from 'react';
+import { getSpanIcon, spanTypeIcons } from './get_span_icon';
import { SpanIcon } from './index';
-import { getSpanIcon } from './get_span_icon';
-import { spanTypeIcons } from './get_span_icon';
const spanTypes = Object.keys(spanTypeIcons);
export default {
title: 'shared/icons',
component: SpanIcon,
- decorators: [
- (Story: ComponentType) => (
-
-
-
- ),
- ],
};
export function SpanIcons() {
diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts
index 0cd5009570613..91b045b8db46f 100644
--- a/x-pack/plugins/apm/public/plugin.ts
+++ b/x-pack/plugins/apm/public/plugin.ts
@@ -74,7 +74,7 @@ export interface ApmPluginStartDeps {
ml?: MlPluginStart;
triggersActionsUi: TriggersAndActionsUIPublicPluginStart;
observability: ObservabilityPublicStart;
- fleet: FleetStart;
+ fleet?: FleetStart;
}
export class ApmPlugin implements Plugin {
@@ -311,20 +311,21 @@ export class ApmPlugin implements Plugin {
}
public start(core: CoreStart, plugins: ApmPluginStartDeps) {
const { fleet } = plugins;
-
- const agentEnrollmentExtensionData = getApmEnrollmentFlyoutData();
-
- fleet.registerExtension({
- package: 'apm',
- view: 'agent-enrollment-flyout',
- title: agentEnrollmentExtensionData.title,
- Component: agentEnrollmentExtensionData.Component,
- });
-
- fleet.registerExtension({
- package: 'apm',
- view: 'package-detail-assets',
- Component: LazyApmCustomAssetsExtension,
- });
+ if (fleet) {
+ const agentEnrollmentExtensionData = getApmEnrollmentFlyoutData();
+
+ fleet.registerExtension({
+ package: 'apm',
+ view: 'agent-enrollment-flyout',
+ title: agentEnrollmentExtensionData.title,
+ Component: agentEnrollmentExtensionData.Component,
+ });
+
+ fleet.registerExtension({
+ package: 'apm',
+ view: 'package-detail-assets',
+ Component: LazyApmCustomAssetsExtension,
+ });
+ }
}
}
diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx
index 33f171ab88247..0d4d3748422ea 100644
--- a/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx
+++ b/x-pack/plugins/apm/public/tutorial/config_agent/config_agent.stories.tsx
@@ -18,6 +18,7 @@ interface Args {
onPrem: boolean;
hasFleetPoliciesWithApmIntegration: boolean;
hasCloudPolicyWithApmIntegration: boolean;
+ isFleetEnabled: boolean;
}
const policyElasticAgentOnCloudAgent: APIResponseType['fleetAgents'][0] = {
@@ -47,6 +48,7 @@ function Wrapper({
apmAgent,
onPrem,
hasCloudPolicyWithApmIntegration,
+ isFleetEnabled,
}: Args) {
const http = ({
get: () => ({
@@ -56,6 +58,7 @@ function Wrapper({
? [policyElasticAgentOnCloudAgent]
: []),
],
+ isFleetEnabled,
cloudStandaloneSetup: {
apmServerUrl: 'cloud_url',
secretToken: 'foo',
@@ -80,6 +83,7 @@ Integration.args = {
onPrem: true,
hasFleetPoliciesWithApmIntegration: false,
hasCloudPolicyWithApmIntegration: false,
+ isFleetEnabled: true,
};
export default {
@@ -113,5 +117,8 @@ export default {
hasCloudPolicyWithApmIntegration: {
control: { type: 'boolean', options: [true, false] },
},
+ isFleetEnabled: {
+ control: { type: 'boolean', options: [true, false], defaultValue: true },
+ },
},
};
diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts b/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts
index 90c9aab80f6f5..c6dc7265f3d3e 100644
--- a/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts
+++ b/x-pack/plugins/apm/public/tutorial/config_agent/get_policy_options.test.ts
@@ -41,6 +41,7 @@ describe('getPolicyOptions', () => {
apmServerUrl: 'cloud_url',
secretToken: 'cloud_token',
},
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -65,6 +66,7 @@ describe('getPolicyOptions', () => {
apmServerUrl: 'cloud_url',
secretToken: 'cloud_token',
},
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -109,6 +111,7 @@ describe('getPolicyOptions', () => {
apmServerUrl: 'cloud_url',
secretToken: 'cloud_token',
},
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -151,6 +154,7 @@ describe('getPolicyOptions', () => {
const data: APIResponseType = {
fleetAgents: [],
cloudStandaloneSetup: undefined,
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -173,6 +177,7 @@ describe('getPolicyOptions', () => {
const data: APIResponseType = {
fleetAgents,
cloudStandaloneSetup: undefined,
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -213,6 +218,7 @@ describe('getPolicyOptions', () => {
const data: APIResponseType = {
fleetAgents: [policyElasticAgentOnCloudAgent, ...fleetAgents],
cloudStandaloneSetup: undefined,
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: true,
@@ -256,6 +262,7 @@ describe('getPolicyOptions', () => {
const data: APIResponseType = {
fleetAgents: [],
cloudStandaloneSetup: undefined,
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: false,
@@ -278,6 +285,7 @@ describe('getPolicyOptions', () => {
const data: APIResponseType = {
fleetAgents,
cloudStandaloneSetup: undefined,
+ isFleetEnabled: true,
};
const options = getPolicyOptions({
isCloudEnabled: false,
diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx
index 8f8afe58506a6..cb49cee108bd1 100644
--- a/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx
+++ b/x-pack/plugins/apm/public/tutorial/config_agent/index.test.tsx
@@ -7,6 +7,10 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { HttpStart } from 'kibana/public';
import React from 'react';
+import {
+ expectTextsInDocument,
+ expectTextsNotInDocument,
+} from '../../utils/testHelpers';
import TutorialConfigAgent from './';
const policyElasticAgentOnCloudAgent = {
@@ -32,68 +36,32 @@ const fleetAgents = [
];
describe('TutorialConfigAgent', () => {
- it('renders loading component while API is being called', () => {
- const component = render(
-
- );
- expect(component.getByTestId('loading')).toBeInTheDocument();
+ beforeAll(() => {
+ // Mocks console.error so it won't polute tests output when testing the api throwing error
+ jest.spyOn(console, 'error').mockImplementation(() => null);
});
- it('updates commands when a different policy is selected', async () => {
- const component = render(
-
- );
- expect(
- await screen.findByText('Default Standalone configuration')
- ).toBeInTheDocument();
- let commands = component.getByTestId('commands').innerHTML;
- expect(commands).not.toEqual('');
- expect(commands).toMatchInlineSnapshot(`
- "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
- -Delastic.apm.service_name=my-application \\\\
- -Delastic.apm.server_urls=http://localhost:8200 \\\\
- -Delastic.apm.secret_token= \\\\
- -Delastic.apm.environment=production \\\\
- -Delastic.apm.application_packages=org.example \\\\
- -jar my-application.jar"
- `);
- fireEvent.click(component.getByTestId('comboBoxToggleListButton'));
- fireEvent.click(component.getByText('agent foo'));
- commands = component.getByTestId('commands').innerHTML;
- expect(commands).not.toEqual('');
- expect(commands).toMatchInlineSnapshot(`
- "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
- -Delastic.apm.service_name=my-application \\\\
- -Delastic.apm.server_urls=foo \\\\
- -Delastic.apm.secret_token=foo \\\\
- -Delastic.apm.environment=production \\\\
- -Delastic.apm.application_packages=org.example \\\\
- -jar my-application.jar"
- `);
+ afterAll(() => {
+ jest.restoreAllMocks();
});
- describe('running on prem', () => {
- it('selects defaul standalone by defauls', async () => {
+
+ describe('when fleet plugin is enabled', () => {
+ it('renders loading component while API is being called', () => {
+ const component = render(
+
+ );
+ expect(component.getByTestId('loading')).toBeInTheDocument();
+ });
+ it('updates commands when a different policy is selected', async () => {
const component = render(
{
get: jest.fn().mockReturnValue({
cloudStandaloneSetup: undefined,
fleetAgents,
+ isFleetEnabled: true,
}),
} as unknown) as HttpStart
}
@@ -112,10 +81,7 @@ describe('TutorialConfigAgent', () => {
expect(
await screen.findByText('Default Standalone configuration')
).toBeInTheDocument();
- expect(
- component.getByTestId('policySelector_onPrem')
- ).toBeInTheDocument();
- const commands = component.getByTestId('commands').innerHTML;
+ let commands = component.getByTestId('commands').innerHTML;
expect(commands).not.toEqual('');
expect(commands).toMatchInlineSnapshot(`
"java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
@@ -126,21 +92,238 @@ describe('TutorialConfigAgent', () => {
-Delastic.apm.application_packages=org.example \\\\
-jar my-application.jar"
`);
+
+ fireEvent.click(component.getByTestId('comboBoxToggleListButton'));
+ fireEvent.click(component.getByText('agent foo'));
+ commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=foo \\\\
+ -Delastic.apm.secret_token=foo \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ });
+ describe('running on prem', () => {
+ it('selects defaul standalone by defauls', async () => {
+ const component = render(
+
+ );
+ expect(
+ await screen.findByText('Default Standalone configuration')
+ ).toBeInTheDocument();
+ expect(
+ component.getByTestId('policySelector_onPrem')
+ ).toBeInTheDocument();
+ const commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=http://localhost:8200 \\\\
+ -Delastic.apm.secret_token= \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ });
+ it('shows get started with fleet link when there are no fleet agents', async () => {
+ const component = render(
+
+ );
+ expect(
+ await screen.findByText('Default Standalone configuration')
+ ).toBeInTheDocument();
+ expect(
+ component.getByTestId('policySelector_onPrem')
+ ).toBeInTheDocument();
+ const commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=http://localhost:8200 \\\\
+ -Delastic.apm.secret_token= \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ expectTextsInDocument(component, ['Get started with fleet']);
+ });
+ });
+ describe('running on cloud', () => {
+ it('selects defaul standalone by defauls', async () => {
+ const component = render(
+
+ );
+ expect(
+ await screen.findByText('Default Standalone configuration')
+ ).toBeInTheDocument();
+ expect(
+ component.getByTestId('policySelector_cloud')
+ ).toBeInTheDocument();
+ const commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=cloud_url \\\\
+ -Delastic.apm.secret_token=cloud_token \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ });
+ it('selects policy elastic agent on cloud when available by default', async () => {
+ const component = render(
+
+ );
+ expect(
+ await screen.findByText('Elastic Cloud agent policy')
+ ).toBeInTheDocument();
+ expect(
+ component.getByTestId('policySelector_policy-elastic-agent-on-cloud')
+ ).toBeInTheDocument();
+ const commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=apm_cloud_url \\\\
+ -Delastic.apm.secret_token=apm_cloud_token \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ });
+
+ it('shows default standalone option when api throws an error', async () => {
+ const component = render(
+ {
+ throw new Error('Boom');
+ },
+ } as unknown) as HttpStart
+ }
+ basePath="http://localhost:5601"
+ isCloudEnabled
+ />
+ );
+ expect(
+ await screen.findByText('Default Standalone configuration')
+ ).toBeInTheDocument();
+ const commands = component.getByTestId('commands').innerHTML;
+ expect(commands).not.toEqual('');
+ expect(commands).toMatchInlineSnapshot(`
+ "java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
+ -Delastic.apm.service_name=my-application \\\\
+ -Delastic.apm.server_urls=http://localhost:8200 \\\\
+ -Delastic.apm.secret_token= \\\\
+ -Delastic.apm.environment=production \\\\
+ -Delastic.apm.application_packages=org.example \\\\
+ -jar my-application.jar"
+ `);
+ });
});
});
- describe('running on cloud', () => {
- it('selects defaul standalone by defauls', async () => {
+ describe('when fleet plugin is disabled', () => {
+ it('hides fleet links', async () => {
const component = render(
+ );
+
+ expectTextsNotInDocument(component, [
+ 'Get started with fleet',
+ 'Manage fleet policies',
+ ]);
+ });
+ it('shows default standalone on prem', async () => {
+ const component = render(
+ {
expect(
await screen.findByText('Default Standalone configuration')
).toBeInTheDocument();
- expect(component.getByTestId('policySelector_cloud')).toBeInTheDocument();
+ expect(
+ component.getByTestId('policySelector_onPrem')
+ ).toBeInTheDocument();
const commands = component.getByTestId('commands').innerHTML;
expect(commands).not.toEqual('');
expect(commands).toMatchInlineSnapshot(`
"java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
-Delastic.apm.service_name=my-application \\\\
- -Delastic.apm.server_urls=cloud_url \\\\
- -Delastic.apm.secret_token=cloud_token \\\\
+ -Delastic.apm.server_urls=http://localhost:8200 \\\\
+ -Delastic.apm.secret_token= \\\\
-Delastic.apm.environment=production \\\\
-Delastic.apm.application_packages=org.example \\\\
-jar my-application.jar"
`);
});
- it('selects policy elastic agent on cloud when available by default', async () => {
+ it('shows default standalone on cloud', async () => {
const component = render(
{
apmServerUrl: 'cloud_url',
secretToken: 'cloud_token',
},
- fleetAgents: [...fleetAgents, policyElasticAgentOnCloudAgent],
+ fleetAgents: [],
+ isFleetEnabled: false,
}),
} as unknown) as HttpStart
}
@@ -184,18 +370,16 @@ describe('TutorialConfigAgent', () => {
/>
);
expect(
- await screen.findByText('Elastic Cloud agent policy')
- ).toBeInTheDocument();
- expect(
- component.getByTestId('policySelector_policy-elastic-agent-on-cloud')
+ await screen.findByText('Default Standalone configuration')
).toBeInTheDocument();
+ expect(component.getByTestId('policySelector_cloud')).toBeInTheDocument();
const commands = component.getByTestId('commands').innerHTML;
expect(commands).not.toEqual('');
expect(commands).toMatchInlineSnapshot(`
"java -javaagent:/path/to/elastic-apm-agent-<version>.jar \\\\
-Delastic.apm.service_name=my-application \\\\
- -Delastic.apm.server_urls=apm_cloud_url \\\\
- -Delastic.apm.secret_token=apm_cloud_token \\\\
+ -Delastic.apm.server_urls=cloud_url \\\\
+ -Delastic.apm.secret_token=cloud_token \\\\
-Delastic.apm.environment=production \\\\
-Delastic.apm.application_packages=org.example \\\\
-jar my-application.jar"
diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx
index 755c3eca55868..d38d51f01c67b 100644
--- a/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx
+++ b/x-pack/plugins/apm/public/tutorial/config_agent/index.tsx
@@ -46,16 +46,43 @@ interface Props {
isCloudEnabled: boolean;
}
+const INITIAL_STATE = {
+ fleetAgents: [],
+ cloudStandaloneSetup: undefined,
+ isFleetEnabled: false,
+};
+
+function getFleetLink({
+ isFleetEnabled,
+ hasFleetAgents,
+ basePath,
+}: {
+ isFleetEnabled: boolean;
+ hasFleetAgents: boolean;
+ basePath: string;
+}) {
+ if (!isFleetEnabled) {
+ return;
+ }
+
+ return hasFleetAgents
+ ? {
+ label: MANAGE_FLEET_POLICIES_LABEL,
+ href: `${basePath}/app/fleet#/policies`,
+ }
+ : {
+ label: GET_STARTED_WITH_FLEET_LABEL,
+ href: `${basePath}/app/integrations#/detail/apm-0.3.0/overview`,
+ };
+}
+
function TutorialConfigAgent({
variantId,
http,
basePath,
isCloudEnabled,
}: Props) {
- const [data, setData] = useState({
- fleetAgents: [],
- cloudStandaloneSetup: undefined,
- });
+ const [data, setData] = useState(INITIAL_STATE);
const [isLoading, setIsLoading] = useState(true);
const [selectedOption, setSelectedOption] = useState();
@@ -68,6 +95,7 @@ function TutorialConfigAgent({
setData(response as APIResponseType);
}
} catch (e) {
+ setIsLoading(false);
console.error('Error while fetching fleet agents.', e);
}
}
@@ -105,15 +133,6 @@ function TutorialConfigAgent({
});
const hasFleetAgents = !!data.fleetAgents.length;
- const fleetLink = hasFleetAgents
- ? {
- label: MANAGE_FLEET_POLICIES_LABEL,
- href: `${basePath}/app/fleet#/policies`,
- }
- : {
- label: GET_STARTED_WITH_FLEET_LABEL,
- href: `${basePath}/app/integrations#/detail/apm-0.3.0/overview`,
- };
return (
<>
@@ -125,7 +144,11 @@ function TutorialConfigAgent({
onChange={(newSelectedOption) =>
setSelectedOption(newSelectedOption)
}
- fleetLink={fleetLink}
+ fleetLink={getFleetLink({
+ isFleetEnabled: data.isFleetEnabled,
+ hasFleetAgents,
+ basePath,
+ })}
/>
diff --git a/x-pack/plugins/apm/public/tutorial/config_agent/policy_selector.tsx b/x-pack/plugins/apm/public/tutorial/config_agent/policy_selector.tsx
index 3a0c6d70db82b..25ce7042c4c97 100644
--- a/x-pack/plugins/apm/public/tutorial/config_agent/policy_selector.tsx
+++ b/x-pack/plugins/apm/public/tutorial/config_agent/policy_selector.tsx
@@ -21,7 +21,7 @@ interface Props {
options: PolicyOption[];
selectedOption?: PolicyOption;
onChange: (selectedOption?: PolicyOption) => void;
- fleetLink: {
+ fleetLink?: {
label: string;
href: string;
};
@@ -58,9 +58,11 @@ export function PolicySelector({
{ defaultMessage: 'Choose policy' }
)}
labelAppend={
-
- {fleetLink.label}
-
+ fleetLink && (
+
+ {fleetLink.label}
+
+ )
}
helpText={i18n.translate(
'xpack.apm.tutorial.agent_config.choosePolicy.helper',
diff --git a/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx b/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx
index 8a81b7a994e76..6fcf13345538f 100644
--- a/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx
+++ b/x-pack/plugins/apm/public/tutorial/tutorial_fleet_instructions/index.tsx
@@ -42,6 +42,7 @@ function TutorialFleetInstructions({ http, basePath, isDarkTheme }: Props) {
const response = await http.get('/api/apm/fleet/has_data');
setData(response as APIResponseType);
} catch (e) {
+ setIsLoading(false);
console.error('Error while fetching fleet details.', e);
}
setIsLoading(false);
diff --git a/x-pack/plugins/apm/server/index.test.ts b/x-pack/plugins/apm/server/index.test.ts
index 6052ec921f9f9..56c9825db5a5c 100644
--- a/x-pack/plugins/apm/server/index.test.ts
+++ b/x-pack/plugins/apm/server/index.test.ts
@@ -30,7 +30,7 @@ describe('mergeConfigs', () => {
expect(mergeConfigs(apmOssConfig, apmConfig)).toEqual({
'apm_oss.errorIndices': 'logs-apm*,apm-*-error-*',
- 'apm_oss.indexPattern': 'apm-*',
+ 'apm_oss.indexPattern': 'traces-apm*,logs-apm*,metrics-apm*,apm-*',
'apm_oss.metricsIndices': 'metrics-apm*,apm-*-metric-*',
'apm_oss.spanIndices': 'traces-apm*,apm-*-span-*',
'apm_oss.transactionIndices': 'traces-apm*,apm-*-transaction-*',
diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts
index f14894a76edb4..9031f454f4a7f 100644
--- a/x-pack/plugins/apm/server/index.ts
+++ b/x-pack/plugins/apm/server/index.ts
@@ -74,7 +74,7 @@ export function mergeConfigs(
'apm_oss.metricsIndices': apmOssConfig.metricsIndices,
'apm_oss.sourcemapIndices': apmOssConfig.sourcemapIndices,
'apm_oss.onboardingIndices': apmOssConfig.onboardingIndices,
- 'apm_oss.indexPattern': apmOssConfig.indexPattern, // TODO: add data stream indices: traces-apm*,logs-apm*,metrics-apm*. Blocked by https://github.com/elastic/kibana/issues/87851
+ 'apm_oss.indexPattern': apmOssConfig.indexPattern,
/* eslint-enable @typescript-eslint/naming-convention */
'xpack.apm.serviceMapEnabled': apmConfig.serviceMapEnabled,
'xpack.apm.serviceMapFingerprintBucketSize':
@@ -119,6 +119,10 @@ export function mergeConfigs(
'apm_oss.metricsIndices'
] = `metrics-apm*,${mergedConfig['apm_oss.metricsIndices']}`;
+ mergedConfig[
+ 'apm_oss.indexPattern'
+ ] = `traces-apm*,logs-apm*,metrics-apm*,${mergedConfig['apm_oss.indexPattern']}`;
+
return mergedConfig;
}
diff --git a/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts b/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts
index 82e85e7da9bb3..291b2fa2af99d 100644
--- a/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts
+++ b/x-pack/plugins/apm/server/lib/fleet/get_apm_package_policy_definition.ts
@@ -34,7 +34,7 @@ export function getApmPackagePolicyDefinition(
],
package: {
name: APM_PACKAGE_NAME,
- version: '0.3.0-dev.1',
+ version: '0.3.0',
title: 'Elastic APM',
},
};
diff --git a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
index 607a7e6227a9d..a2944d6241d2d 100644
--- a/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
+++ b/x-pack/plugins/apm/server/lib/index_pattern/create_static_index_pattern.ts
@@ -19,7 +19,8 @@ export async function createStaticIndexPattern(
setup: Setup,
config: APMRouteHandlerResources['config'],
savedObjectsClient: InternalSavedObjectsClient,
- spaceId: string | undefined
+ spaceId: string | undefined,
+ overwrite = false
): Promise {
return withApmSpan('create_static_index_pattern', async () => {
// don't autocreate APM index pattern if it's been disabled via the config
@@ -45,7 +46,7 @@ export async function createStaticIndexPattern(
},
{
id: APM_STATIC_INDEX_PATTERN_ID,
- overwrite: false,
+ overwrite,
namespace: spaceId,
}
)
diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts
index f260971c3bdcb..3a7eb738dd3b2 100644
--- a/x-pack/plugins/apm/server/plugin.ts
+++ b/x-pack/plugins/apm/server/plugin.ts
@@ -15,7 +15,7 @@ import {
Plugin,
PluginInitializerContext,
} from 'src/core/server';
-import { mapValues, once } from 'lodash';
+import { isEmpty, mapValues, once } from 'lodash';
import { TECHNICAL_COMPONENT_TEMPLATE_NAME } from '../../rule_registry/common/assets';
import { mappingFromFieldMap } from '../../rule_registry/common/mapping_from_field_map';
import { APMConfig, APMXPackConfig, APM_SERVER_FEATURE_ID } from '.';
@@ -104,21 +104,6 @@ export class APMPlugin
});
}
- plugins.home?.tutorials.registerTutorial(
- tutorialProvider({
- isEnabled: this.currentConfig['xpack.apm.ui.enabled'],
- indexPatternTitle: this.currentConfig['apm_oss.indexPattern'],
- cloud: plugins.cloud,
- indices: {
- errorIndices: this.currentConfig['apm_oss.errorIndices'],
- metricsIndices: this.currentConfig['apm_oss.metricsIndices'],
- onboardingIndices: this.currentConfig['apm_oss.onboardingIndices'],
- sourcemapIndices: this.currentConfig['apm_oss.sourcemapIndices'],
- transactionIndices: this.currentConfig['apm_oss.transactionIndices'],
- },
- })
- );
-
plugins.features.registerKibanaFeature(APM_FEATURE);
registerFeaturesUsage({ licensingPlugin: plugins.licensing });
@@ -206,6 +191,22 @@ export class APMPlugin
};
}) as APMRouteHandlerResources['plugins'];
+ plugins.home?.tutorials.registerTutorial(
+ tutorialProvider({
+ isEnabled: this.currentConfig['xpack.apm.ui.enabled'],
+ indexPatternTitle: this.currentConfig['apm_oss.indexPattern'],
+ cloud: plugins.cloud,
+ isFleetPluginEnabled: !isEmpty(resourcePlugins.fleet),
+ indices: {
+ errorIndices: this.currentConfig['apm_oss.errorIndices'],
+ metricsIndices: this.currentConfig['apm_oss.metricsIndices'],
+ onboardingIndices: this.currentConfig['apm_oss.onboardingIndices'],
+ sourcemapIndices: this.currentConfig['apm_oss.sourcemapIndices'],
+ transactionIndices: this.currentConfig['apm_oss.transactionIndices'],
+ },
+ })
+ );
+
const telemetryUsageCounter = resourcePlugins.usageCollection?.setup.createUsageCounter(
APM_SERVER_FEATURE_ID
);
diff --git a/x-pack/plugins/apm/server/routes/fleet.ts b/x-pack/plugins/apm/server/routes/fleet.ts
index b83bfd54b93cd..b760014d6af89 100644
--- a/x-pack/plugins/apm/server/routes/fleet.ts
+++ b/x-pack/plugins/apm/server/routes/fleet.ts
@@ -25,6 +25,8 @@ import { createCloudApmPackgePolicy } from '../lib/fleet/create_cloud_apm_packag
import { getUnsupportedApmServerSchema } from '../lib/fleet/get_unsupported_apm_server_schema';
import { isSuperuser } from '../lib/fleet/is_superuser';
import { getInternalSavedObjectsClient } from '../lib/helpers/get_internal_saved_objects_client';
+import { setupRequest } from '../lib/helpers/setup_request';
+import { createStaticIndexPattern } from '../lib/index_pattern/create_static_index_pattern';
const hasFleetDataRoute = createApmServerRoute({
endpoint: 'GET /api/apm/fleet/has_data',
@@ -32,7 +34,7 @@ const hasFleetDataRoute = createApmServerRoute({
handler: async ({ core, plugins }) => {
const fleetPluginStart = await plugins.fleet?.start();
if (!fleetPluginStart) {
- throw Boom.internal(FLEET_REQUIRED_MESSAGE);
+ return { hasData: false };
}
const packagePolicies = await getApmPackgePolicies({
core,
@@ -56,7 +58,7 @@ const fleetAgentsRoute = createApmServerRoute({
const fleetPluginStart = await plugins.fleet?.start();
if (!fleetPluginStart) {
- throw Boom.internal(FLEET_REQUIRED_MESSAGE);
+ return { cloudStandaloneSetup, fleetAgents: [], isFleetEnabled: false };
}
// fetches package policies that contains APM integrations
const packagePolicies = await getApmPackgePolicies({
@@ -75,6 +77,7 @@ const fleetAgentsRoute = createApmServerRoute({
return {
cloudStandaloneSetup,
+ isFleetEnabled: true,
fleetAgents: fleetAgents.map((agent) => {
const packagePolicy = policiesGroupedById[agent.id];
const packagePolicyVars = packagePolicy.inputs[0]?.vars;
@@ -153,7 +156,7 @@ const createCloudApmPackagePolicyRoute = createApmServerRoute({
endpoint: 'POST /api/apm/fleet/cloud_apm_package_policy',
options: { tags: ['access:apm', 'access:apm_write'] },
handler: async (resources) => {
- const { plugins, context, config, request, logger } = resources;
+ const { plugins, context, config, request, logger, core } = resources;
const cloudApmMigrationEnabled =
config['xpack.apm.agent.migrations.enabled'];
if (!plugins.fleet || !plugins.security) {
@@ -170,15 +173,34 @@ const createCloudApmPackagePolicyRoute = createApmServerRoute({
if (!hasRequiredRole || !cloudApmMigrationEnabled) {
throw Boom.forbidden(CLOUD_SUPERUSER_REQUIRED_MESSAGE);
}
- return {
- cloud_apm_package_policy: await createCloudApmPackgePolicy({
- cloudPluginSetup,
- fleetPluginStart,
- savedObjectsClient,
- esClient,
- logger,
- }),
- };
+
+ const cloudApmAackagePolicy = await createCloudApmPackgePolicy({
+ cloudPluginSetup,
+ fleetPluginStart,
+ savedObjectsClient,
+ esClient,
+ logger,
+ });
+
+ const [setup, internalSavedObjectsClient] = await Promise.all([
+ setupRequest(resources),
+ core
+ .start()
+ .then(({ savedObjects }) => savedObjects.createInternalRepository()),
+ ]);
+
+ const spaceId = plugins.spaces?.setup.spacesService.getSpaceId(request);
+
+ // force update the index pattern title with data streams
+ await createStaticIndexPattern(
+ setup,
+ config,
+ internalSavedObjectsClient,
+ spaceId,
+ true
+ );
+
+ return { cloud_apm_package_policy: cloudApmAackagePolicy };
},
});
@@ -190,11 +212,6 @@ export const apmFleetRouteRepository = createApmServerRouteRepository()
.add(getMigrationCheckRoute)
.add(createCloudApmPackagePolicyRoute);
-const FLEET_REQUIRED_MESSAGE = i18n.translate(
- 'xpack.apm.fleet_has_data.fleetRequired',
- { defaultMessage: `Fleet plugin is required` }
-);
-
const FLEET_SECURITY_REQUIRED_MESSAGE = i18n.translate(
'xpack.apm.api.fleet.fleetSecurityRequired',
{ defaultMessage: `Fleet and Security plugins are required` }
diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts b/x-pack/plugins/apm/server/routes/register_routes/index.test.ts
index 158d7ee7e76a3..b9dece866fae5 100644
--- a/x-pack/plugins/apm/server/routes/register_routes/index.test.ts
+++ b/x-pack/plugins/apm/server/routes/register_routes/index.test.ts
@@ -109,6 +109,11 @@ const initApi = (
params: {},
query: {},
body: null,
+ events: {
+ aborted$: {
+ toPromise: () => new Promise(() => {}),
+ },
+ },
...request,
},
responseMock
@@ -202,7 +207,7 @@ describe('createApi', () => {
describe('when validating', () => {
describe('_inspect', () => {
it('allows _inspect=true', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
mocks: { response },
@@ -234,7 +239,7 @@ describe('createApi', () => {
});
it('rejects _inspect=1', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
@@ -267,7 +272,7 @@ describe('createApi', () => {
});
it('allows omitting _inspect', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
@@ -297,7 +302,11 @@ describe('createApi', () => {
simulateRequest,
mocks: { response },
} = initApi([
- { endpoint: 'GET /foo', options: { tags: [] }, handler: jest.fn() },
+ {
+ endpoint: 'GET /foo',
+ options: { tags: [] },
+ handler: jest.fn().mockResolvedValue({}),
+ },
]);
await simulateRequest({
@@ -328,7 +337,7 @@ describe('createApi', () => {
});
it('validates path parameters', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
mocks: { response },
@@ -402,7 +411,7 @@ describe('createApi', () => {
});
it('validates body parameters', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
mocks: { response },
@@ -448,7 +457,7 @@ describe('createApi', () => {
});
it('validates query parameters', async () => {
- const handlerMock = jest.fn();
+ const handlerMock = jest.fn().mockResolvedValue({});
const {
simulateRequest,
mocks: { response },
diff --git a/x-pack/plugins/apm/server/routes/register_routes/index.ts b/x-pack/plugins/apm/server/routes/register_routes/index.ts
index 136f3c73d8046..8e6070de722be 100644
--- a/x-pack/plugins/apm/server/routes/register_routes/index.ts
+++ b/x-pack/plugins/apm/server/routes/register_routes/index.ts
@@ -29,6 +29,13 @@ const inspectRt = t.exact(
})
);
+const CLIENT_CLOSED_REQUEST = {
+ statusCode: 499,
+ body: {
+ message: 'Client closed request',
+ },
+};
+
export const inspectableEsQueriesMap = new WeakMap<
KibanaRequest,
InspectResponse
@@ -89,23 +96,40 @@ export function registerRoutes({
runtimeType
);
- const data: Record | undefined | null = (await handler({
- request,
- context,
- config,
- logger,
- core,
- plugins,
- params: merge(
- {
- query: {
- _inspect: false,
+ const { aborted, data } = await Promise.race([
+ handler({
+ request,
+ context,
+ config,
+ logger,
+ core,
+ plugins,
+ params: merge(
+ {
+ query: {
+ _inspect: false,
+ },
},
- },
- validatedParams
- ),
- ruleDataClient,
- })) as any;
+ validatedParams
+ ),
+ ruleDataClient,
+ }).then((value) => {
+ return {
+ aborted: false,
+ data: value as Record | undefined | null,
+ };
+ }),
+ request.events.aborted$.toPromise().then(() => {
+ return {
+ aborted: true,
+ data: undefined,
+ };
+ }),
+ ]);
+
+ if (aborted) {
+ return response.custom(CLIENT_CLOSED_REQUEST);
+ }
if (Array.isArray(data)) {
throw new Error('Return type cannot be an array');
@@ -118,9 +142,6 @@ export function registerRoutes({
}
: { ...data };
- // cleanup
- inspectableEsQueriesMap.delete(request);
-
if (!options.disableTelemetry && telemetryUsageCounter) {
telemetryUsageCounter.incrementCounter({
counterName: `${method.toUpperCase()} ${pathname}`,
@@ -131,6 +152,7 @@ export function registerRoutes({
return response.ok({ body });
} catch (error) {
logger.error(error);
+
if (!options.disableTelemetry && telemetryUsageCounter) {
telemetryUsageCounter.incrementCounter({
counterName: `${method.toUpperCase()} ${pathname}`,
@@ -147,16 +169,18 @@ export function registerRoutes({
},
};
- if (Boom.isBoom(error)) {
- opts.statusCode = error.output.statusCode;
+ if (error instanceof RequestAbortedError) {
+ return response.custom(merge(opts, CLIENT_CLOSED_REQUEST));
}
- if (error instanceof RequestAbortedError) {
- opts.statusCode = 499;
- opts.body.message = 'Client closed request';
+ if (Boom.isBoom(error)) {
+ opts.statusCode = error.output.statusCode;
}
return response.custom(opts);
+ } finally {
+ // cleanup
+ inspectableEsQueriesMap.delete(request);
}
}
);
diff --git a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts b/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts
index 882d45c4c21db..400da79e3d2d0 100644
--- a/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts
+++ b/x-pack/plugins/apm/server/tutorial/envs/on_prem.ts
@@ -38,12 +38,14 @@ export function onPremInstructions({
metricsIndices,
sourcemapIndices,
onboardingIndices,
+ isFleetPluginEnabled,
}: {
errorIndices: string;
transactionIndices: string;
metricsIndices: string;
sourcemapIndices: string;
onboardingIndices: string;
+ isFleetPluginEnabled: boolean;
}): InstructionsSchema {
const EDIT_CONFIG = createEditConfig();
const START_SERVER_UNIX = createStartServerUnix();
@@ -69,12 +71,17 @@ export function onPremInstructions({
iconType: 'alert',
},
instructionVariants: [
- {
- id: INSTRUCTION_VARIANT.FLEET,
- instructions: [
- { customComponentName: 'TutorialFleetInstructions' },
- ],
- },
+ // hides fleet section when plugin is disabled
+ ...(isFleetPluginEnabled
+ ? [
+ {
+ id: INSTRUCTION_VARIANT.FLEET,
+ instructions: [
+ { customComponentName: 'TutorialFleetInstructions' },
+ ],
+ },
+ ]
+ : []),
{
id: INSTRUCTION_VARIANT.OSX,
instructions: [
diff --git a/x-pack/plugins/apm/server/tutorial/index.ts b/x-pack/plugins/apm/server/tutorial/index.ts
index 9118c30b845d0..edf056a6d1be4 100644
--- a/x-pack/plugins/apm/server/tutorial/index.ts
+++ b/x-pack/plugins/apm/server/tutorial/index.ts
@@ -28,6 +28,7 @@ export const tutorialProvider = ({
indexPatternTitle,
indices,
cloud,
+ isFleetPluginEnabled,
}: {
isEnabled: boolean;
indexPatternTitle: string;
@@ -39,6 +40,7 @@ export const tutorialProvider = ({
sourcemapIndices: string;
onboardingIndices: string;
};
+ isFleetPluginEnabled: boolean;
}) => () => {
const savedObjects = [
{
@@ -104,7 +106,7 @@ It allows you to monitor the performance of thousands of applications in real ti
euiIconType: 'apmApp',
artifacts,
customStatusCheckName: 'apm_fleet_server_status_check',
- onPrem: onPremInstructions(indices),
+ onPrem: onPremInstructions({ ...indices, isFleetPluginEnabled }),
elasticCloud: createElasticCloudInstructions(cloud),
previewImagePath: '/plugins/apm/assets/apm.png',
savedObjects,
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.test.tsx
index 3b8e1c96ff504..63952bc2a6de7 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.test.tsx
@@ -10,7 +10,7 @@ import '../../../__mocks__/shallow_useeffect.mock';
import React from 'react';
-import { shallow } from 'enzyme';
+import { shallow, ShallowWrapper } from 'enzyme';
import { rerender } from '../../../test_helpers';
@@ -162,10 +162,18 @@ describe('MultiInputRows', () => {
});
describe('onChange', () => {
+ let wrapper: ShallowWrapper;
const onChange = jest.fn();
+ beforeEach(() => {
+ wrapper = shallow();
+ });
+
+ it('does not call on change on mount', () => {
+ expect(onChange).not.toHaveBeenCalled();
+ });
+
it('returns the current values dynamically on change', () => {
- const wrapper = shallow();
setMockValues({ ...values, values: ['updated'] });
rerender(wrapper);
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.tsx
index ac61e69eb44c4..257f4b637f3e0 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/multi_input_rows/multi_input_rows.tsx
@@ -5,9 +5,10 @@
* 2.0.
*/
-import React, { useEffect } from 'react';
+import React from 'react';
import { useValues, useActions } from 'kea';
+import useUpdateEffect from 'react-use/lib/useUpdateEffect';
import { EuiForm, EuiButton, EuiButtonEmpty, EuiSpacer } from '@elastic/eui';
@@ -49,7 +50,7 @@ export const MultiInputRows: React.FC = ({
const { values, addedNewRow, hasEmptyValues, hasOnlyOneValue } = useValues(logic);
const { addValue, editValue, deleteValue } = useActions(logic);
- useEffect(() => {
+ useUpdateEffect(() => {
if (onChange) {
onChange(filterEmptyValues(values));
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts
index 4233a7b300d15..e2493b6404f7d 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.test.ts
@@ -229,7 +229,7 @@ describe('RelevanceTuningLogic', () => {
});
describe('updatePrecision', () => {
- it('should set precision inside search settings', () => {
+ it('should set precision inside search settings and set unsavedChanges to true', () => {
mount();
RelevanceTuningLogic.actions.updatePrecision(9);
@@ -239,6 +239,7 @@ describe('RelevanceTuningLogic', () => {
...DEFAULT_VALUES.searchSettings,
precision: 9,
},
+ unsavedChanges: true,
});
});
});
diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.ts b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.ts
index 743bb1aa1502b..02903b4588ed4 100644
--- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.ts
+++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/relevance_tuning/relevance_tuning_logic.ts
@@ -191,6 +191,7 @@ export const RelevanceTuningLogic = kea<
unsavedChanges: [
false,
{
+ updatePrecision: () => true,
setSearchSettings: () => true,
setSearchSettingsResponse: () => false,
},
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx
index a7eb2424e797a..0dd2b0988b3f4 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/components/product_selector/product_selector.tsx
@@ -19,6 +19,7 @@ import {
EuiFlexItem,
EuiSpacer,
EuiTitle,
+ EuiText,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
@@ -59,14 +60,15 @@ export const ProductSelector: React.FC = ({ access }) => {
-
+
{i18n.translate('xpack.enterpriseSearch.overview.heading', {
defaultMessage: 'Welcome to Elastic Enterprise Search',
})}
-
-
+
+
+
{config.host
? i18n.translate('xpack.enterpriseSearch.overview.subheading', {
defaultMessage: 'Select a product to get started.',
@@ -75,7 +77,7 @@ export const ProductSelector: React.FC = ({ access }) => {
defaultMessage: 'Choose a product to set up and get started.',
})}
-
+
diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss
index 45bf37def1121..4be8d7322b4c8 100644
--- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss
+++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search/index.scss
@@ -21,21 +21,7 @@
&__header {
text-align: center;
margin: auto;
- }
-
- &__heading {
- @include euiBreakpoint('xs', 's') {
- font-size: $euiFontSizeXL;
- line-height: map-get(map-get($euiTitles, 'm'), 'line-height');
- }
- }
-
- &__subheading {
- color: $euiColorMediumShade;
- font-size: $euiFontSize;
-
@include euiBreakpoint('m', 'l', 'xl') {
- font-size: $euiFontSizeL;
margin-bottom: $euiSizeL;
}
}
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/status_item/status_item.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/status_item/status_item.tsx
index 79455ccc1d90d..35ac8f1b85c05 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/status_item/status_item.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/components/shared/status_item/status_item.tsx
@@ -44,7 +44,7 @@ export const StatusItem: React.FC = ({ details }) => {
const infoPopover = (
{
onGroupNameInputChange,
} = useActions(GroupLogic);
const {
- group: { name, contentSources, users, canDeleteGroup },
+ group: { name, contentSources, canDeleteGroup },
groupNameInputValue,
dataLoading,
confirmDeleteModalVisible,
@@ -158,7 +157,6 @@ export const GroupOverview: React.FC = () => {
);
const hasContentSources = contentSources?.length > 0;
- const hasUsers = users?.length > 0;
const manageSourcesButton = (
@@ -199,12 +197,11 @@ export const GroupOverview: React.FC = () => {
const usersSection = (
- {hasUsers && }
+ {manageUsersButton}
);
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx
index f98b873aed5bb..770bf8a51efd3 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.test.tsx
@@ -14,8 +14,7 @@ import moment from 'moment';
import { EuiTableRow } from '@elastic/eui';
-import { GroupRow, NO_USERS_MESSAGE, NO_SOURCES_MESSAGE } from './group_row';
-import { GroupUsers } from './group_users';
+import { GroupRow, NO_SOURCES_MESSAGE } from './group_row';
describe('GroupRow', () => {
it('renders', () => {
@@ -24,12 +23,6 @@ describe('GroupRow', () => {
expect(wrapper.find(EuiTableRow)).toHaveLength(1);
});
- it('renders group users', () => {
- const wrapper = shallow();
-
- expect(wrapper.find(GroupUsers)).toHaveLength(1);
- });
-
it('renders fromNow date string when in range', () => {
const wrapper = shallow(
@@ -44,12 +37,6 @@ describe('GroupRow', () => {
expect(wrapper.find('small').text()).toEqual('Last updated January 1, 2020.');
});
- it('renders empty users message when no users present', () => {
- const wrapper = shallow();
-
- expect(wrapper.find('.user-group__accounts').text()).toEqual(NO_USERS_MESSAGE);
- });
-
it('renders empty sources message when no sources present', () => {
const wrapper = shallow();
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx
index 94d44fde57aed..d079eb34fbf89 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/group_row.tsx
@@ -19,7 +19,6 @@ import { Group } from '../../../types';
import { MAX_NAME_LENGTH } from '../group_logic';
import { GroupSources } from './group_sources';
-import { GroupUsers } from './group_users';
const DAYS_CUTOFF = 8;
export const NO_SOURCES_MESSAGE = i18n.translate(
@@ -40,14 +39,7 @@ const dateDisplay = (date: string) =>
? moment(date).fromNow()
: moment(date).format('MMMM D, YYYY');
-export const GroupRow: React.FC = ({
- id,
- name,
- updatedAt,
- contentSources,
- users,
- usersCount,
-}) => {
+export const GroupRow: React.FC = ({ id, name, updatedAt, contentSources }) => {
const GROUP_UPDATED_TEXT = i18n.translate(
'xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText',
{
@@ -76,15 +68,6 @@ export const GroupRow: React.FC = ({
)}
-
-
- {usersCount > 0 ? (
-
- ) : (
- NO_USERS_MESSAGE
- )}
-
-
diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx
index cfb3ed8044235..45175e489f94a 100644
--- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx
+++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/groups/components/groups_table.tsx
@@ -36,12 +36,6 @@ const SOURCES_TABLE_HEADER = i18n.translate(
defaultMessage: 'Content sources',
}
);
-const USERS_TABLE_HEADER = i18n.translate(
- 'xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader',
- {
- defaultMessage: 'Users',
- }
-);
export const GroupsTable: React.FC<{}> = () => {
const { setActivePage } = useActions(GroupsLogic);
@@ -77,7 +71,6 @@ export const GroupsTable: React.FC<{}> = () => {
{GROUP_TABLE_HEADER}
{SOURCES_TABLE_HEADER}
- {USERS_TABLE_HEADER}
diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts
index d0e74f3234c14..f9756119b336c 100644
--- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts
+++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.test.ts
@@ -403,7 +403,7 @@ describe('EnterpriseSearchRequestHandler', () => {
expect(responseMock.customError).toHaveBeenCalledWith({
statusCode: 502,
body: 'Cannot authenticate Enterprise Search user',
- headers: mockExpectedResponseHeaders,
+ headers: { ...mockExpectedResponseHeaders, [ERROR_CONNECTING_HEADER]: 'true' },
});
expect(mockLogger.error).toHaveBeenCalled();
});
diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts
index 8031fc724f7b3..57b91c2b30c73 100644
--- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts
+++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_request_handler.ts
@@ -283,12 +283,11 @@ export class EnterpriseSearchRequestHandler {
handleConnectionError(response: KibanaResponseFactory, e: Error) {
const errorMessage = `Error connecting to Enterprise Search: ${e?.message || e.toString()}`;
+ const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' };
this.log.error(errorMessage);
if (e instanceof Error) this.log.debug(e.stack as string);
- const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' };
-
return response.customError({ statusCode: 502, headers, body: errorMessage });
}
@@ -298,9 +297,10 @@ export class EnterpriseSearchRequestHandler {
*/
handleAuthenticationError(response: KibanaResponseFactory) {
const errorMessage = 'Cannot authenticate Enterprise Search user';
+ const headers = { ...this.headers, [ERROR_CONNECTING_HEADER]: 'true' };
this.log.error(errorMessage);
- return response.customError({ statusCode: 502, headers: this.headers, body: errorMessage });
+ return response.customError({ statusCode: 502, headers, body: errorMessage });
}
/**
diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/fleet_server_on_prem_instructions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/fleet_server_on_prem_instructions.tsx
index 48ff51f1a25e8..0fc3821d2e3f7 100644
--- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/fleet_server_on_prem_instructions.tsx
+++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_requirements_page/components/fleet_server_on_prem_instructions.tsx
@@ -452,6 +452,8 @@ export const AddFleetServerHostStepContent = ({
await addFleetServerHost(fleetServerHost);
setCalloutHost(fleetServerHost);
setFleetServerHost('');
+ } else {
+ setCalloutHost('');
}
} finally {
setIsLoading(false);
diff --git a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
index ed603357206ad..39d4dd1a71dd9 100644
--- a/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
+++ b/x-pack/plugins/ml/public/application/components/annotations/annotations_table/annotations_table.js
@@ -18,13 +18,13 @@ import React, { Component, Fragment, useContext } from 'react';
import memoizeOne from 'memoize-one';
import {
EuiBadge,
- EuiButtonEmpty,
EuiCallOut,
EuiFlexGroup,
EuiFlexItem,
EuiInMemoryTable,
EuiLink,
EuiLoadingSpinner,
+ EuiToolTip,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
@@ -52,6 +52,19 @@ import { timeFormatter } from '../../../../../common/util/date_utils';
import { MlAnnotationUpdatesContext } from '../../../contexts/ml/ml_annotation_updates_context';
import { DatafeedChartFlyout } from '../../../jobs/jobs_list/components/datafeed_chart_flyout';
+const editAnnotationsText = (
+
+);
+const viewDataFeedText = (
+
+);
+
const CURRENT_SERIES = 'current_series';
/**
* Table component for rendering the lists of annotations for an ML job.
@@ -463,82 +476,67 @@ class AnnotationsTableUI extends Component {
const actions = [];
actions.push({
- render: (annotation) => {
- // find the original annotation because the table might not show everything
+ name: editAnnotationsText,
+ description: editAnnotationsText,
+ icon: 'pencil',
+ type: 'icon',
+ onClick: (annotation) => {
const annotationId = annotation._id;
const originalAnnotation = annotations.find((d) => d._id === annotationId);
- const editAnnotationsText = (
-
- );
- const editAnnotationsAriaLabelText = i18n.translate(
- 'xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel',
- { defaultMessage: 'Edit annotation' }
- );
- return (
- annotationUpdatesService.setValue(originalAnnotation ?? annotation)}
- >
- {editAnnotationsText}
-
- );
+
+ annotationUpdatesService.setValue(originalAnnotation ?? annotation);
},
});
if (this.state.jobId && this.props.jobs[0].analysis_config.bucket_span) {
// add datafeed modal action
actions.push({
- render: (annotation) => {
- const viewDataFeedText = (
-
- );
- const viewDataFeedTooltipAriaLabelText = i18n.translate(
- 'xpack.ml.annotationsTable.datafeedChartTooltipAriaLabel',
- { defaultMessage: 'Datafeed chart' }
- );
- return (
-
- this.setState({
- datafeedFlyoutVisible: true,
- datafeedEnd: annotation.end_timestamp,
- })
- }
- >
- {viewDataFeedText}
-
- );
+ name: viewDataFeedText,
+ description: viewDataFeedText,
+ icon: 'visAreaStacked',
+ type: 'icon',
+ onClick: (annotation) => {
+ this.setState({
+ datafeedFlyoutVisible: true,
+ datafeedEnd: annotation.end_timestamp,
+ });
},
});
}
if (isSingleMetricViewerLinkVisible) {
actions.push({
- render: (annotation) => {
+ name: (annotation) => {
const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id));
- const openInSingleMetricViewerTooltipText = isDrillDownAvailable ? (
-
- ) : (
-
+
+ if (isDrillDownAvailable) {
+ return (
+
+ );
+ }
+ return (
+
+ }
+ >
+
+
);
- const openInSingleMetricViewerAriaLabelText = isDrillDownAvailable
+ },
+ description: (annotation) => {
+ const isDrillDownAvailable = isTimeSeriesViewJob(this.getJob(annotation.job_id));
+
+ return isDrillDownAvailable
? i18n.translate('xpack.ml.annotationsTable.openInSingleMetricViewerAriaLabel', {
defaultMessage: 'Open in Single Metric Viewer',
})
@@ -546,19 +544,11 @@ class AnnotationsTableUI extends Component {
'xpack.ml.annotationsTable.jobConfigurationNotSupportedInSingleMetricViewerAriaLabel',
{ defaultMessage: 'Job configuration not supported in Single Metric Viewer' }
);
-
- return (
- this.openSingleMetricView(annotation)}
- >
- {openInSingleMetricViewerTooltipText}
-
- );
},
+ enabled: (annotation) => isTimeSeriesViewJob(this.getJob(annotation.job_id)),
+ icon: 'visLine',
+ type: 'icon',
+ onClick: (annotation) => this.openSingleMetricView(annotation),
});
}
diff --git a/x-pack/plugins/ml/public/application/explorer/explorer.js b/x-pack/plugins/ml/public/application/explorer/explorer.js
index a11a42b9b65b2..31058b62af7fe 100644
--- a/x-pack/plugins/ml/public/application/explorer/explorer.js
+++ b/x-pack/plugins/ml/public/application/explorer/explorer.js
@@ -261,6 +261,30 @@ export class ExplorerUI extends React.Component {
} = this.props.explorerState;
const { annotationsData, aggregations, error: annotationsError } = annotations;
+ const annotationsCnt = Array.isArray(annotationsData) ? annotationsData.length : 0;
+ const allAnnotationsCnt = Array.isArray(aggregations?.event?.buckets)
+ ? aggregations.event.buckets.reduce((acc, v) => acc + v.doc_count, 0)
+ : annotationsCnt;
+
+ const badge =
+ allAnnotationsCnt > annotationsCnt ? (
+
+
+
+ ) : (
+
+
+
+ );
+
const jobSelectorProps = {
dateFormatTz: getDateFormatTz(),
};
@@ -404,7 +428,7 @@ export class ExplorerUI extends React.Component {
{loading === false && tableData.anomalies?.length ? (
) : null}
- {annotationsData.length > 0 && (
+ {annotationsCnt > 0 && (
<>
-
-
- ),
+ badge,
}}
/>
diff --git a/x-pack/plugins/observability/.storybook/jest_setup.js b/x-pack/plugins/observability/.storybook/jest_setup.js
new file mode 100644
index 0000000000000..32071b8aa3f62
--- /dev/null
+++ b/x-pack/plugins/observability/.storybook/jest_setup.js
@@ -0,0 +1,11 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { setGlobalConfig } from '@storybook/testing-react';
+import * as globalStorybookConfig from './preview';
+
+setGlobalConfig(globalStorybookConfig);
diff --git a/x-pack/plugins/observability/.storybook/preview.js b/x-pack/plugins/observability/.storybook/preview.js
new file mode 100644
index 0000000000000..18343c15a6465
--- /dev/null
+++ b/x-pack/plugins/observability/.storybook/preview.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiThemeProviderDecorator } from '../../../../src/plugins/kibana_react/common';
+
+export const decorators = [EuiThemeProviderDecorator];
diff --git a/x-pack/plugins/observability/jest.config.js b/x-pack/plugins/observability/jest.config.js
index 66d42122382f3..6fdeab06df053 100644
--- a/x-pack/plugins/observability/jest.config.js
+++ b/x-pack/plugins/observability/jest.config.js
@@ -9,4 +9,5 @@ module.exports = {
preset: '@kbn/test',
rootDir: '../../..',
roots: ['/x-pack/plugins/observability'],
+ setupFiles: ['/x-pack/plugins/observability/.storybook/jest_setup.js'],
};
diff --git a/x-pack/plugins/observability/public/components/shared/core_web_vitals/__stories__/core_vitals.stories.tsx b/x-pack/plugins/observability/public/components/shared/core_web_vitals/__stories__/core_vitals.stories.tsx
index 5f5cf2cb4da21..5c07b4626cf19 100644
--- a/x-pack/plugins/observability/public/components/shared/core_web_vitals/__stories__/core_vitals.stories.tsx
+++ b/x-pack/plugins/observability/public/components/shared/core_web_vitals/__stories__/core_vitals.stories.tsx
@@ -9,7 +9,6 @@ import React, { ComponentType } from 'react';
import { __IntlProvider as IntlProvider } from '@kbn/i18n/react';
import { Observable } from 'rxjs';
import { CoreStart } from 'src/core/public';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { createKibanaReactContext } from '../../../../../../../../src/plugins/kibana_react/public';
import { CoreVitalItem } from '../core_vital_item';
import { LCP_HELP_LABEL, LCP_LABEL } from '../translations';
@@ -25,9 +24,7 @@ export default {
(Story: ComponentType) => (
-
-
-
+
),
diff --git a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx
index 80a25b82eb8cb..1152ba32960ed 100644
--- a/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx
+++ b/x-pack/plugins/observability/public/components/shared/field_value_suggestions/__stories__/field_value_selection.stories.tsx
@@ -10,7 +10,6 @@ import { __IntlProvider as IntlProvider } from '@kbn/i18n/react';
import { Observable } from 'rxjs';
import { CoreStart } from 'src/core/public';
import { text } from '@storybook/addon-knobs';
-import { EuiThemeProvider } from '../../../../../../../../src/plugins/kibana_react/common';
import { createKibanaReactContext } from '../../../../../../../../src/plugins/kibana_react/public';
import { FieldValueSelectionProps } from '../types';
import { FieldValueSelection } from '../field_value_selection';
@@ -31,16 +30,14 @@ export default {
(Story: ComponentType) => (
-
- {}}
- selectedValue={[]}
- loading={false}
- setQuery={() => {}}
- />
-
+ {}}
+ selectedValue={[]}
+ loading={false}
+ setQuery={() => {}}
+ />
),
diff --git a/x-pack/plugins/observability/public/pages/landing/landing.stories.tsx b/x-pack/plugins/observability/public/pages/landing/landing.stories.tsx
index 86922b045c742..ef3ded61492c7 100644
--- a/x-pack/plugins/observability/public/pages/landing/landing.stories.tsx
+++ b/x-pack/plugins/observability/public/pages/landing/landing.stories.tsx
@@ -6,7 +6,6 @@
*/
import React, { ComponentType } from 'react';
-import { EuiThemeProvider } from '../../../../../../src/plugins/kibana_react/common';
import { PluginContext, PluginContextValue } from '../../context/plugin_context';
import { LandingPage } from './';
@@ -27,9 +26,7 @@ export default {
} as unknown) as PluginContextValue;
return (
-
-
-
+
);
},
diff --git a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx
index dd424cf221d15..2982333235331 100644
--- a/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx
+++ b/x-pack/plugins/observability/public/pages/overview/overview.stories.tsx
@@ -10,7 +10,6 @@ import { storiesOf } from '@storybook/react';
import { AppMountParameters, CoreStart } from 'kibana/public';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
-import { EuiThemeProvider } from '../../../../../../src/plugins/kibana_react/common';
import { UI_SETTINGS } from '../../../../../../src/plugins/data/public';
import { HasDataContextProvider } from '../../context/has_data_context';
import { PluginContext } from '../../context/plugin_context';
@@ -65,9 +64,7 @@ const withCore = makeDecorator({
ObservabilityPageTemplate: KibanaPageTemplate,
}}
>
-
- {storyFn(context)}
-
+ {storyFn(context)}
);
diff --git a/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap b/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap
index 9ce249aa32a1d..8007acad93e4b 100644
--- a/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap
+++ b/x-pack/plugins/reporting/public/management/__snapshots__/report_listing.test.tsx.snap
@@ -424,7 +424,7 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -480,7 +480,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -522,7 +521,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -1489,7 +1487,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -1531,7 +1528,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -2512,7 +2508,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -2554,7 +2549,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -3582,7 +3576,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -3624,7 +3617,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -4685,7 +4677,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -4727,7 +4718,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -5755,7 +5745,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -5797,7 +5786,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -6825,7 +6813,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -6867,7 +6854,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -7895,7 +7881,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -7937,7 +7922,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -8965,7 +8949,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
@@ -9007,7 +8990,6 @@ exports[`ReportListing Report job listing with some items 1`] = `
className="euiTableCellContent euiTableCellContent--overflowingContent"
>
{
return (
<>
@@ -375,7 +376,7 @@ class ReportListingUi extends Component {
}),
render: (objectTitle: string, record: Job) => {
return (
-
+
{objectTitle}
{record.object_type}
diff --git a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap
index 01a8be98bc4be..83dc0c9e215b0 100644
--- a/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap
+++ b/x-pack/plugins/reporting/public/share_context_menu/__snapshots__/screen_capture_panel_content.test.tsx.snap
@@ -312,9 +312,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "canvas" layout
onResize={[Function]}
>
-
+
@@ -752,9 +750,7 @@ exports[`ScreenCapturePanelContent properly renders a view with "print" layout o
onResize={[Function]}
>
-
+
@@ -1064,9 +1060,7 @@ exports[`ScreenCapturePanelContent renders the default view properly 1`] = `
onResize={[Function]}
>
-
+
diff --git a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
index 1141437eae0ef..eb2abf4036c03 100644
--- a/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
+++ b/x-pack/plugins/reporting/server/browsers/chromium/driver_factory/index.ts
@@ -26,6 +26,18 @@ import { HeadlessChromiumDriver } from '../driver';
import { args } from './args';
import { Metrics, getMetrics } from './metrics';
+// Puppeteer type definitions do not match the documentation.
+// See https://pptr.dev/#?product=Puppeteer&version=v8.0.0&show=api-puppeteerlaunchoptions
+interface ReportingLaunchOptions extends puppeteer.LaunchOptions {
+ userDataDir?: string;
+ ignoreHTTPSErrors?: boolean;
+ args?: string[];
+}
+
+declare module 'puppeteer' {
+ function launch(options: ReportingLaunchOptions): Promise;
+}
+
type BrowserConfig = CaptureConfig['browser']['chromium'];
type ViewportConfig = CaptureConfig['viewport'];
@@ -85,11 +97,12 @@ export class HeadlessChromiumDriverFactory {
userDataDir: this.userDataDir,
executablePath: this.binaryPath,
ignoreHTTPSErrors: true,
+ handleSIGHUP: false,
args: chromiumArgs,
env: {
TZ: browserTimezone,
},
- } as puppeteer.LaunchOptions);
+ });
page = await browser.newPage();
devTools = await page.target().createCDPSession();
diff --git a/x-pack/plugins/rule_registry/docs/README.md b/x-pack/plugins/rule_registry/docs/README.md
index a22dc1ab7e864..0eb2463005193 100644
--- a/x-pack/plugins/rule_registry/docs/README.md
+++ b/x-pack/plugins/rule_registry/docs/README.md
@@ -19,7 +19,7 @@ yarn global add typedoc typedoc-plugin-markdown
```bash
cd x-pack/plugins/rule_registry/docs
-npx typedoc --options alerts_client_typedoc.json
+npx typedoc --gitRemote upstream --options alerts_client_typedoc.json
```
After running the above commands the files in the `server` directory will be updated to match the new tsdocs.
diff --git a/x-pack/plugins/rule_registry/docs/alerts_client/classes/alertsclient.md b/x-pack/plugins/rule_registry/docs/alerts_client/classes/alertsclient.md
index 9b639829a9f5f..359834bf9c2e7 100644
--- a/x-pack/plugins/rule_registry/docs/alerts_client/classes/alertsclient.md
+++ b/x-pack/plugins/rule_registry/docs/alerts_client/classes/alertsclient.md
@@ -41,7 +41,7 @@ on alerts as data.
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:59](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L59)
+[rule_registry/server/alert_data_client/alerts_client.ts:59](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L59)
## Properties
@@ -51,7 +51,7 @@ on alerts as data.
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:57](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L57)
+[rule_registry/server/alert_data_client/alerts_client.ts:57](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L57)
___
@@ -61,7 +61,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:58](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L58)
+[rule_registry/server/alert_data_client/alerts_client.ts:58](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L58)
___
@@ -71,7 +71,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:59](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L59)
+[rule_registry/server/alert_data_client/alerts_client.ts:59](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L59)
___
@@ -81,13 +81,13 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:56](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L56)
+[rule_registry/server/alert_data_client/alerts_client.ts:56](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L56)
## Methods
### fetchAlert
-▸ `Private` **fetchAlert**(`__namedParameters`): `Promise`
+▸ `Private` **fetchAlert**(`__namedParameters`): `Promise`\>, ``"kibana.rac.alert.owner"`` \| ``"rule.id"``\> & { `kibana.rac.alert.owner`: `string` ; `rule.id`: `string` } & { `_version`: `undefined` \| `string` }\>
#### Parameters
@@ -97,17 +97,17 @@ ___
#### Returns
-`Promise`
+`Promise`\>, ``"kibana.rac.alert.owner"`` \| ``"rule.id"``\> & { `kibana.rac.alert.owner`: `string` ; `rule.id`: `string` } & { `_version`: `undefined` \| `string` }\>
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:79](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L79)
+[rule_registry/server/alert_data_client/alerts_client.ts:79](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L79)
___
### get
-▸ **get**(`__namedParameters`): `Promise`\>\>
+▸ **get**(`__namedParameters`): `Promise`\>\>
#### Parameters
@@ -117,11 +117,11 @@ ___
#### Returns
-`Promise`\>\>
+`Promise`\>\>
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:108](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L108)
+[rule_registry/server/alert_data_client/alerts_client.ts:115](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L115)
___
@@ -142,7 +142,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:68](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L68)
+[rule_registry/server/alert_data_client/alerts_client.ts:68](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L68)
___
@@ -162,13 +162,13 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:200](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L200)
+[rule_registry/server/alert_data_client/alerts_client.ts:219](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L219)
___
### update
-▸ **update**(`__namedParameters`): `Promise`<`Object`\>
+▸ **update**(`__namedParameters`): `Promise`
#### Type parameters
@@ -184,8 +184,8 @@ ___
#### Returns
-`Promise`<`Object`\>
+`Promise`
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:146](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L146)
+[rule_registry/server/alert_data_client/alerts_client.ts:160](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L160)
diff --git a/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/constructoroptions.md b/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/constructoroptions.md
index e3dbc6b2c2354..051a5affc0379 100644
--- a/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/constructoroptions.md
+++ b/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/constructoroptions.md
@@ -19,7 +19,7 @@
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:34](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L34)
+[rule_registry/server/alert_data_client/alerts_client.ts:34](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L34)
___
@@ -29,7 +29,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:33](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L33)
+[rule_registry/server/alert_data_client/alerts_client.ts:33](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L33)
___
@@ -39,7 +39,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:35](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L35)
+[rule_registry/server/alert_data_client/alerts_client.ts:35](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L35)
___
@@ -49,4 +49,4 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:32](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L32)
+[rule_registry/server/alert_data_client/alerts_client.ts:32](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L32)
diff --git a/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/updateoptions.md b/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/updateoptions.md
index fbc0991635000..10e793155c196 100644
--- a/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/updateoptions.md
+++ b/x-pack/plugins/rule_registry/docs/alerts_client/interfaces/updateoptions.md
@@ -25,7 +25,7 @@
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:41](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L41)
+[rule_registry/server/alert_data_client/alerts_client.ts:41](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L41)
___
@@ -35,7 +35,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:39](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L39)
+[rule_registry/server/alert_data_client/alerts_client.ts:39](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L39)
___
@@ -45,7 +45,7 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:42](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L42)
+[rule_registry/server/alert_data_client/alerts_client.ts:42](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L42)
___
@@ -55,4 +55,4 @@ ___
#### Defined in
-[rule_registry/server/alert_data_client/alerts_client.ts:40](https://github.com/dhurley14/kibana/blob/d2173f5090e/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L40)
+[rule_registry/server/alert_data_client/alerts_client.ts:40](https://github.com/elastic/kibana/blob/f2a94addc85/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts#L40)
diff --git a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts
index fd4d89540f0ce..98cb7729c9440 100644
--- a/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/schema/actions.ts
@@ -23,6 +23,8 @@ export const EndpointActionLogRequestSchema = {
query: schema.object({
page: schema.number({ defaultValue: 1, min: 1 }),
page_size: schema.number({ defaultValue: 10, min: 1, max: 100 }),
+ start_date: schema.maybe(schema.string()),
+ end_date: schema.maybe(schema.string()),
}),
params: schema.object({
agent_id: schema.string(),
diff --git a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts
index dfaad68e295eb..25fc831ca0aa4 100644
--- a/x-pack/plugins/security_solution/common/endpoint/types/actions.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/types/actions.ts
@@ -60,6 +60,8 @@ export type ActivityLogEntry = ActivityLogAction | ActivityLogActionResponse;
export interface ActivityLog {
page: number;
pageSize: number;
+ startDate?: string;
+ endDate?: string;
data: ActivityLogEntry[];
}
diff --git a/x-pack/plugins/security_solution/common/endpoint/types/index.ts b/x-pack/plugins/security_solution/common/endpoint/types/index.ts
index 1e0d798cf7f07..cf8c33d38f8fa 100644
--- a/x-pack/plugins/security_solution/common/endpoint/types/index.ts
+++ b/x-pack/plugins/security_solution/common/endpoint/types/index.ts
@@ -178,8 +178,6 @@ export interface HostResultList {
request_page_size: number;
/* the page index requested */
request_page_index: number;
- /* the version of the query strategy */
- query_strategy_version: MetadataQueryStrategyVersions;
/* policy IDs and versions */
policy_info?: HostInfo['policy_info'];
}
@@ -404,21 +402,11 @@ export enum HostStatus {
INACTIVE = 'inactive',
}
-export enum MetadataQueryStrategyVersions {
- VERSION_1 = 'v1',
- VERSION_2 = 'v2',
-}
-
export type PolicyInfo = Immutable<{
revision: number;
id: string;
}>;
-export interface HostMetadataInfo {
- metadata: HostMetadata;
- query_strategy_version: MetadataQueryStrategyVersions;
-}
-
export type HostInfo = Immutable<{
metadata: HostMetadata;
host_status: HostStatus;
@@ -438,8 +426,6 @@ export type HostInfo = Immutable<{
*/
endpoint: PolicyInfo;
};
- /* the version of the query strategy */
- query_strategy_version: MetadataQueryStrategyVersions;
}>;
// HostMetadataDetails is now just HostMetadata
diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
index ad71d54eb2a7a..ce00c9b40aead 100644
--- a/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
+++ b/x-pack/plugins/security_solution/cypress/integration/detection_rules/threshold_rule.spec.ts
@@ -6,7 +6,7 @@
*/
import { formatMitreAttackDescription } from '../../helpers/rules';
-import { indexPatterns, newRule, newThresholdRule } from '../../objects/rule';
+import { indexPatterns, newRule, newThresholdRule, ThresholdRule } from '../../objects/rule';
import {
ALERT_RULE_METHOD,
@@ -180,9 +180,9 @@ describe('Detection rules, threshold', () => {
cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', rule.riskScore);
});
- it('Preview results', () => {
- const previewRule = { ...newThresholdRule };
- previewRule.index!.push('.siem-signals*');
+ it('Preview results of keyword using "host.name"', () => {
+ const previewRule: ThresholdRule = { ...newThresholdRule };
+ previewRule.index = [...previewRule.index, '.siem-signals*'];
createCustomRuleActivated(newRule);
goToManageAlertsDetectionRules();
@@ -194,4 +194,23 @@ describe('Detection rules, threshold', () => {
cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '3 unique hits');
});
+
+ it('Preview results of "ip" using "source.ip"', () => {
+ const previewRule: ThresholdRule = {
+ ...newThresholdRule,
+ thresholdField: 'source.ip',
+ threshold: '1',
+ };
+ previewRule.index = [...previewRule.index, '.siem-signals*'];
+
+ createCustomRuleActivated(newRule);
+ goToManageAlertsDetectionRules();
+ waitForRulesTableToBeLoaded();
+ goToCreateNewRule();
+ selectThresholdRuleType();
+ fillDefineThresholdRule(previewRule);
+ previewResults();
+
+ cy.get(PREVIEW_HEADER_SUBTITLE).should('have.text', '10 unique hits');
+ });
});
diff --git a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
index 9b74110f0ef77..1b420cd6d1520 100644
--- a/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
+++ b/x-pack/plugins/security_solution/cypress/tasks/create_new_rule.ts
@@ -275,7 +275,7 @@ export const fillDefineThresholdRule = (rule: ThresholdRule) => {
cy.get(TIMELINE(rule.timeline.id!)).click();
cy.get(COMBO_BOX_CLEAR_BTN).click();
- rule.index!.forEach((index) => {
+ rule.index.forEach((index) => {
cy.get(COMBO_BOX_INPUT).first().type(`${index}{enter}`);
});
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx
index 3a1a29b63eadf..329b8e32f057d 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/alert_summary_view.tsx
@@ -213,7 +213,7 @@ const AlertSummaryViewComponent: React.FC<{
return (
<>
-
+
{
- const mount = useMountAppended();
- const mockTheme = getMockTheme({
- eui: {
- euiBreakpoints: {
- l: '1200px',
- },
- paddingSizes: {
- m: '8px',
- xl: '32px',
- },
- },
- });
-
- test('renders correct items', () => {
- const wrapper = mount(
-
-
-
- );
- expect(wrapper.find('[data-test-subj="empty-threat-details-view"]').exists()).toEqual(true);
- });
-
- test('renders link to docs', () => {
- const wrapper = mount(
-
-
-
- );
- expect(wrapper.find('a').exists()).toEqual(true);
- });
-});
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx
deleted file mode 100644
index d7e1c4d7754ec..0000000000000
--- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/empty_threat_details_view.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import { EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui';
-import React from 'react';
-import styled from 'styled-components';
-
-import { useKibana } from '../../../lib/kibana';
-import * as i18n from './translations';
-
-const EmptyThreatDetailsViewContainer = styled.div`
- display: flex;
- flex-direction: column;
- align-items: center;
-`;
-
-const Span = styled.span`
- color: ${({ theme }) => theme.eui.euiColorDarkShade};
- line-height: 1.8em;
- text-align: center;
- padding: ${({ theme }) => `${theme.eui.paddingSizes.m} ${theme.eui.paddingSizes.xl}`};
-`;
-
-const EmptyThreatDetailsViewComponent: React.FC<{}> = () => {
- const threatIntelDocsUrl = `${
- useKibana().services.docLinks.links.filebeat.base
- }/filebeat-module-threatintel.html`;
-
- return (
-
-
-
- {i18n.NO_ENRICHMENT_FOUND}
-
-
- {i18n.IF_CTI_NOT_ENABLED}
-
- {i18n.CHECK_DOCS}
-
-
-
- );
-};
-
-EmptyThreatDetailsViewComponent.displayName = 'EmptyThreatDetailsView';
-
-export const EmptyThreatDetailsView = React.memo(EmptyThreatDetailsViewComponent);
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx
new file mode 100644
index 0000000000000..819c666bd7267
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.test.tsx
@@ -0,0 +1,57 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import React from 'react';
+import { mount } from 'enzyme';
+
+import { NoEnrichmentsPanel } from './no_enrichments_panel';
+import * as i18n from './translations';
+
+jest.mock('../../../lib/kibana');
+
+describe('NoEnrichmentsPanelView', () => {
+ it('renders a qualified container', () => {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(true);
+ });
+
+ it('renders nothing when all enrichments are present', () => {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(false);
+ });
+
+ it('renders expected text when no enrichments are present', () => {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain(
+ i18n.NO_ENRICHMENTS_FOUND_TITLE
+ );
+ });
+
+ it('renders expected text when existing enrichments are absent', () => {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain(
+ i18n.NO_INDICATOR_ENRICHMENTS_TITLE
+ );
+ });
+
+ it('renders expected text when investigation enrichments are absent', () => {
+ const wrapper = mount(
+
+ );
+ expect(wrapper.find('[data-test-subj="no-enrichments-panel"]').hostNodes().text()).toContain(
+ i18n.NO_INVESTIGATION_ENRICHMENTS_TITLE
+ );
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx
new file mode 100644
index 0000000000000..b521c3ba92c4d
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/no_enrichments_panel.tsx
@@ -0,0 +1,88 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { EuiHorizontalRule, EuiLink, EuiPanel, EuiSpacer, EuiText } from '@elastic/eui';
+import React from 'react';
+import styled from 'styled-components';
+import { useKibana } from '../../../lib/kibana';
+
+import * as i18n from './translations';
+
+const Container = styled(EuiPanel)`
+ display: flex;
+ flex-direction: column;
+`;
+
+const NoEnrichmentsPanelView: React.FC<{
+ title: React.ReactNode;
+ description: React.ReactNode;
+}> = ({ title, description }) => {
+ return (
+
+ {title}
+
+
+ {description}
+
+
+ );
+};
+
+NoEnrichmentsPanelView.displayName = 'NoEnrichmentsPanelView';
+
+export const NoEnrichmentsPanel: React.FC<{
+ existingEnrichmentsCount: number;
+ investigationEnrichmentsCount: number;
+}> = ({ existingEnrichmentsCount, investigationEnrichmentsCount }) => {
+ const threatIntelDocsUrl = `${
+ useKibana().services.docLinks.links.filebeat.base
+ }/filebeat-module-threatintel.html`;
+ const noIndicatorEnrichmentsDescription = (
+ <>
+ {i18n.IF_CTI_NOT_ENABLED}
+
+ {i18n.CHECK_DOCS}
+
+ >
+ );
+
+ if (existingEnrichmentsCount === 0 && investigationEnrichmentsCount === 0) {
+ return (
+ {i18n.NO_ENRICHMENTS_FOUND_TITLE}}
+ description={
+ <>
+ {noIndicatorEnrichmentsDescription}
+ {i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION}
+ >
+ }
+ />
+ );
+ } else if (existingEnrichmentsCount === 0) {
+ return (
+ <>
+
+ {i18n.NO_INDICATOR_ENRICHMENTS_TITLE}}
+ description={noIndicatorEnrichmentsDescription}
+ />
+ >
+ );
+ } else if (investigationEnrichmentsCount === 0) {
+ return (
+ <>
+
+ {i18n.NO_INVESTIGATION_ENRICHMENTS_TITLE}}
+ description={i18n.NO_INVESTIGATION_ENRICHMENTS_DESCRIPTION}
+ />
+ >
+ );
+ } else {
+ return null;
+ }
+};
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx
index 0113dde96a4b6..c25457a5e5e88 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.test.tsx
@@ -31,15 +31,6 @@ describe('ThreatDetailsView', () => {
);
});
- it('renders an empty view if there are no enrichments', () => {
- const wrapper = mount(
-
-
-
- );
- expect(wrapper.find('[data-test-subj="empty-threat-details-view"]').exists()).toEqual(true);
- });
-
it('renders anchor links for event.url and event.reference', () => {
const enrichments = [
buildEventEnrichmentMock({
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx
index d5e985c5757a6..b6b8a47c1dd8c 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/cti_details/threat_details_view.tsx
@@ -20,7 +20,6 @@ import React, { Fragment } from 'react';
import { StyledEuiInMemoryTable } from '../summary_view';
import { getSummaryColumns, SummaryRow, ThreatDetailsRow } from '../helpers';
-import { EmptyThreatDetailsView } from './empty_threat_details_view';
import { FIRSTSEEN, EVENT_URL, EVENT_REFERENCE } from '../../../../../common/cti/constants';
import { DEFAULT_INDICATOR_SOURCE_PATH } from '../../../../../common/constants';
import { getFirstElement } from '../../../../../common/utils/data_retrieval';
@@ -70,15 +69,13 @@ const ThreatDetailsHeader: React.FC<{
+ {isInvestigationTimeEnrichment(type) && (
+
+
+
+ )}
- {isInvestigationTimeEnrichment(type) && (
-
-
-
-
-
- )}
>
);
@@ -131,10 +128,6 @@ const buildThreatDetailsItems = (enrichment: CtiEnrichment) =>
const ThreatDetailsViewComponent: React.FC<{
enrichments: CtiEnrichment[];
}> = ({ enrichments }) => {
- if (enrichments.length < 1) {
- return ;
- }
-
const sortedEnrichments = enrichments.sort((a, b) => getFirstSeen(b) - getFirstSeen(a));
return (
@@ -146,6 +139,7 @@ const ThreatDetailsViewComponent: React.FC<{
return (
+
{
).toEqual('Summary');
});
});
+
+ describe('threat intel tab', () => {
+ it('renders a "no enrichments" panel view if there are no enrichments', () => {
+ alertsWrapper.find('[data-test-subj="threatIntelTab"]').first().simulate('click');
+ expect(alertsWrapper.find('[data-test-subj="no-enrichments-panel"]').exists()).toEqual(true);
+ });
+ });
});
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx
index 9afaaef61b17a..7074212dcdb4c 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/event_details.tsx
@@ -9,9 +9,6 @@ import {
EuiTabbedContent,
EuiTabbedContentTab,
EuiSpacer,
- EuiButton,
- EuiFlexGroup,
- EuiFlexItem,
EuiLoadingContent,
EuiLoadingSpinner,
} from '@elastic/eui';
@@ -34,6 +31,7 @@ import {
parseExistingEnrichments,
timelineDataToEnrichment,
} from './cti_details/helpers';
+import { NoEnrichmentsPanel } from './cti_details/no_enrichments_panel';
type EventViewTab = EuiTabbedContentTab;
@@ -100,9 +98,6 @@ const EventDetailsComponent: React.FC = ({
(tab: EuiTabbedContentTab) => setSelectedTabId(tab.id as EventViewId),
[setSelectedTabId]
);
- const viewThreatIntelTab = useCallback(() => setSelectedTabId(EventsViewType.threatIntelView), [
- setSelectedTabId,
- ]);
const eventFields = useMemo(() => getEnrichmentFields(data), [data]);
const existingEnrichments = useMemo(
@@ -118,6 +113,9 @@ const EventDetailsComponent: React.FC = ({
loading: enrichmentsLoading,
result: enrichmentsResponse,
} = useInvestigationTimeEnrichment(eventFields);
+ const investigationEnrichments = useMemo(() => enrichmentsResponse?.enrichments ?? [], [
+ enrichmentsResponse?.enrichments,
+ ]);
const allEnrichments = useMemo(() => {
if (enrichmentsLoading || !enrichmentsResponse?.enrichments) {
return existingEnrichments;
@@ -140,29 +138,20 @@ const EventDetailsComponent: React.FC = ({
eventId: id,
browserFields,
timelineId,
- title: i18n.ALERT_SUMMARY,
}}
/>
+ {enrichmentCount > 0 && (
+
+ )}
{enrichmentsLoading && (
<>
>
)}
- {enrichmentCount > 0 && (
- <>
-
-
-
-
- {i18n.VIEW_CTI_DATA}
-
-
- >
- )}
>
),
}
@@ -176,7 +165,6 @@ const EventDetailsComponent: React.FC = ({
enrichmentsLoading,
enrichmentCount,
allEnrichments,
- viewThreatIntelTab,
]
);
@@ -192,10 +180,25 @@ const EventDetailsComponent: React.FC = ({
{enrichmentsLoading ? : `(${enrichmentCount})`}
),
- content: ,
+ content: (
+ <>
+
+
+ >
+ ),
}
: undefined,
- [allEnrichments, enrichmentCount, enrichmentsLoading, isAlert]
+ [
+ allEnrichments,
+ enrichmentCount,
+ enrichmentsLoading,
+ existingEnrichments.length,
+ investigationEnrichments.length,
+ isAlert,
+ ]
);
const tableTab = useMemo(
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx
index 0e846f3f6f699..961860ed6d8b9 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/summary_view.tsx
@@ -13,12 +13,13 @@ import { SummaryRow } from './helpers';
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const StyledEuiInMemoryTable = styled(EuiInMemoryTable as any)`
- .euiTableHeaderCell {
- border: none;
- }
+ .euiTableHeaderCell,
.euiTableRowCell {
border: none;
}
+ .euiTableHeaderCell .euiTableCellContent {
+ padding: 0;
+ }
`;
const StyledEuiTitle = styled(EuiTitle)`
diff --git a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts
index a17ca5e434ace..c632f5d6332e0 100644
--- a/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts
+++ b/x-pack/plugins/security_solution/public/common/components/event_details/translations.ts
@@ -11,22 +11,10 @@ export const SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.summa
defaultMessage: 'Summary',
});
-export const ALERT_SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.alertSummary', {
- defaultMessage: 'Alert Summary',
-});
-
export const THREAT_INTEL = i18n.translate('xpack.securitySolution.alertDetails.threatIntel', {
defaultMessage: 'Threat Intel',
});
-export const THREAT_SUMMARY = i18n.translate('xpack.securitySolution.alertDetails.threatSummary', {
- defaultMessage: 'Threat Summary',
-});
-
-export const VIEW_CTI_DATA = i18n.translate('xpack.securitySolution.alertDetails.threatIntelCta', {
- defaultMessage: 'View threat intel data',
-});
-
export const INVESTIGATION_GUIDE = i18n.translate(
'xpack.securitySolution.alertDetails.summary.investigationGuide',
{
diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap
index 22805d34d2ee1..410fb7f3ae793 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap
+++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/__snapshots__/groups_filter_popover.test.tsx.snap
@@ -10,6 +10,7 @@ exports[`GroupsFilterPopover renders correctly against snapshot 1`] = `
iconType="arrowDown"
isSelected={false}
numActiveFilters={0}
+ numFilters={3}
onClick={[Function]}
>
Groups
diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx
index b7425a62f6773..249dc0dfccdbb 100644
--- a/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/jobs_table/filters/groups_filter_popover.tsx
@@ -59,6 +59,7 @@ export const GroupsFilterPopoverComponent = ({
iconType="arrowDown"
onClick={() => setIsGroupPopoverOpen(!isGroupPopoverOpen)}
isSelected={isGroupPopoverOpen}
+ numFilters={uniqueGroups.length}
hasActiveFilters={selectedGroups.length > 0}
numActiveFilters={selectedGroups.length}
>
diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx
index 6342d468f5962..45b66058a04fb 100644
--- a/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/rules/query_preview/index.tsx
@@ -118,6 +118,7 @@ export const PreviewQuery = ({
startDate: toTime,
filterQuery: queryFilter,
indexNames: index,
+ includeMissingData: false,
histogramType: MatrixHistogramType.events,
stackByField: 'event.category',
threshold: ruleType === 'threshold' ? threshold : undefined,
diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
index 45ce5bc18361c..c5262caf6c776 100644
--- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
+++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_table_filters/tags_filter_popover.tsx
@@ -102,9 +102,11 @@ const TagsFilterPopoverComponent = ({
ownFocus
button={
setIsTagPopoverOpen(!isTagPopoverOpen)}
+ numFilters={tags.length}
isSelected={isTagPopoverOpen}
hasActiveFilters={selectedTags.length > 0}
numActiveFilters={selectedTags.length}
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts
index d6b24fa3cbdfc..76de52222bbd3 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/mocks.ts
@@ -15,7 +15,6 @@ import {
HostPolicyResponse,
HostResultList,
HostStatus,
- MetadataQueryStrategyVersions,
} from '../../../../common/endpoint/types';
import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data';
import {
@@ -54,7 +53,6 @@ export const endpointMetadataHttpMocks = httpHandlerMockFactory & {
payload: EndpointState['endpointDetails']['activityLog']['logData'];
};
@@ -165,9 +158,18 @@ export interface EndpointDetailsActivityLogUpdatePaging {
type: 'endpointDetailsActivityLogUpdatePaging';
payload: {
// disable paging when no more data after paging
- disabled: boolean;
+ disabled?: boolean;
page: number;
pageSize: number;
+ startDate?: string;
+ endDate?: string;
+ };
+}
+
+export interface EndpointDetailsActivityLogUpdateIsInvalidDateRange {
+ type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange';
+ payload: {
+ isInvalidDateRange?: boolean;
};
}
@@ -181,8 +183,8 @@ export type EndpointAction =
| ServerFailedToReturnEndpointList
| ServerReturnedEndpointDetails
| ServerFailedToReturnEndpointDetails
- | AppRequestedEndpointActivityLog
| EndpointDetailsActivityLogUpdatePaging
+ | EndpointDetailsActivityLogUpdateIsInvalidDateRange
| EndpointDetailsFlyoutTabChanged
| EndpointDetailsActivityLogChanged
| ServerReturnedEndpointPolicyResponse
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts
index 5db861d18cd69..384a7b999d826 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts
@@ -25,6 +25,9 @@ export const initialEndpointPageState = (): Immutable => {
disabled: false,
page: 1,
pageSize: 50,
+ startDate: undefined,
+ endDate: undefined,
+ isInvalidDateRange: false,
},
logData: createUninitialisedResourceState(),
},
@@ -53,7 +56,6 @@ export const initialEndpointPageState = (): Immutable => {
agentsWithEndpointsTotalError: undefined,
endpointsTotal: 0,
endpointsTotalError: undefined,
- queryStrategyVersion: undefined,
policyVersionInfo: undefined,
hostStatus: undefined,
isolationRequestState: createUninitialisedResourceState(),
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
index 3bf625d726e5f..a9c65c74015c6 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/index.test.ts
@@ -48,6 +48,7 @@ describe('EndpointList store concerns', () => {
disabled: false,
page: 1,
pageSize: 50,
+ isInvalidDateRange: false,
},
logData: { type: 'UninitialisedResourceState' },
},
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
index e34e9cf5a83f3..922f10cee2f8b 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts
@@ -28,7 +28,6 @@ import {
nonExistingPolicies,
patterns,
searchBarQuery,
- isTransformEnabled,
getIsIsolationRequestPending,
getCurrentIsolationRequestState,
getActivityLogData,
@@ -65,6 +64,7 @@ import { resolvePathVariables } from '../../../../common/utils/resolve_path_vari
import { EndpointPackageInfoStateChanged } from './action';
import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions';
import { EndpointDetailsTabsTypes } from '../view/details/components/endpoint_details_tabs';
+import { getIsInvalidDateRange } from '../utils';
type EndpointPageStore = ImmutableMiddlewareAPI;
@@ -179,7 +179,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory(getActivityLogData(getState())),
- });
-
+ if (
+ action.type === 'endpointDetailsActivityLogUpdatePaging' &&
+ hasSelectedEndpoint(getState())
+ ) {
try {
- const { page, pageSize } = getActivityLogDataPaging(getState());
+ const { disabled, page, pageSize, startDate, endDate } = getActivityLogDataPaging(
+ getState()
+ );
+ // don't page when paging is disabled or when date ranges are invalid
+ if (disabled) {
+ return;
+ }
+ if (getIsInvalidDateRange({ startDate, endDate })) {
+ dispatch({
+ type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
+ payload: {
+ isInvalidDateRange: true,
+ },
+ });
+ return;
+ }
+
+ dispatch({
+ type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
+ payload: {
+ isInvalidDateRange: false,
+ },
+ });
+ dispatch({
+ type: 'endpointDetailsActivityLogChanged',
+ // ts error to be fixed when AsyncResourceState is refactored (#830)
+ // @ts-expect-error
+ payload: createLoadingResourceState(getActivityLogData(getState())),
+ });
const route = resolvePathVariables(ENDPOINT_ACTION_LOG_ROUTE, {
agent_id: selectedAgent(getState()),
});
const activityLog = await coreStart.http.get(route, {
- query: { page, page_size: pageSize },
+ query: {
+ page,
+ page_size: pageSize,
+ start_date: startDate,
+ end_date: endDate,
+ },
});
const lastLoadedLogData = getLastLoadedActivityLogData(getState());
@@ -428,6 +457,8 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory 1 ? activityLog.page - 1 : 1,
pageSize: activityLog.pageSize,
+ startDate: activityLog.startDate,
+ endDate: activityLog.endDate,
},
});
}
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
index 8d257678a425d..e0590a80a66aa 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/mock_endpoint_result_list.ts
@@ -12,7 +12,6 @@ import {
HostPolicyResponse,
HostResultList,
HostStatus,
- MetadataQueryStrategyVersions,
PendingActionsResponse,
} from '../../../../../common/endpoint/types';
import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data';
@@ -38,13 +37,11 @@ export const mockEndpointResultList: (options?: {
total?: number;
request_page_size?: number;
request_page_index?: number;
- query_strategy_version?: MetadataQueryStrategyVersions;
}) => HostResultList = (options = {}) => {
const {
total = 1,
request_page_size: requestPageSize = 10,
request_page_index: requestPageIndex = 0,
- query_strategy_version: queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2,
} = options;
// Skip any that are before the page we're on
@@ -58,7 +55,6 @@ export const mockEndpointResultList: (options?: {
hosts.push({
metadata: generator.generateHostMetadata(),
host_status: HostStatus.UNHEALTHY,
- query_strategy_version: queryStrategyVersion,
});
}
const mock: HostResultList = {
@@ -66,7 +62,6 @@ export const mockEndpointResultList: (options?: {
total,
request_page_size: requestPageSize,
request_page_index: requestPageIndex,
- query_strategy_version: queryStrategyVersion,
};
return mock;
};
@@ -78,7 +73,6 @@ export const mockEndpointDetailsApiResult = (): HostInfo => {
return {
metadata: generator.generateHostMetadata(),
host_status: HostStatus.UNHEALTHY,
- query_strategy_version: MetadataQueryStrategyVersions.VERSION_2,
};
};
@@ -92,7 +86,6 @@ const endpointListApiPathHandlerMocks = ({
endpointPackagePolicies = [],
policyResponse = generator.generatePolicyResponse(),
agentPolicy = generator.generateAgentPolicy(),
- queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2,
totalAgentsUsingEndpoint = 0,
}: {
/** route handlers will be setup for each individual host in this array */
@@ -101,7 +94,6 @@ const endpointListApiPathHandlerMocks = ({
endpointPackagePolicies?: GetPolicyListResponse['items'];
policyResponse?: HostPolicyResponse;
agentPolicy?: GetAgentPoliciesResponseItem;
- queryStrategyVersion?: MetadataQueryStrategyVersions;
totalAgentsUsingEndpoint?: number;
} = {}) => {
const apiHandlers = {
@@ -119,7 +111,6 @@ const endpointListApiPathHandlerMocks = ({
request_page_size: 10,
request_page_index: 0,
total: endpointsResults?.length || 0,
- query_strategy_version: queryStrategyVersion,
};
},
@@ -192,16 +183,11 @@ export const setEndpointListApiMockImplementation: (
apiResponses?: Parameters[0]
) => void = (
mockedHttpService,
- {
- endpointsResults = mockEndpointResultList({ total: 3 }).hosts,
- queryStrategyVersion = MetadataQueryStrategyVersions.VERSION_2,
- ...pathHandlersOptions
- } = {}
+ { endpointsResults = mockEndpointResultList({ total: 3 }).hosts, ...pathHandlersOptions } = {}
) => {
const apiHandlers = endpointListApiPathHandlerMocks({
...pathHandlersOptions,
endpointsResults,
- queryStrategyVersion,
});
mockedHttpService.post
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
index 0981d621f26f3..c6bf13a3b5715 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts
@@ -41,6 +41,8 @@ const handleEndpointDetailsActivityLogChanged: CaseReducer) =
state.agentsWithEndpointsTotalError;
export const endpointsTotalError = (state: Immutable) => state.endpointsTotalError;
-const queryStrategyVersion = (state: Immutable) => state.queryStrategyVersion;
export const endpointPackageVersion = createSelector(endpointPackageInfo, (info) =>
isLoadedResourceState(info) ? info.data.version : undefined
);
-export const isTransformEnabled = createSelector(
- queryStrategyVersion,
- (version) => version !== MetadataQueryStrategyVersions.VERSION_1
-);
-
/**
* Returns the index patterns for the SearchBar to use for autosuggest
*/
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts
index de213b3dbccc3..875841cb55b73 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts
@@ -13,7 +13,6 @@ import {
HostPolicyResponse,
AppLocation,
PolicyData,
- MetadataQueryStrategyVersions,
HostStatus,
HostIsolationResponse,
EndpointPendingActions,
@@ -40,9 +39,12 @@ export interface EndpointState {
flyoutView: EndpointIndexUIQueryParams['show'];
activityLog: {
paging: {
- disabled: boolean;
+ disabled?: boolean;
page: number;
pageSize: number;
+ startDate?: string;
+ endDate?: string;
+ isInvalidDateRange: boolean;
};
logData: AsyncResourceState;
};
@@ -93,8 +95,6 @@ export interface EndpointState {
endpointsTotal: number;
/** api error for total, actual Endpoints */
endpointsTotalError?: ServerApiError;
- /** The query strategy version that informs whether the transform for KQL is enabled or not */
- queryStrategyVersion?: MetadataQueryStrategyVersions;
/** The policy IDs and revision number of the corresponding agent, and endpoint. May be more recent than what's running */
policyVersionInfo?: HostInfo['policy_info'];
/** The status of the host, which is mapped to the Elastic Agent status in Fleet */
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.test.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.test.ts
new file mode 100644
index 0000000000000..fa2aaaa16ae37
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.test.ts
@@ -0,0 +1,30 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import moment from 'moment';
+import { getIsInvalidDateRange } from './utils';
+
+describe('utils', () => {
+ describe('getIsInvalidDateRange', () => {
+ it('should return FALSE when either dates are undefined', () => {
+ expect(getIsInvalidDateRange({})).toBe(false);
+ expect(getIsInvalidDateRange({ startDate: moment().subtract(1, 'd').toISOString() })).toBe(
+ false
+ );
+ expect(getIsInvalidDateRange({ endDate: moment().toISOString() })).toBe(false);
+ });
+
+ it('should return TRUE when startDate is after endDate', () => {
+ expect(
+ getIsInvalidDateRange({
+ startDate: moment().toISOString(),
+ endDate: moment().subtract(1, 'd').toISOString(),
+ })
+ ).toBe(true);
+ });
+ });
+});
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts
index 3e17992dd975f..e2d619743c83b 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/utils.ts
@@ -5,6 +5,7 @@
* 2.0.
*/
+import moment from 'moment';
import { HostInfo, HostMetadata } from '../../../../common/endpoint/types';
export const isPolicyOutOfDate = (
@@ -23,3 +24,18 @@ export const isPolicyOutOfDate = (
reported.endpoint_policy_version >= current.endpoint.revision
);
};
+
+export const getIsInvalidDateRange = ({
+ startDate,
+ endDate,
+}: {
+ startDate?: string;
+ endDate?: string;
+}) => {
+ if (startDate && endDate) {
+ const start = moment(startDate);
+ const end = moment(endDate);
+ return start.isAfter(end);
+ }
+ return false;
+};
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.tsx
new file mode 100644
index 0000000000000..f11d2872e3d26
--- /dev/null
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/activity_log_date_range_picker/index.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 { useDispatch } from 'react-redux';
+import React, { memo, useCallback } from 'react';
+import styled from 'styled-components';
+import moment from 'moment';
+import { EuiFlexGroup, EuiFlexItem, EuiDatePicker, EuiDatePickerRange } from '@elastic/eui';
+
+import * as i18 from '../../../translations';
+import { useEndpointSelector } from '../../../hooks';
+import { getActivityLogDataPaging } from '../../../../store/selectors';
+
+const DatePickerWrapper = styled.div`
+ width: ${(props) => props.theme.eui.fractions.single.percentage};
+ background: white;
+`;
+const StickyFlexItem = styled(EuiFlexItem)`
+ position: sticky;
+ top: ${(props) => props.theme.eui.euiSizeM};
+ z-index: 1;
+`;
+
+export const DateRangePicker = memo(() => {
+ const dispatch = useDispatch();
+ const { page, pageSize, startDate, endDate, isInvalidDateRange } = useEndpointSelector(
+ getActivityLogDataPaging
+ );
+
+ const onClear = useCallback(
+ ({ clearStart = false, clearEnd = false }: { clearStart?: boolean; clearEnd?: boolean }) => {
+ dispatch({
+ type: 'endpointDetailsActivityLogUpdatePaging',
+ payload: {
+ disabled: false,
+ page,
+ pageSize,
+ startDate: clearStart ? undefined : startDate,
+ endDate: clearEnd ? undefined : endDate,
+ },
+ });
+ },
+ [dispatch, endDate, startDate, page, pageSize]
+ );
+
+ const onChangeStartDate = useCallback(
+ (date) => {
+ dispatch({
+ type: 'endpointDetailsActivityLogUpdatePaging',
+ payload: {
+ disabled: false,
+ page,
+ pageSize,
+ startDate: date ? date?.toISOString() : undefined,
+ endDate: endDate ? endDate : undefined,
+ },
+ });
+ },
+ [dispatch, endDate, page, pageSize]
+ );
+
+ const onChangeEndDate = useCallback(
+ (date) => {
+ dispatch({
+ type: 'endpointDetailsActivityLogUpdatePaging',
+ payload: {
+ disabled: false,
+ page,
+ pageSize,
+ startDate: startDate ? startDate : undefined,
+ endDate: date ? date.toISOString() : undefined,
+ },
+ });
+ },
+ [dispatch, startDate, page, pageSize]
+ );
+
+ return (
+
+
+
+
+ onClear({ clearStart: true })}
+ placeholderText={i18.ACTIVITY_LOG.datePicker.startDate}
+ selected={startDate ? moment(startDate) : undefined}
+ showTimeSelect
+ startDate={startDate ? moment(startDate) : undefined}
+ />
+ }
+ endDateControl={
+ onClear({ clearEnd: true })}
+ placeholderText={i18.ACTIVITY_LOG.datePicker.endDate}
+ selected={endDate ? moment(endDate) : undefined}
+ showTimeSelect
+ startDate={startDate ? moment(startDate) : undefined}
+ />
+ }
+ />
+
+
+
+
+ );
+});
+
+DateRangePicker.displayName = 'DateRangePicker';
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx
index aa1f56529657e..73a3734e4ca88 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/endpoint_details_tabs.tsx
@@ -56,19 +56,14 @@ export const EndpointDetailsFlyoutTabs = memo(
},
});
if (tab.id === EndpointDetailsTabsTypes.activityLog) {
- const paging = {
- page: 1,
- pageSize,
- };
- dispatch({
- type: 'appRequestedEndpointActivityLog',
- payload: paging,
- });
dispatch({
type: 'endpointDetailsActivityLogUpdatePaging',
payload: {
disabled: false,
- ...paging,
+ page: 1,
+ pageSize,
+ startDate: undefined,
+ endDate: undefined,
},
});
}
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_activity_log.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_activity_log.tsx
index 360d6e3842816..121f23fdb3a9e 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_activity_log.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_activity_log.tsx
@@ -5,7 +5,7 @@
* 2.0.
*/
-import React, { memo, useCallback, useEffect, useRef } from 'react';
+import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react';
import styled from 'styled-components';
import {
@@ -17,6 +17,7 @@ import {
} from '@elastic/eui';
import { useDispatch } from 'react-redux';
import { LogEntry } from './components/log_entry';
+import { DateRangePicker } from './components/activity_log_date_range_picker';
import * as i18 from '../translations';
import { Immutable, ActivityLog } from '../../../../../../common/endpoint/types';
import { AsyncResourceState } from '../../../../state';
@@ -31,12 +32,12 @@ import {
getActivityLogRequestLoading,
} from '../../store/selectors';
-const StyledEuiFlexGroup = styled(EuiFlexGroup)`
- height: 85vh;
+const StyledEuiFlexGroup = styled(EuiFlexGroup)<{ isShorter: boolean }>`
+ height: ${({ isShorter }) => (isShorter ? '25vh' : '85vh')};
`;
const LoadMoreTrigger = styled.div`
- height: 6px;
- width: 100%;
+ height: ${(props) => props.theme.eui.euiSizeXS};
+ width: ${(props) => props.theme.eui.fractions.single.percentage};
`;
export const EndpointActivityLog = memo(
@@ -48,25 +49,37 @@ export const EndpointActivityLog = memo(
const activityLogSize = activityLogData.length;
const activityLogError = useEndpointSelector(getActivityLogError);
const dispatch = useDispatch<(action: EndpointAction) => void>();
- const { page, pageSize, disabled: isPagingDisabled } = useEndpointSelector(
+ const { page, pageSize, startDate, endDate, disabled: isPagingDisabled } = useEndpointSelector(
getActivityLogDataPaging
);
+ const hasActiveDateRange = useMemo(() => !!startDate || !!endDate, [startDate, endDate]);
+ const showEmptyState = useMemo(
+ () => (activityLogLoaded && !activityLogSize && !hasActiveDateRange) || activityLogError,
+ [activityLogLoaded, activityLogSize, hasActiveDateRange, activityLogError]
+ );
+ const isShorter = useMemo(
+ () => !!(hasActiveDateRange && isPagingDisabled && !activityLogLoading && !activityLogSize),
+ [hasActiveDateRange, isPagingDisabled, activityLogLoading, activityLogSize]
+ );
+
const loadMoreTrigger = useRef(null);
const getActivityLog = useCallback(
(entries: IntersectionObserverEntry[]) => {
const isTargetIntersecting = entries.some((entry) => entry.isIntersecting);
if (isTargetIntersecting && activityLogLoaded && !isPagingDisabled) {
dispatch({
- type: 'appRequestedEndpointActivityLog',
+ type: 'endpointDetailsActivityLogUpdatePaging',
payload: {
page: page + 1,
pageSize,
+ startDate,
+ endDate,
},
});
}
},
- [activityLogLoaded, dispatch, isPagingDisabled, page, pageSize]
+ [activityLogLoaded, dispatch, isPagingDisabled, page, pageSize, startDate, endDate]
);
useEffect(() => {
@@ -82,8 +95,8 @@ export const EndpointActivityLog = memo(
return (
<>
-
- {(activityLogLoaded && !activityLogSize) || activityLogError ? (
+
+ {showEmptyState ? (
) : (
<>
+
{activityLogLoaded &&
activityLogData.map((logEntry) => (
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx
index ee5ef52d00f18..26d0d53e39982 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.test.tsx
@@ -23,7 +23,6 @@ import {
HostPolicyResponseActionStatus,
HostPolicyResponseAppliedAction,
HostStatus,
- MetadataQueryStrategyVersions,
} from '../../../../../common/endpoint/types';
import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data';
import { POLICY_STATUS_TO_TEXT } from './host_constants';
@@ -167,31 +166,6 @@ describe('when on the endpoint list page', () => {
});
});
- describe('when loading data with the query_strategy_version is `v1`', () => {
- beforeEach(() => {
- reactTestingLibrary.act(() => {
- const mockedEndpointListData = mockEndpointResultList({
- total: 4,
- query_strategy_version: MetadataQueryStrategyVersions.VERSION_1,
- });
- setEndpointListApiMockImplementation(coreStart.http, {
- endpointsResults: mockedEndpointListData.hosts,
- queryStrategyVersion: mockedEndpointListData.query_strategy_version,
- });
- });
- });
- afterEach(() => {
- jest.clearAllMocks();
- });
- it('should not display the KQL bar', async () => {
- const renderResult = render();
- await reactTestingLibrary.act(async () => {
- await middlewareSpy.waitForAction('serverReturnedEndpointList');
- });
- expect(renderResult.queryByTestId('adminSearchBar')).toBeNull();
- });
- });
-
describe('when determining when to show the enrolling message', () => {
afterEach(() => {
jest.clearAllMocks();
@@ -268,7 +242,6 @@ describe('when on the endpoint list page', () => {
reactTestingLibrary.act(() => {
const mockedEndpointData = mockEndpointResultList({ total: 5 });
const hostListData = mockedEndpointData.hosts;
- const queryStrategyVersion = mockedEndpointData.query_strategy_version;
firstPolicyID = hostListData[0].metadata.Endpoint.policy.applied.id;
firstPolicyRev = hostListData[0].metadata.Endpoint.policy.applied.endpoint_policy_version;
@@ -329,7 +302,6 @@ describe('when on the endpoint list page', () => {
hostListData[index].metadata.Endpoint.policy.applied,
setup.policy
),
- query_strategy_version: queryStrategyVersion,
};
});
hostListData.forEach((item, index) => {
@@ -535,8 +507,6 @@ describe('when on the endpoint list page', () => {
// eslint-disable-next-line @typescript-eslint/naming-convention
host_status,
metadata: { agent, Endpoint, ...details },
- // eslint-disable-next-line @typescript-eslint/naming-convention
- query_strategy_version,
} = mockEndpointDetailsApiResult();
hostDetails = {
@@ -555,7 +525,6 @@ describe('when on the endpoint list page', () => {
id: '1',
},
},
- query_strategy_version,
};
const policy = docGenerator.generatePolicyPackagePolicy();
@@ -889,6 +858,27 @@ describe('when on the endpoint list page', () => {
const emptyState = await renderResult.queryByTestId('activityLogEmpty');
expect(emptyState).not.toBe(null);
});
+
+ it('should not display empty state with no log data while date range filter is active', async () => {
+ const activityLogTab = await renderResult.findByTestId('activity_log');
+ reactTestingLibrary.act(() => {
+ reactTestingLibrary.fireEvent.click(activityLogTab);
+ });
+ await middlewareSpy.waitForAction('endpointDetailsActivityLogChanged');
+ reactTestingLibrary.act(() => {
+ dispatchEndpointDetailsActivityLogChanged('success', {
+ page: 1,
+ pageSize: 50,
+ startDate: new Date().toISOString(),
+ data: [],
+ });
+ });
+
+ const emptyState = await renderResult.queryByTestId('activityLogEmpty');
+ const dateRangePicker = await renderResult.queryByTestId('activityLogDateRangePicker');
+ expect(emptyState).toBe(null);
+ expect(dateRangePicker).not.toBe(null);
+ });
});
describe('when showing host Policy Response panel', () => {
@@ -1177,7 +1167,7 @@ describe('when on the endpoint list page', () => {
let renderResult: ReturnType;
const mockEndpointListApi = () => {
- const { hosts, query_strategy_version: queryStrategyVersion } = mockEndpointResultList();
+ const { hosts } = mockEndpointResultList();
hostInfo = {
host_status: hosts[0].host_status,
metadata: {
@@ -1201,7 +1191,6 @@ describe('when on the endpoint list page', () => {
version: '7.14.0',
},
},
- query_strategy_version: queryStrategyVersion,
};
const packagePolicy = docGenerator.generatePolicyPackagePolicy();
diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx
index 0ee345431055b..c78d4ca6af634 100644
--- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx
+++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/index.tsx
@@ -120,7 +120,6 @@ export const EndpointList = () => {
areEndpointsEnrolling,
agentsWithEndpointsTotalError,
endpointsTotalError,
- isTransformEnabled,
} = useEndpointSelector(selector);
const { search } = useFormatUrl(SecurityPageName.administration);
const { getAppUrl } = useAppUrl();
@@ -476,8 +475,8 @@ export const EndpointList = () => {
const hasListData = listData && listData.length > 0;
const refreshStyle = useMemo(() => {
- return { display: endpointsExist && isTransformEnabled ? 'flex' : 'none', maxWidth: 200 };
- }, [endpointsExist, isTransformEnabled]);
+ return { display: endpointsExist ? 'flex' : 'none', maxWidth: 200 };
+ }, [endpointsExist]);
const refreshIsPaused = useMemo(() => {
return !endpointsExist ? false : hasSelectedEndpoint ? true : !isAutoRefreshEnabled;
@@ -492,8 +491,8 @@ export const EndpointList = () => {
}, [endpointsTotalError, agentsWithEndpointsTotalError]);
const shouldShowKQLBar = useMemo(() => {
- return endpointsExist && !patternsError && isTransformEnabled;
- }, [endpointsExist, patternsError, isTransformEnabled]);
+ return endpointsExist && !patternsError;
+ }, [endpointsExist, patternsError]);
return (
{
title={i18n.DANGER_TITLE}
body={i18n.DANGER_BODY}
button={
-
+
{i18n.DANGER_BUTTON}
}
diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx
index 4565c16bc2bf6..b34f6e657d39a 100644
--- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx
+++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/threat_intel_panel_view.tsx
@@ -22,7 +22,6 @@ import { InspectButtonContainer } from '../../../common/components/inspect';
import { HeaderSection } from '../../../common/components/header_section';
import { ID as CTIEventCountQueryId } from '../../containers/overview_cti_links/use_cti_event_counts';
import { CtiListItem } from '../../containers/overview_cti_links/helpers';
-import { LinkButton } from '../../../common/components/links';
import { useKibana } from '../../../common/lib/kibana';
import { CtiInnerPanel } from './cti_inner_panel';
import * as i18n from './translations';
@@ -36,7 +35,7 @@ const DashboardLinkItems = styled(EuiFlexGroup)`
`;
const Title = styled(EuiFlexItem)`
- min-width: 140px;
+ min-width: 110px;
`;
const List = styled.ul`
@@ -45,12 +44,11 @@ const List = styled.ul`
const DashboardRightSideElement = styled(EuiFlexItem)`
align-items: flex-end;
- max-width: 160px;
`;
const RightSideLink = styled(EuiLink)`
text-align: right;
- min-width: 140px;
+ min-width: 180px;
`;
interface ThreatIntelPanelViewProps {
@@ -96,12 +94,12 @@ export const ThreatIntelPanelView: React.FC = ({
const button = useMemo(
() => (
-
+
-
+
),
[buttonHref]
);
@@ -117,7 +115,11 @@ export const ThreatIntelPanelView: React.FC = ({
color={'primary'}
title={i18n.INFO_TITLE}
body={i18n.INFO_BODY}
- button={{i18n.INFO_BUTTON}}
+ button={
+
+ {i18n.INFO_BUTTON}
+
+ }
/>
) : null,
[isDashboardPluginDisabled, threatIntelDashboardDocLink]
@@ -149,9 +151,7 @@ export const ThreatIntelPanelView: React.FC = ({
gutterSize="l"
justifyContent="spaceBetween"
>
-
- {title}
-
+ {title}
= ({
alignItems="center"
justifyContent="flexEnd"
>
-
+
{count}
-
+
{path ? (
- {linkCopy}
+
+ {linkCopy}
+
) : (
{linkCopy}
diff --git a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts
index 663ec3a75c902..91abd48eb2b7e 100644
--- a/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts
+++ b/x-pack/plugins/security_solution/public/overview/components/overview_cti_links/translations.ts
@@ -51,9 +51,10 @@ export const DANGER_TITLE = i18n.translate(
);
export const DANGER_BODY = i18n.translate(
- 'xpack.securitySolution.overview.ctiDashboardDangerPanelBody',
+ 'xpack.securitySolution.overview.ctiDashboardEnableThreatIntel',
{
- defaultMessage: 'You need to enable module in order to view data from different sources.',
+ defaultMessage:
+ 'You need to enable the filebeat threatintel module in order to view data from different sources.',
}
);
diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts
index d8e7a813c37c3..3ab0e6179f842 100644
--- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts
@@ -20,7 +20,6 @@ import { SecurityPluginStart } from '../../../security/server';
import {
AgentService,
FleetStartContract,
- PackageService,
AgentPolicyServiceInterface,
PackagePolicyServiceInterface,
} from '../../../fleet/server';
@@ -30,14 +29,6 @@ import {
getPackagePolicyUpdateCallback,
} from '../fleet_integration/fleet_integration';
import { ManifestManager } from './services/artifacts';
-import { MetadataQueryStrategy } from './types';
-import { MetadataQueryStrategyVersions } from '../../common/endpoint/types';
-import {
- metadataQueryStrategyV1,
- metadataQueryStrategyV2,
-} from './routes/metadata/support/query_strategies';
-import { ElasticsearchAssetType } from '../../../fleet/common/types/models';
-import { metadataTransformPrefix } from '../../common/endpoint/constants';
import { AppClientFactory } from '../client';
import { ConfigType } from '../config';
import { LicenseService } from '../../common/license';
@@ -46,45 +37,6 @@ import {
parseExperimentalConfigValue,
} from '../../common/experimental_features';
-export interface MetadataService {
- queryStrategy(
- savedObjectsClient: SavedObjectsClientContract,
- version?: MetadataQueryStrategyVersions
- ): Promise;
-}
-
-export const createMetadataService = (packageService: PackageService): MetadataService => {
- return {
- async queryStrategy(
- savedObjectsClient: SavedObjectsClientContract,
- version?: MetadataQueryStrategyVersions
- ): Promise {
- if (version === MetadataQueryStrategyVersions.VERSION_1) {
- return metadataQueryStrategyV1();
- }
- if (!packageService) {
- throw new Error('package service is uninitialized');
- }
-
- if (version === MetadataQueryStrategyVersions.VERSION_2 || !version) {
- const assets =
- (await packageService.getInstallation({ savedObjectsClient, pkgName: 'endpoint' }))
- ?.installed_es ?? [];
- const expectedTransformAssets = assets.filter(
- (ref) =>
- ref.type === ElasticsearchAssetType.transform &&
- ref.id.startsWith(metadataTransformPrefix)
- );
- if (expectedTransformAssets && expectedTransformAssets.length === 1) {
- return metadataQueryStrategyV2();
- }
- return metadataQueryStrategyV1();
- }
- return metadataQueryStrategyV1();
- },
- };
-};
-
export type EndpointAppContextServiceStartContract = Partial<
Pick<
FleetStartContract,
@@ -114,7 +66,6 @@ export class EndpointAppContextService {
private packagePolicyService: PackagePolicyServiceInterface | undefined;
private agentPolicyService: AgentPolicyServiceInterface | undefined;
private savedObjectsStart: SavedObjectsServiceStart | undefined;
- private metadataService: MetadataService | undefined;
private config: ConfigType | undefined;
private license: LicenseService | undefined;
public security: SecurityPluginStart | undefined;
@@ -128,7 +79,6 @@ export class EndpointAppContextService {
this.agentPolicyService = dependencies.agentPolicyService;
this.manifestManager = dependencies.manifestManager;
this.savedObjectsStart = dependencies.savedObjectsStart;
- this.metadataService = createMetadataService(dependencies.packageService!);
this.config = dependencies.config;
this.license = dependencies.licenseService;
this.security = dependencies.security;
@@ -176,10 +126,6 @@ export class EndpointAppContextService {
return this.agentPolicyService;
}
- public getMetadataService(): MetadataService | undefined {
- return this.metadataService;
- }
-
public getManifestManager(): ManifestManager | undefined {
return this.manifestManager;
}
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.test.ts
index c7f07151f8724..d9069444a10d7 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.test.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log.test.ts
@@ -60,6 +60,37 @@ describe('Action Log API', () => {
}).not.toThrow();
});
+ it('should work with all query params', () => {
+ expect(() => {
+ EndpointActionLogRequestSchema.query.validate({
+ page: 10,
+ page_size: 100,
+ start_date: new Date(new Date().setDate(new Date().getDate() - 1)).toISOString(), // yesterday
+ end_date: new Date().toISOString(), // today
+ });
+ }).not.toThrow();
+ });
+
+ it('should work with just startDate', () => {
+ expect(() => {
+ EndpointActionLogRequestSchema.query.validate({
+ page: 1,
+ page_size: 100,
+ start_date: new Date(new Date().setDate(new Date().getDate() - 1)).toISOString(), // yesterday
+ });
+ }).not.toThrow();
+ });
+
+ it('should work with just endDate', () => {
+ expect(() => {
+ EndpointActionLogRequestSchema.query.validate({
+ page: 1,
+ page_size: 100,
+ end_date: new Date().toISOString(), // today
+ });
+ }).not.toThrow();
+ });
+
it('should not work without allowed page and page_size params', () => {
expect(() => {
EndpointActionLogRequestSchema.query.validate({ page_size: 101 });
@@ -176,5 +207,20 @@ describe('Action Log API', () => {
expect(error.message).toEqual(`Error fetching actions log for agent_id ${mockID}`);
}
});
+
+ it('should return date ranges if present in the query', async () => {
+ havingActionsAndResponses([], []);
+ const startDate = new Date(new Date().setDate(new Date().getDate() - 1)).toISOString();
+ const endDate = new Date().toISOString();
+ const response = await getActivityLog({
+ page: 1,
+ page_size: 50,
+ start_date: startDate,
+ end_date: endDate,
+ });
+ expect(response.ok).toBeCalled();
+ expect((response.ok.mock.calls[0][0]?.body as ActivityLog).startDate).toEqual(startDate);
+ expect((response.ok.mock.calls[0][0]?.body as ActivityLog).endDate).toEqual(endDate);
+ });
});
});
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log_handler.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log_handler.ts
index 5e9594f478b31..716c1ab833559 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log_handler.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/audit_log_handler.ts
@@ -27,10 +27,18 @@ export const actionsLogRequestHandler = (
return async (context, req, res) => {
const {
params: { agent_id: elasticAgentId },
- query: { page, page_size: pageSize },
+ query: { page, page_size: pageSize, start_date: startDate, end_date: endDate },
} = req;
- const body = await getAuditLogResponse({ elasticAgentId, page, pageSize, context, logger });
+ const body = await getAuditLogResponse({
+ elasticAgentId,
+ page,
+ pageSize,
+ startDate,
+ endDate,
+ context,
+ logger,
+ });
return res.ok({
body,
});
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts
index 45063ca92e2b0..fceb45b17c258 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/actions/isolation.ts
@@ -83,7 +83,7 @@ export const isolationRequestHandler = function (
// fetch the Agent IDs to send the commands to
const endpointIDs = [...new Set(req.body.endpoint_ids)]; // dedupe
- const endpointData = await getMetadataForEndpoints(endpointIDs, context, endpointContext);
+ const endpointData = await getMetadataForEndpoints(endpointIDs, context);
const casesClient = await endpointContext.service.getCasesClient(req);
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts
index 960f3abda8195..39aa0bf2d8cf7 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/enrichment.test.ts
@@ -5,7 +5,7 @@
* 2.0.
*/
-import { HostStatus, MetadataQueryStrategyVersions } from '../../../../common/endpoint/types';
+import { HostStatus } from '../../../../common/endpoint/types';
import { createMockMetadataRequestContext } from '../../mocks';
import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data';
import { enrichHostMetadata, MetadataRequestContext } from './handlers';
@@ -18,30 +18,6 @@ describe('test document enrichment', () => {
metaReqCtx = createMockMetadataRequestContext();
});
- // verify query version passed through
- describe('metadata query strategy enrichment', () => {
- it('should match v1 strategy when directed', async () => {
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_1
- );
- expect(enrichedHostList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_1
- );
- });
- it('should match v2 strategy when directed', async () => {
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
- expect(enrichedHostList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_2
- );
- });
- });
-
describe('host status enrichment', () => {
let statusFn: jest.Mock;
@@ -57,77 +33,49 @@ describe('test document enrichment', () => {
it('should return host healthy for online agent', async () => {
statusFn.mockImplementation(() => 'online');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.HEALTHY);
});
it('should return host offline for offline agent', async () => {
statusFn.mockImplementation(() => 'offline');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.OFFLINE);
});
it('should return host updating for unenrolling agent', async () => {
statusFn.mockImplementation(() => 'unenrolling');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.UPDATING);
});
it('should return host unhealthy for degraded agent', async () => {
statusFn.mockImplementation(() => 'degraded');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY);
});
it('should return host unhealthy for erroring agent', async () => {
statusFn.mockImplementation(() => 'error');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY);
});
it('should return host unhealthy for warning agent', async () => {
statusFn.mockImplementation(() => 'warning');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY);
});
it('should return host unhealthy for invalid agent', async () => {
statusFn.mockImplementation(() => 'asliduasofb');
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.host_status).toEqual(HostStatus.UNHEALTHY);
});
});
@@ -164,11 +112,7 @@ describe('test document enrichment', () => {
};
});
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.policy_info).toBeDefined();
expect(enrichedHostList.policy_info!.agent.applied.id).toEqual(policyID);
expect(enrichedHostList.policy_info!.agent.applied.revision).toEqual(policyRev);
@@ -184,11 +128,7 @@ describe('test document enrichment', () => {
};
});
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.policy_info).toBeDefined();
expect(enrichedHostList.policy_info!.agent.configured.id).toEqual(policyID);
expect(enrichedHostList.policy_info!.agent.configured.revision).toEqual(policyRev);
@@ -209,11 +149,7 @@ describe('test document enrichment', () => {
};
});
- const enrichedHostList = await enrichHostMetadata(
- docGen.generateHostMetadata(),
- metaReqCtx,
- MetadataQueryStrategyVersions.VERSION_2
- );
+ const enrichedHostList = await enrichHostMetadata(docGen.generateHostMetadata(), metaReqCtx);
expect(enrichedHostList.policy_info).toBeDefined();
expect(enrichedHostList.policy_info!.endpoint.id).toEqual(policyID);
expect(enrichedHostList.policy_info!.endpoint.revision).toEqual(policyRev);
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts
index 815f30e6e7426..2ceca170881e3 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts
@@ -17,10 +17,8 @@ import {
import {
HostInfo,
HostMetadata,
- HostMetadataInfo,
HostResultList,
HostStatus,
- MetadataQueryStrategyVersions,
} from '../../../../common/endpoint/types';
import type { SecuritySolutionRequestHandlerContext } from '../../../types';
@@ -33,6 +31,10 @@ import { findAllUnenrolledAgentIds } from './support/unenroll';
import { findAgentIDsByStatus } from './support/agent_status';
import { EndpointAppContextService } from '../../endpoint_app_context_services';
import { fleetAgentStatusToEndpointHostStatus } from '../../utils';
+import {
+ queryResponseToHostListResult,
+ queryResponseToHostResult,
+} from './support/query_strategies';
export interface MetadataRequestContext {
esClient?: IScopedClusterClient;
@@ -58,8 +60,7 @@ export const getLogger = (endpointAppContext: EndpointAppContext): Logger => {
export const getMetadataListRequestHandler = function (
endpointAppContext: EndpointAppContext,
- logger: Logger,
- queryStrategyVersion?: MetadataQueryStrategyVersions
+ logger: Logger
): RequestHandler<
unknown,
unknown,
@@ -96,24 +97,15 @@ export const getMetadataListRequestHandler = function (
)
: undefined;
- const queryStrategy = await endpointAppContext.service
- ?.getMetadataService()
- ?.queryStrategy(context.core.savedObjects.client, queryStrategyVersion);
-
- const queryParams = await kibanaRequestToMetadataListESQuery(
- request,
- endpointAppContext,
- queryStrategy!,
- {
- unenrolledAgentIds: unenrolledAgentIds.concat(IGNORED_ELASTIC_AGENT_IDS),
- statusAgentIDs: statusIDs,
- }
- );
+ const queryParams = await kibanaRequestToMetadataListESQuery(request, endpointAppContext, {
+ unenrolledAgentIds: unenrolledAgentIds.concat(IGNORED_ELASTIC_AGENT_IDS),
+ statusAgentIDs: statusIDs,
+ });
const result = await context.core.elasticsearch.client.asCurrentUser.search(
queryParams
);
- const hostListQueryResult = queryStrategy!.queryResponseToHostListResult(result.body);
+ const hostListQueryResult = queryResponseToHostListResult(result.body);
return response.ok({
body: await mapToHostResultList(queryParams, hostListQueryResult, metadataRequestContext),
});
@@ -122,8 +114,7 @@ export const getMetadataListRequestHandler = function (
export const getMetadataRequestHandler = function (
endpointAppContext: EndpointAppContext,
- logger: Logger,
- queryStrategyVersion?: MetadataQueryStrategyVersions
+ logger: Logger
): RequestHandler<
TypeOf,
unknown,
@@ -145,11 +136,7 @@ export const getMetadataRequestHandler = function (
};
try {
- const doc = await getHostData(
- metadataRequestContext,
- request?.params?.id,
- queryStrategyVersion
- );
+ const doc = await getHostData(metadataRequestContext, request?.params?.id);
if (doc) {
return response.ok({ body: doc });
}
@@ -169,9 +156,8 @@ export const getMetadataRequestHandler = function (
export async function getHostMetaData(
metadataRequestContext: MetadataRequestContext,
- id: string,
- queryStrategyVersion?: MetadataQueryStrategyVersions
-): Promise {
+ id: string
+): Promise {
if (
!metadataRequestContext.esClient &&
!metadataRequestContext.requestHandlerContext?.core.elasticsearch.client
@@ -190,32 +176,23 @@ export async function getHostMetaData(
metadataRequestContext.requestHandlerContext?.core.elasticsearch
.client) as IScopedClusterClient;
- const esSavedObjectClient =
- metadataRequestContext?.savedObjectsClient ??
- (metadataRequestContext.requestHandlerContext?.core.savedObjects
- .client as SavedObjectsClientContract);
-
- const queryStrategy = await metadataRequestContext.endpointAppContextService
- ?.getMetadataService()
- ?.queryStrategy(esSavedObjectClient, queryStrategyVersion);
- const query = getESQueryHostMetadataByID(id, queryStrategy!);
+ const query = getESQueryHostMetadataByID(id);
const response = await esClient.asCurrentUser.search(query);
- const hostResult = queryStrategy!.queryResponseToHostResult(response.body);
+ const hostResult = queryResponseToHostResult(response.body);
const hostMetadata = hostResult.result;
if (!hostMetadata) {
return undefined;
}
- return { metadata: hostMetadata, query_strategy_version: hostResult.queryStrategyVersion };
+ return hostMetadata;
}
export async function getHostData(
metadataRequestContext: MetadataRequestContext,
- id: string,
- queryStrategyVersion?: MetadataQueryStrategyVersions
+ id: string
): Promise {
if (!metadataRequestContext.savedObjectsClient) {
throw Boom.badRequest('savedObjectsClient not found');
@@ -228,25 +205,21 @@ export async function getHostData(
throw Boom.badRequest('esClient not found');
}
- const hostResult = await getHostMetaData(metadataRequestContext, id, queryStrategyVersion);
+ const hostMetadata = await getHostMetaData(metadataRequestContext, id);
- if (!hostResult) {
+ if (!hostMetadata) {
return undefined;
}
- const agent = await findAgent(metadataRequestContext, hostResult.metadata);
+ const agent = await findAgent(metadataRequestContext, hostMetadata);
if (agent && !agent.active) {
throw Boom.badRequest('the requested endpoint is unenrolled');
}
- const metadata = await enrichHostMetadata(
- hostResult.metadata,
- metadataRequestContext,
- hostResult.query_strategy_version
- );
+ const metadata = await enrichHostMetadata(hostMetadata, metadataRequestContext);
- return { ...metadata, query_strategy_version: hostResult.query_strategy_version };
+ return metadata;
}
async function findAgent(
@@ -293,15 +266,10 @@ export async function mapToHostResultList(
request_page_index: queryParams.from,
hosts: await Promise.all(
hostListQueryResult.resultList.map(async (entry) =>
- enrichHostMetadata(
- entry,
- metadataRequestContext,
- hostListQueryResult.queryStrategyVersion
- )
+ enrichHostMetadata(entry, metadataRequestContext)
)
),
total: totalNumberOfHosts,
- query_strategy_version: hostListQueryResult.queryStrategyVersion,
};
} else {
return {
@@ -309,15 +277,13 @@ export async function mapToHostResultList(
request_page_index: queryParams.from,
total: totalNumberOfHosts,
hosts: [],
- query_strategy_version: hostListQueryResult.queryStrategyVersion,
};
}
}
export async function enrichHostMetadata(
hostMetadata: HostMetadata,
- metadataRequestContext: MetadataRequestContext,
- metadataQueryStrategyVersion: MetadataQueryStrategyVersions
+ metadataRequestContext: MetadataRequestContext
): Promise {
let hostStatus = HostStatus.UNHEALTHY;
let elasticAgentId = hostMetadata?.elastic?.agent?.id;
@@ -413,6 +379,5 @@ export async function enrichHostMetadata(
metadata: hostMetadata,
host_status: hostStatus,
policy_info: policyInfo,
- query_strategy_version: metadataQueryStrategyVersion,
};
}
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts
index b4784c1ff5ed4..d9c3e6c195307 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts
@@ -7,19 +7,15 @@
import { schema } from '@kbn/config-schema';
-import { HostStatus, MetadataQueryStrategyVersions } from '../../../../common/endpoint/types';
+import { HostStatus } from '../../../../common/endpoint/types';
import { EndpointAppContext } from '../../types';
import { getLogger, getMetadataListRequestHandler, getMetadataRequestHandler } from './handlers';
import type { SecuritySolutionPluginRouter } from '../../../types';
import {
- BASE_ENDPOINT_ROUTE,
HOST_METADATA_GET_ROUTE,
HOST_METADATA_LIST_ROUTE,
} from '../../../../common/endpoint/constants';
-export const METADATA_REQUEST_V1_ROUTE = `${BASE_ENDPOINT_ROUTE}/v1/metadata`;
-export const GET_METADATA_REQUEST_V1_ROUTE = `${METADATA_REQUEST_V1_ROUTE}/{id}`;
-
/* Filters that can be applied to the endpoint fetch route */
export const endpointFilters = schema.object({
kql: schema.nullable(schema.string()),
@@ -69,18 +65,6 @@ export function registerEndpointRoutes(
endpointAppContext: EndpointAppContext
) {
const logger = getLogger(endpointAppContext);
- router.post(
- {
- path: `${METADATA_REQUEST_V1_ROUTE}`,
- validate: GetMetadataListRequestSchema,
- options: { authRequired: true, tags: ['access:securitySolution'] },
- },
- getMetadataListRequestHandler(
- endpointAppContext,
- logger,
- MetadataQueryStrategyVersions.VERSION_1
- )
- );
router.post(
{
@@ -91,15 +75,6 @@ export function registerEndpointRoutes(
getMetadataListRequestHandler(endpointAppContext, logger)
);
- router.get(
- {
- path: `${GET_METADATA_REQUEST_V1_ROUTE}`,
- validate: GetMetadataRequestSchema,
- options: { authRequired: true, tags: ['access:securitySolution'] },
- },
- getMetadataRequestHandler(endpointAppContext, logger, MetadataQueryStrategyVersions.VERSION_1)
- );
-
router.get(
{
path: `${HOST_METADATA_GET_ROUTE}`,
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts
index 5250f7c49d6ad..1e56f79aa0b32 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata.test.ts
@@ -19,12 +19,7 @@ import {
loggingSystemMock,
savedObjectsClientMock,
} from '../../../../../../../src/core/server/mocks';
-import {
- HostInfo,
- HostResultList,
- HostStatus,
- MetadataQueryStrategyVersions,
-} from '../../../../common/endpoint/types';
+import { HostInfo, HostResultList, HostStatus } from '../../../../common/endpoint/types';
import { parseExperimentalConfigValue } from '../../../../common/experimental_features';
import { registerEndpointRoutes } from './index';
import {
@@ -39,7 +34,7 @@ import {
import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__';
import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data';
import { Agent, ElasticsearchAssetType } from '../../../../../fleet/common/types/models';
-import { createV1SearchResponse, createV2SearchResponse } from './support/test_support';
+import { createV2SearchResponse } from './support/test_support';
import { PackageService } from '../../../../../fleet/server/services';
import {
HOST_METADATA_LIST_ROUTE,
@@ -98,94 +93,6 @@ describe('test endpoint route', () => {
);
});
- describe('with no transform package', () => {
- beforeEach(() => {
- endpointAppContextService = new EndpointAppContextService();
- mockPackageService = createMockPackageService();
- mockPackageService.getInstallation.mockReturnValue(Promise.resolve(undefined));
- endpointAppContextService.start({ ...startContract, packageService: mockPackageService });
- mockAgentService = startContract.agentService!;
-
- registerEndpointRoutes(routerMock, {
- logFactory: loggingSystemMock.create(),
- service: endpointAppContextService,
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- });
- });
-
- afterEach(() => endpointAppContextService.stop());
-
- it('test find the latest of all endpoints', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({});
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
- [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
- path.startsWith(`${HOST_METADATA_LIST_ROUTE}`)
- )!;
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error');
- mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent);
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.ok).toBeCalled();
- const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList;
- expect(endpointResultList.hosts.length).toEqual(1);
- expect(endpointResultList.total).toEqual(1);
- expect(endpointResultList.request_page_index).toEqual(0);
- expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_1
- );
- });
-
- it('should return a single endpoint with status healthy', async () => {
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
- const mockRequest = httpServerMock.createKibanaRequest({
- params: { id: response.hits.hits[0]._id },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('online');
- mockAgentService.getAgent = jest.fn().mockReturnValue(({
- active: true,
- } as unknown) as Agent);
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${HOST_METADATA_LIST_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.ok).toBeCalled();
- const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo;
- expect(result).toHaveProperty('metadata.Endpoint');
- expect(result.host_status).toEqual(HostStatus.HEALTHY);
- expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_1);
- });
- });
-
describe('with new transform package', () => {
beforeEach(() => {
endpointAppContextService = new EndpointAppContextService();
@@ -254,9 +161,6 @@ describe('test endpoint route', () => {
expect(endpointResultList.total).toEqual(1);
expect(endpointResultList.request_page_index).toEqual(0);
expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_2
- );
});
it('test find the latest of all endpoints with paging properties', async () => {
@@ -311,9 +215,6 @@ describe('test endpoint route', () => {
expect(endpointResultList.total).toEqual(1);
expect(endpointResultList.request_page_index).toEqual(10);
expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_2
- );
});
it('test find the latest of all endpoints with paging and filters properties', async () => {
@@ -405,9 +306,6 @@ describe('test endpoint route', () => {
expect(endpointResultList.total).toEqual(1);
expect(endpointResultList.request_page_index).toEqual(10);
expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_2
- );
});
describe('Endpoint Details route', () => {
@@ -475,7 +373,6 @@ describe('test endpoint route', () => {
const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo;
expect(result).toHaveProperty('metadata.Endpoint');
expect(result.host_status).toEqual(HostStatus.HEALTHY);
- expect(result.query_strategy_version).toEqual(MetadataQueryStrategyVersions.VERSION_2);
});
it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => {
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts
deleted file mode 100644
index 29b2c231cc4a5..0000000000000
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/metadata_v1.test.ts
+++ /dev/null
@@ -1,456 +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 {
- KibanaResponseFactory,
- RequestHandler,
- RouteConfig,
- SavedObjectsClientContract,
- SavedObjectsErrorHelpers,
-} from '../../../../../../../src/core/server';
-import {
- ClusterClientMock,
- ScopedClusterClientMock,
- // eslint-disable-next-line @kbn/eslint/no-restricted-paths
-} from '../../../../../../../src/core/server/elasticsearch/client/mocks';
-import {
- elasticsearchServiceMock,
- httpServerMock,
- httpServiceMock,
- loggingSystemMock,
- savedObjectsClientMock,
-} from '../../../../../../../src/core/server/mocks';
-import {
- HostInfo,
- HostResultList,
- HostStatus,
- MetadataQueryStrategyVersions,
-} from '../../../../common/endpoint/types';
-import { registerEndpointRoutes, METADATA_REQUEST_V1_ROUTE } from './index';
-import {
- createMockEndpointAppContextServiceStartContract,
- createMockPackageService,
- createRouteHandlerContext,
-} from '../../mocks';
-import {
- EndpointAppContextService,
- EndpointAppContextServiceStartContract,
-} from '../../endpoint_app_context_services';
-import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__';
-import { EndpointDocGenerator } from '../../../../common/endpoint/generate_data';
-import { parseExperimentalConfigValue } from '../../../../common/experimental_features';
-import { Agent } from '../../../../../fleet/common/types/models';
-import { createV1SearchResponse } from './support/test_support';
-import { PackageService } from '../../../../../fleet/server/services';
-import type { SecuritySolutionPluginRouter } from '../../../types';
-import { PackagePolicyServiceInterface } from '../../../../../fleet/server';
-
-describe('test endpoint route v1', () => {
- let routerMock: jest.Mocked;
- let mockResponse: jest.Mocked;
- let mockClusterClient: ClusterClientMock;
- let mockScopedClient: ScopedClusterClientMock;
- let mockSavedObjectClient: jest.Mocked;
- let mockPackageService: jest.Mocked;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let routeHandler: RequestHandler;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- let routeConfig: RouteConfig;
- // tests assume that fleet is enabled, and thus agentService is available
- let mockAgentService: Required<
- ReturnType
- >['agentService'];
- let endpointAppContextService: EndpointAppContextService;
- let startContract: EndpointAppContextServiceStartContract;
- const noUnenrolledAgent = {
- agents: [],
- total: 0,
- page: 1,
- perPage: 1,
- };
-
- beforeEach(() => {
- mockClusterClient = elasticsearchServiceMock.createClusterClient();
- mockScopedClient = elasticsearchServiceMock.createScopedClusterClient();
- mockSavedObjectClient = savedObjectsClientMock.create();
- mockClusterClient.asScoped.mockReturnValue(mockScopedClient);
- routerMock = httpServiceMock.createRouter();
- mockResponse = httpServerMock.createResponseFactory();
- endpointAppContextService = new EndpointAppContextService();
- mockPackageService = createMockPackageService();
- mockPackageService.getInstallation.mockReturnValue(Promise.resolve(undefined));
- startContract = createMockEndpointAppContextServiceStartContract();
- endpointAppContextService.start({ ...startContract, packageService: mockPackageService });
- mockAgentService = startContract.agentService!;
-
- (startContract.packagePolicyService as jest.Mocked).list.mockImplementation(
- () => {
- return Promise.resolve({
- items: [],
- total: 0,
- page: 1,
- perPage: 1000,
- });
- }
- );
-
- registerEndpointRoutes(routerMock, {
- logFactory: loggingSystemMock.create(),
- service: endpointAppContextService,
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- });
- });
-
- afterEach(() => endpointAppContextService.stop());
-
- it('test find the latest of all endpoints', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({});
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
- [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error');
- mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent);
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] });
- expect(mockResponse.ok).toBeCalled();
- const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList;
- expect(endpointResultList.hosts.length).toEqual(1);
- expect(endpointResultList.total).toEqual(1);
- expect(endpointResultList.request_page_index).toEqual(0);
- expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_1
- );
- });
-
- it('test find the latest of all endpoints with paging properties', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {
- paging_properties: [
- {
- page_size: 10,
- },
- {
- page_index: 1,
- },
- ],
- },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error');
- mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent);
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({
- body: createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()),
- })
- );
- [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(
- (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool
- .must_not
- ).toContainEqual({
- terms: {
- 'elastic.agent.id': [
- '00000000-0000-0000-0000-000000000000',
- '11111111-1111-1111-1111-111111111111',
- ],
- },
- });
- expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] });
- expect(mockResponse.ok).toBeCalled();
- const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList;
- expect(endpointResultList.hosts.length).toEqual(1);
- expect(endpointResultList.total).toEqual(1);
- expect(endpointResultList.request_page_index).toEqual(10);
- expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_1
- );
- });
-
- it('test find the latest of all endpoints with paging and filters properties', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {
- paging_properties: [
- {
- page_size: 10,
- },
- {
- page_index: 1,
- },
- ],
-
- filters: { kql: 'not host.ip:10.140.73.246' },
- },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error');
- mockAgentService.listAgents = jest.fn().mockReturnValue(noUnenrolledAgent);
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({
- body: createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata()),
- })
- );
- [routeConfig, routeHandler] = routerMock.post.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toBeCalled();
- // needs to have the KQL filter passed through
- expect(
- (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool.must
- ).toContainEqual({
- bool: {
- must_not: {
- bool: {
- should: [
- {
- match: {
- 'host.ip': '10.140.73.246',
- },
- },
- ],
- minimum_should_match: 1,
- },
- },
- },
- });
- // and unenrolled should be filtered out.
- expect(
- (mockScopedClient.asCurrentUser.search as jest.Mock).mock.calls[0][0]?.body?.query.bool.must
- ).toContainEqual({
- bool: {
- must_not: [
- {
- terms: {
- 'elastic.agent.id': [
- '00000000-0000-0000-0000-000000000000',
- '11111111-1111-1111-1111-111111111111',
- ],
- },
- },
- {
- terms: {
- // we actually don't care about HostDetails in v1 queries, but
- // harder to set up the expectation to ignore its inclusion succinctly
- 'HostDetails.elastic.agent.id': [
- '00000000-0000-0000-0000-000000000000',
- '11111111-1111-1111-1111-111111111111',
- ],
- },
- },
- ],
- },
- });
- expect(routeConfig.options).toEqual({ authRequired: true, tags: ['access:securitySolution'] });
- expect(mockResponse.ok).toBeCalled();
- const endpointResultList = mockResponse.ok.mock.calls[0][0]?.body as HostResultList;
- expect(endpointResultList.hosts.length).toEqual(1);
- expect(endpointResultList.total).toEqual(1);
- expect(endpointResultList.request_page_index).toEqual(10);
- expect(endpointResultList.request_page_size).toEqual(10);
- expect(endpointResultList.query_strategy_version).toEqual(
- MetadataQueryStrategyVersions.VERSION_1
- );
- });
-
- describe('Endpoint Details route', () => {
- it('should return 404 on no results', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({ params: { id: 'BADID' } });
-
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: createV1SearchResponse() })
- );
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('error');
- mockAgentService.getAgent = jest.fn().mockReturnValue(({
- active: true,
- } as unknown) as Agent);
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.notFound).toBeCalled();
- const message = mockResponse.notFound.mock.calls[0][0]?.body;
- expect(message).toEqual('Endpoint Not Found');
- });
-
- it('should return a single endpoint with status healthy', async () => {
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
- const mockRequest = httpServerMock.createKibanaRequest({
- params: { id: response.hits.hits[0]._id },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('online');
- mockAgentService.getAgent = jest.fn().mockReturnValue(({
- active: true,
- } as unknown) as Agent);
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.ok).toBeCalled();
- const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo;
- expect(result).toHaveProperty('metadata.Endpoint');
- expect(result.host_status).toEqual(HostStatus.HEALTHY);
- });
-
- it('should return a single endpoint with status unhealthy when AgentService throw 404', async () => {
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
-
- const mockRequest = httpServerMock.createKibanaRequest({
- params: { id: response.hits.hits[0]._id },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockImplementation(() => {
- SavedObjectsErrorHelpers.createGenericNotFoundError();
- });
-
- mockAgentService.getAgent = jest.fn().mockImplementation(() => {
- SavedObjectsErrorHelpers.createGenericNotFoundError();
- });
-
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.ok).toBeCalled();
- const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo;
- expect(result.host_status).toEqual(HostStatus.UNHEALTHY);
- });
-
- it('should return a single endpoint with status unhealthy when status is not offline, online or enrolling', async () => {
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
-
- const mockRequest = httpServerMock.createKibanaRequest({
- params: { id: response.hits.hits[0]._id },
- });
-
- mockAgentService.getAgentStatusById = jest.fn().mockReturnValue('warning');
- mockAgentService.getAgent = jest.fn().mockReturnValue(({
- active: true,
- } as unknown) as Agent);
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(routeConfig.options).toEqual({
- authRequired: true,
- tags: ['access:securitySolution'],
- });
- expect(mockResponse.ok).toBeCalled();
- const result = mockResponse.ok.mock.calls[0][0]?.body as HostInfo;
- expect(result.host_status).toEqual(HostStatus.UNHEALTHY);
- });
-
- it('should throw error when endpoint agent is not active', async () => {
- const response = createV1SearchResponse(new EndpointDocGenerator().generateHostMetadata());
-
- const mockRequest = httpServerMock.createKibanaRequest({
- params: { id: response.hits.hits[0]._id },
- });
- (mockScopedClient.asCurrentUser.search as jest.Mock).mockImplementationOnce(() =>
- Promise.resolve({ body: response })
- );
- mockAgentService.getAgent = jest.fn().mockReturnValue(({
- active: false,
- } as unknown) as Agent);
-
- [routeConfig, routeHandler] = routerMock.get.mock.calls.find(([{ path }]) =>
- path.startsWith(`${METADATA_REQUEST_V1_ROUTE}`)
- )!;
-
- await routeHandler(
- createRouteHandlerContext(mockScopedClient, mockSavedObjectClient),
- mockRequest,
- mockResponse
- );
-
- expect(mockScopedClient.asCurrentUser.search).toHaveBeenCalledTimes(1);
- expect(mockResponse.customError).toBeCalled();
- });
- });
-});
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts
index e790c1de1a5b8..87de5a540ea99 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.test.ts
@@ -11,38 +11,29 @@ import { EndpointAppContextService } from '../../endpoint_app_context_services';
import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__';
import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants';
import { parseExperimentalConfigValue } from '../../../../common/experimental_features';
-import { metadataQueryStrategyV2 } from './support/query_strategies';
import { get } from 'lodash';
describe('query builder', () => {
describe('MetadataListESQuery', () => {
it('queries the correct index', async () => {
const mockRequest = httpServerMock.createKibanaRequest({ body: {} });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV2()
- );
+ const query = await kibanaRequestToMetadataListESQuery(mockRequest, {
+ logFactory: loggingSystemMock.create(),
+ service: new EndpointAppContextService(),
+ config: () => Promise.resolve(createMockConfig()),
+ experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
+ });
expect(query.index).toEqual(metadataCurrentIndexPattern);
});
it('sorts using *event.created', async () => {
const mockRequest = httpServerMock.createKibanaRequest({ body: {} });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV2()
- );
+ const query = await kibanaRequestToMetadataListESQuery(mockRequest, {
+ logFactory: loggingSystemMock.create(),
+ service: new EndpointAppContextService(),
+ config: () => Promise.resolve(createMockConfig()),
+ experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
+ });
expect(query.body.sort).toContainEqual({
'event.created': {
order: 'desc',
@@ -61,16 +52,12 @@ describe('query builder', () => {
const mockRequest = httpServerMock.createKibanaRequest({
body: {},
});
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV2()
- );
+ const query = await kibanaRequestToMetadataListESQuery(mockRequest, {
+ logFactory: loggingSystemMock.create(),
+ service: new EndpointAppContextService(),
+ config: () => Promise.resolve(createMockConfig()),
+ experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
+ });
expect(query.body.query).toHaveProperty('match_all');
});
@@ -87,7 +74,6 @@ describe('query builder', () => {
config: () => Promise.resolve(createMockConfig()),
experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
},
- metadataQueryStrategyV2(),
{
unenrolledAgentIds: [unenrolledElasticAgentId],
}
@@ -111,16 +97,12 @@ describe('query builder', () => {
filters: { kql: 'not host.ip:10.140.73.246' },
},
});
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV2()
- );
+ const query = await kibanaRequestToMetadataListESQuery(mockRequest, {
+ logFactory: loggingSystemMock.create(),
+ service: new EndpointAppContextService(),
+ config: () => Promise.resolve(createMockConfig()),
+ experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
+ });
expect(query.body.query.bool.must).toContainEqual({
bool: {
@@ -160,7 +142,6 @@ describe('query builder', () => {
createMockConfig().enableExperimental
),
},
- metadataQueryStrategyV2(),
{
unenrolledAgentIds: [unenrolledElasticAgentId],
}
@@ -197,13 +178,13 @@ describe('query builder', () => {
describe('MetadataGetQuery', () => {
it('searches the correct index', () => {
- const query = getESQueryHostMetadataByID('nonsense-id', metadataQueryStrategyV2());
+ const query = getESQueryHostMetadataByID('nonsense-id');
expect(query.index).toEqual(metadataCurrentIndexPattern);
});
it('searches for the correct ID', () => {
const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899';
- const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV2());
+ const query = getESQueryHostMetadataByID(mockID);
expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({
term: { 'agent.id': mockID },
@@ -212,7 +193,7 @@ describe('query builder', () => {
it('supports HostDetails in schema for backwards compat', () => {
const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899';
- const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV2());
+ const query = getESQueryHostMetadataByID(mockID);
expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({
term: { 'HostDetails.agent.id': mockID },
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts
index f0950e5fb79ba..99ec1d1022747 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders.ts
@@ -6,9 +6,10 @@
*/
import type { estypes } from '@elastic/elasticsearch';
+import { metadataCurrentIndexPattern } from '../../../../common/endpoint/constants';
import { KibanaRequest } from '../../../../../../../src/core/server';
import { esKuery } from '../../../../../../../src/plugins/data/server';
-import { EndpointAppContext, MetadataQueryStrategy } from '../../types';
+import { EndpointAppContext } from '../../types';
export interface QueryBuilderOptions {
unenrolledAgentIds?: string[];
@@ -39,7 +40,6 @@ export async function kibanaRequestToMetadataListESQuery(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request: KibanaRequest,
endpointAppContext: EndpointAppContext,
- metadataQueryStrategy: MetadataQueryStrategy,
queryBuilderOptions?: QueryBuilderOptions
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise> {
@@ -49,16 +49,15 @@ export async function kibanaRequestToMetadataListESQuery(
body: {
query: buildQueryBody(
request,
- metadataQueryStrategy,
queryBuilderOptions?.unenrolledAgentIds!,
queryBuilderOptions?.statusAgentIDs!
),
- ...metadataQueryStrategy.extraBodyProperties,
+ track_total_hits: true,
sort: MetadataSortMethod,
},
from: pagingProperties.pageIndex * pagingProperties.pageSize,
size: pagingProperties.pageSize,
- index: metadataQueryStrategy.index,
+ index: metadataCurrentIndexPattern,
};
}
@@ -86,7 +85,6 @@ async function getPagingProperties(
function buildQueryBody(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
request: KibanaRequest,
- metadataQueryStrategy: MetadataQueryStrategy,
unerolledAgentIds: string[] | undefined,
statusAgentIDs: string[] | undefined
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -144,10 +142,7 @@ function buildQueryBody(
};
}
-export function getESQueryHostMetadataByID(
- agentID: string,
- metadataQueryStrategy: MetadataQueryStrategy
-): estypes.SearchRequest {
+export function getESQueryHostMetadataByID(agentID: string): estypes.SearchRequest {
return {
body: {
query: {
@@ -167,14 +162,11 @@ export function getESQueryHostMetadataByID(
sort: MetadataSortMethod,
size: 1,
},
- index: metadataQueryStrategy.index,
+ index: metadataCurrentIndexPattern,
};
}
-export function getESQueryHostMetadataByIDs(
- agentIDs: string[],
- metadataQueryStrategy: MetadataQueryStrategy
-) {
+export function getESQueryHostMetadataByIDs(agentIDs: string[]) {
return {
body: {
query: {
@@ -193,6 +185,6 @@ export function getESQueryHostMetadataByIDs(
},
sort: MetadataSortMethod,
},
- index: metadataQueryStrategy.index,
+ index: metadataCurrentIndexPattern,
};
}
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts
deleted file mode 100644
index c18c585cd3d34..0000000000000
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/query_builders_v1.test.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import { httpServerMock, loggingSystemMock } from '../../../../../../../src/core/server/mocks';
-import { kibanaRequestToMetadataListESQuery, getESQueryHostMetadataByID } from './query_builders';
-import { EndpointAppContextService } from '../../endpoint_app_context_services';
-import { createMockConfig } from '../../../lib/detection_engine/routes/__mocks__';
-import { metadataIndexPattern } from '../../../../common/endpoint/constants';
-import { parseExperimentalConfigValue } from '../../../../common/experimental_features';
-import { metadataQueryStrategyV1 } from './support/query_strategies';
-import { get } from 'lodash';
-
-describe('query builder v1', () => {
- describe('MetadataListESQuery', () => {
- it('test default query params for all endpoints metadata when no params or body is provided', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {},
- });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV1()
- );
-
- expect(query.body.query).toHaveProperty('match_all'); // no filtering
- expect(query.body.collapse).toEqual({
- field: 'agent.id',
- inner_hits: {
- name: 'most_recent',
- size: 1,
- sort: [{ 'event.created': 'desc' }],
- },
- });
- expect(query.body.aggs).toEqual({
- total: {
- cardinality: {
- field: 'agent.id',
- },
- },
- });
- expect(query.index).toEqual(metadataIndexPattern);
- });
-
- it(
- 'test default query params for all endpoints metadata when no params or body is provided ' +
- 'with unenrolled host ids excluded',
- async () => {
- const unenrolledElasticAgentId = '1fdca33f-799f-49f4-939c-ea4383c77672';
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {},
- });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(
- createMockConfig().enableExperimental
- ),
- },
- metadataQueryStrategyV1(),
- {
- unenrolledAgentIds: [unenrolledElasticAgentId],
- }
- );
- expect(Object.keys(query.body.query.bool)).toEqual(['must_not']); // only filtering out unenrolled
- expect(query.body.query.bool.must_not).toContainEqual({
- terms: { 'elastic.agent.id': [unenrolledElasticAgentId] },
- });
- }
- );
- });
-
- describe('test query builder with kql filter', () => {
- it('test default query params for all endpoints metadata when body filter is provided', async () => {
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {
- filters: { kql: 'not host.ip:10.140.73.246' },
- },
- });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(createMockConfig().enableExperimental),
- },
- metadataQueryStrategyV1()
- );
- expect(query.body.query.bool.must).toHaveLength(1); // should not be any other filtering happening
- expect(query.body.query.bool.must).toContainEqual({
- bool: {
- must_not: {
- bool: {
- should: [
- {
- match: {
- 'host.ip': '10.140.73.246',
- },
- },
- ],
- minimum_should_match: 1,
- },
- },
- },
- });
- });
-
- it(
- 'test default query params for all endpoints endpoint metadata excluding unerolled endpoint ' +
- 'and when body filter is provided',
- async () => {
- const unenrolledElasticAgentId = '1fdca33f-799f-49f4-939c-ea4383c77672';
- const mockRequest = httpServerMock.createKibanaRequest({
- body: {
- filters: { kql: 'not host.ip:10.140.73.246' },
- },
- });
- const query = await kibanaRequestToMetadataListESQuery(
- mockRequest,
- {
- logFactory: loggingSystemMock.create(),
- service: new EndpointAppContextService(),
- config: () => Promise.resolve(createMockConfig()),
- experimentalFeatures: parseExperimentalConfigValue(
- createMockConfig().enableExperimental
- ),
- },
- metadataQueryStrategyV1(),
- {
- unenrolledAgentIds: [unenrolledElasticAgentId],
- }
- );
-
- expect(query.body.query.bool.must.length).toBeGreaterThan(1);
- // unenrollment filter should be there
- expect(query.body.query.bool.must).toContainEqual({
- bool: {
- must_not: [
- { terms: { 'elastic.agent.id': [unenrolledElasticAgentId] } },
- // below is not actually necessary behavior for v1, but hard to structure the test to ignore it
- { terms: { 'HostDetails.elastic.agent.id': [unenrolledElasticAgentId] } },
- ],
- },
- });
- // and KQL should also be there
- expect(query.body.query.bool.must).toContainEqual({
- bool: {
- must_not: {
- bool: {
- should: [
- {
- match: {
- 'host.ip': '10.140.73.246',
- },
- },
- ],
- minimum_should_match: 1,
- },
- },
- },
- });
- }
- );
- });
-
- describe('MetadataGetQuery', () => {
- it('searches for the correct ID', () => {
- const mockID = 'AABBCCDD-0011-2233-AA44-DEADBEEF8899';
- const query = getESQueryHostMetadataByID(mockID, metadataQueryStrategyV1());
-
- expect(get(query, 'body.query.bool.filter.0.bool.should')).toContainEqual({
- term: { 'agent.id': mockID },
- });
- });
- });
-});
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts
index 506c02fc2f1ec..2d7bff4a53f3f 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/query_strategies.ts
@@ -6,102 +6,39 @@
*/
import { SearchResponse } from '@elastic/elasticsearch/api/types';
-import {
- metadataCurrentIndexPattern,
- metadataIndexPattern,
-} from '../../../../../common/endpoint/constants';
-import { HostMetadata, MetadataQueryStrategyVersions } from '../../../../../common/endpoint/types';
-import { HostListQueryResult, HostQueryResult, MetadataQueryStrategy } from '../../../types';
+import { HostMetadata } from '../../../../../common/endpoint/types';
+import { HostListQueryResult, HostQueryResult } from '../../../types';
-export function metadataQueryStrategyV1(): MetadataQueryStrategy {
- return {
- index: metadataIndexPattern,
- extraBodyProperties: {
- collapse: {
- field: 'agent.id',
- inner_hits: {
- name: 'most_recent',
- size: 1,
- sort: [{ 'event.created': 'desc' }],
- },
- },
- aggs: {
- total: {
- cardinality: {
- field: 'agent.id',
- },
- },
- },
- },
- queryResponseToHostListResult: (
- searchResponse: SearchResponse
- ): HostListQueryResult => {
- const response = searchResponse as SearchResponse;
- return {
- resultLength:
- ((response?.aggregations?.total as unknown) as { value?: number; relation: string })
- ?.value || 0,
- resultList: response.hits.hits
- .map((hit) => hit.inner_hits?.most_recent.hits.hits)
- .flatMap((data) => data)
- .map((entry) => (entry?._source ?? {}) as HostMetadata),
- queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_1,
- };
- },
- queryResponseToHostResult: (searchResponse: SearchResponse): HostQueryResult => {
- const response = searchResponse as SearchResponse;
- return {
- resultLength: response.hits.hits.length,
- result: response.hits.hits.length > 0 ? response.hits.hits[0]._source : undefined,
- queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_1,
- };
- },
- };
+// remove the top-level 'HostDetails' property if found, from previous schemas
+function stripHostDetails(host: HostMetadata | { HostDetails: HostMetadata }): HostMetadata {
+ return 'HostDetails' in host ? host.HostDetails : host;
}
-export function metadataQueryStrategyV2(): MetadataQueryStrategy {
+export const queryResponseToHostResult = (
+ searchResponse: SearchResponse
+): HostQueryResult => {
+ const response = searchResponse as SearchResponse;
return {
- index: metadataCurrentIndexPattern,
- extraBodyProperties: {
- track_total_hits: true,
- },
- queryResponseToHostListResult: (
- searchResponse: SearchResponse
- ): HostListQueryResult => {
- const response = searchResponse as SearchResponse<
- HostMetadata | { HostDetails: HostMetadata }
- >;
- const list =
- response.hits.hits.length > 0
- ? response.hits.hits.map((entry) => stripHostDetails(entry?._source as HostMetadata))
- : [];
-
- return {
- resultLength:
- ((response.hits?.total as unknown) as { value: number; relation: string }).value || 0,
- resultList: list,
- queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_2,
- };
- },
- queryResponseToHostResult: (
- searchResponse: SearchResponse
- ): HostQueryResult => {
- const response = searchResponse as SearchResponse<
- HostMetadata | { HostDetails: HostMetadata }
- >;
- return {
- resultLength: response.hits.hits.length,
- result:
- response.hits.hits.length > 0
- ? stripHostDetails(response.hits.hits[0]._source as HostMetadata)
- : undefined,
- queryStrategyVersion: MetadataQueryStrategyVersions.VERSION_2,
- };
- },
+ resultLength: response.hits.hits.length,
+ result:
+ response.hits.hits.length > 0
+ ? stripHostDetails(response.hits.hits[0]._source as HostMetadata)
+ : undefined,
};
-}
+};
-// remove the top-level 'HostDetails' property if found, from previous schemas
-function stripHostDetails(host: HostMetadata | { HostDetails: HostMetadata }): HostMetadata {
- return 'HostDetails' in host ? host.HostDetails : host;
-}
+export const queryResponseToHostListResult = (
+ searchResponse: SearchResponse
+): HostListQueryResult => {
+ const response = searchResponse as SearchResponse;
+ const list =
+ response.hits.hits.length > 0
+ ? response.hits.hits.map((entry) => stripHostDetails(entry?._source as HostMetadata))
+ : [];
+
+ return {
+ resultLength:
+ ((response.hits?.total as unknown) as { value: number; relation: string }).value || 0,
+ resultList: list,
+ };
+};
diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts
index bc23c253c4347..a0530590f5f9f 100644
--- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/test_support.ts
@@ -8,62 +8,6 @@
import { SearchResponse } from 'elasticsearch';
import { HostMetadata } from '../../../../../common/endpoint/types';
-export function createV1SearchResponse(hostMetadata?: HostMetadata): SearchResponse {
- return ({
- took: 15,
- timed_out: false,
- _shards: {
- total: 1,
- successful: 1,
- skipped: 0,
- failed: 0,
- },
- hits: {
- total: {
- value: 5,
- relation: 'eq',
- },
- max_score: null,
- hits: hostMetadata
- ? [
- {
- _index: 'metrics-endpoint.metadata-default',
- _id: '8FhM0HEBYyRTvb6lOQnw',
- _score: null,
- _source: hostMetadata,
- sort: [1588337587997],
- inner_hits: {
- most_recent: {
- hits: {
- total: {
- value: 2,
- relation: 'eq',
- },
- max_score: null,
- hits: [
- {
- _index: 'metrics-endpoint.metadata-default',
- _id: 'W6Vo1G8BYQH1gtPUgYkC',
- _score: null,
- _source: hostMetadata,
- sort: [1579816615336],
- },
- ],
- },
- },
- },
- },
- ]
- : [],
- },
- aggregations: {
- total: {
- value: 1,
- },
- },
- } as unknown) as SearchResponse;
-}
-
export function createV2SearchResponse(hostMetadata?: HostMetadata): SearchResponse {
return ({
took: 15,
diff --git a/x-pack/plugins/security_solution/server/endpoint/services/actions.ts b/x-pack/plugins/security_solution/server/endpoint/services/actions.ts
index 9d8db5b9a2154..89f088e322ffa 100644
--- a/x-pack/plugins/security_solution/server/endpoint/services/actions.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/services/actions.ts
@@ -19,28 +19,37 @@ export const getAuditLogResponse = async ({
elasticAgentId,
page,
pageSize,
+ startDate,
+ endDate,
context,
logger,
}: {
elasticAgentId: string;
page: number;
pageSize: number;
+ startDate?: string;
+ endDate?: string;
context: SecuritySolutionRequestHandlerContext;
logger: Logger;
-}): Promise<{
- page: number;
- pageSize: number;
- data: ActivityLog['data'];
-}> => {
+}): Promise => {
const size = Math.floor(pageSize / 2);
const from = page <= 1 ? 0 : page * size - size + 1;
const esClient = context.core.elasticsearch.client.asCurrentUser;
-
- const data = await getActivityLog({ esClient, from, size, elasticAgentId, logger });
+ const data = await getActivityLog({
+ esClient,
+ from,
+ size,
+ startDate,
+ endDate,
+ elasticAgentId,
+ logger,
+ });
return {
page,
pageSize,
+ startDate,
+ endDate,
data,
};
};
@@ -49,6 +58,8 @@ const getActivityLog = async ({
esClient,
size,
from,
+ startDate,
+ endDate,
elasticAgentId,
logger,
}: {
@@ -56,6 +67,8 @@ const getActivityLog = async ({
elasticAgentId: string;
size: number;
from: number;
+ startDate?: string;
+ endDate?: string;
logger: Logger;
}) => {
const options = {
@@ -67,8 +80,22 @@ const getActivityLog = async ({
let actionsResult;
let responsesResult;
+ const dateFilters = [];
+ if (startDate) {
+ dateFilters.push({ range: { '@timestamp': { gte: startDate } } });
+ }
+ if (endDate) {
+ dateFilters.push({ range: { '@timestamp': { lte: endDate } } });
+ }
try {
+ // fetch actions with matching agent_id
+ const baseActionFilters = [
+ { term: { agents: elasticAgentId } },
+ { term: { input_type: 'endpoint' } },
+ { term: { type: 'INPUT_ACTION' } },
+ ];
+ const actionsFilters = [...baseActionFilters, ...dateFilters];
actionsResult = await esClient.search(
{
index: AGENT_ACTIONS_INDEX,
@@ -77,11 +104,8 @@ const getActivityLog = async ({
body: {
query: {
bool: {
- filter: [
- { term: { agents: elasticAgentId } },
- { term: { input_type: 'endpoint' } },
- { term: { type: 'INPUT_ACTION' } },
- ],
+ // @ts-ignore
+ filter: actionsFilters,
},
},
sort: [
@@ -99,6 +123,12 @@ const getActivityLog = async ({
(e) => (e._source as EndpointAction).action_id
);
+ // fetch responses with matching `action_id`s
+ const baseResponsesFilter = [
+ { term: { agent_id: elasticAgentId } },
+ { terms: { action_id: actionIds } },
+ ];
+ const responsesFilters = [...baseResponsesFilter, ...dateFilters];
responsesResult = await esClient.search(
{
index: AGENT_ACTIONS_RESULTS_INDEX,
@@ -106,7 +136,7 @@ const getActivityLog = async ({
body: {
query: {
bool: {
- filter: [{ term: { agent_id: elasticAgentId } }, { terms: { action_id: actionIds } }],
+ filter: responsesFilters,
},
},
},
diff --git a/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts b/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts
index 0ca1983aa68d5..1a5515d8122f1 100644
--- a/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/services/metadata.ts
@@ -10,20 +10,15 @@ import { SearchResponse } from 'elasticsearch';
import { HostMetadata } from '../../../common/endpoint/types';
import { SecuritySolutionRequestHandlerContext } from '../../types';
import { getESQueryHostMetadataByIDs } from '../routes/metadata/query_builders';
-import { EndpointAppContext } from '../types';
+import { queryResponseToHostListResult } from '../routes/metadata/support/query_strategies';
export async function getMetadataForEndpoints(
endpointIDs: string[],
- requestHandlerContext: SecuritySolutionRequestHandlerContext,
- endpointAppContext: EndpointAppContext
+ requestHandlerContext: SecuritySolutionRequestHandlerContext
): Promise {
- const queryStrategy = await endpointAppContext.service
- ?.getMetadataService()
- ?.queryStrategy(requestHandlerContext.core.savedObjects.client);
-
- const query = getESQueryHostMetadataByIDs(endpointIDs, queryStrategy!);
+ const query = getESQueryHostMetadataByIDs(endpointIDs);
const esClient = requestHandlerContext.core.elasticsearch.client.asCurrentUser;
const { body } = await esClient.search(query as SearchRequest);
- const hosts = queryStrategy!.queryResponseToHostListResult(body as SearchResponse);
+ const hosts = queryResponseToHostListResult(body as SearchResponse);
return hosts.resultList;
}
diff --git a/x-pack/plugins/security_solution/server/endpoint/types.ts b/x-pack/plugins/security_solution/server/endpoint/types.ts
index 6076aa9af635b..bc52b759b9f0a 100644
--- a/x-pack/plugins/security_solution/server/endpoint/types.ts
+++ b/x-pack/plugins/security_solution/server/endpoint/types.ts
@@ -7,11 +7,9 @@
import { LoggerFactory } from 'kibana/server';
-import { SearchResponse } from '@elastic/elasticsearch/api/types';
-import { JsonObject } from '@kbn/common-utils';
import { ConfigType } from '../config';
import { EndpointAppContextService } from './endpoint_app_context_services';
-import { HostMetadata, MetadataQueryStrategyVersions } from '../../common/endpoint/types';
+import { HostMetadata } from '../../common/endpoint/types';
import { ExperimentalFeatures } from '../../common/experimental_features';
/**
@@ -31,20 +29,9 @@ export interface EndpointAppContext {
export interface HostListQueryResult {
resultLength: number;
resultList: HostMetadata[];
- queryStrategyVersion: MetadataQueryStrategyVersions;
}
export interface HostQueryResult {
resultLength: number;
result: HostMetadata | undefined;
- queryStrategyVersion: MetadataQueryStrategyVersions;
-}
-
-export interface MetadataQueryStrategy {
- index: string;
- extraBodyProperties?: JsonObject;
- queryResponseToHostListResult: (
- searchResponse: SearchResponse
- ) => HostListQueryResult;
- queryResponseToHostResult: (searchResponse: SearchResponse) => HostQueryResult;
}
diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
index f4d942f733c1d..9b9f49a167397 100644
--- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
+++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts
@@ -199,10 +199,10 @@ export const getHostEndpoint = async (
};
const endpointData =
id != null && metadataRequestContext.endpointAppContextService.getAgentService() != null
- ? await getHostMetaData(metadataRequestContext, id, undefined)
+ ? await getHostMetaData(metadataRequestContext, id)
: null;
- const fleetAgentId = endpointData?.metadata.elastic.agent.id;
+ const fleetAgentId = endpointData?.elastic.agent.id;
const [fleetAgentStatus, pendingActions] = !fleetAgentId
? [undefined, {}]
: await Promise.all([
@@ -214,13 +214,13 @@ export const getHostEndpoint = async (
}),
]);
- return endpointData != null && endpointData.metadata
+ return endpointData != null && endpointData
? {
- endpointPolicy: endpointData.metadata.Endpoint.policy.applied.name,
- policyStatus: endpointData.metadata.Endpoint.policy.applied.status,
- sensorVersion: endpointData.metadata.agent.version,
+ endpointPolicy: endpointData.Endpoint.policy.applied.name,
+ policyStatus: endpointData.Endpoint.policy.applied.status,
+ sensorVersion: endpointData.agent.version,
elasticAgentStatus: fleetAgentStatusToEndpointHostStatus(fleetAgentStatus!),
- isolation: endpointData.metadata.Endpoint.state?.isolation ?? false,
+ isolation: endpointData.Endpoint.state?.isolation ?? false,
pendingActions,
}
: null;
diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts
index 1e26ea09618d5..37e0a293b03a0 100644
--- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts
+++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/es_query_builder.ts
@@ -151,7 +151,14 @@ export async function executeEsQueryFactory(
},
},
],
- docvalue_fields: [entity, dateField, geoField],
+ docvalue_fields: [
+ entity,
+ {
+ field: dateField,
+ format: 'strict_date_optional_time',
+ },
+ geoField,
+ ],
_source: false,
},
},
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 754af920b009e..21a536dd474ba 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
@@ -103,7 +103,7 @@ export function getActiveEntriesAndGenerateAlerts(
locationsArr.forEach(({ location, shapeLocationId, dateInShape, docId }) => {
const context = {
entityId: entityName,
- entityDateTime: dateInShape ? new Date(dateInShape).toISOString() : null,
+ entityDateTime: dateInShape || null,
entityDocumentId: docId,
detectionDateTime: new Date(currIntervalEndTime).toISOString(),
entityLocation: `POINT (${location[0]} ${location[1]})`,
diff --git a/x-pack/plugins/timelines/.i18nrc.json b/x-pack/plugins/timelines/.i18nrc.json
deleted file mode 100644
index 4fe01ccc7bc69..0000000000000
--- a/x-pack/plugins/timelines/.i18nrc.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "prefix": "timelines",
- "paths": {
- "timelines": "."
- },
- "translations": ["translations/ja-JP.json"]
-}
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index 11770d2d2f386..2b1088d8c11ae 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -8105,7 +8105,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.groupSourcesUpdated": "共有コンテンツソースが正常に更新されました。",
"xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.groupTableHeader": "グループ",
"xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.sourcesTableHeader": "コンテンツソース",
- "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader": "ユーザー",
"xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText": "前回更新日時{updatedAt}。",
"xpack.enterpriseSearch.workplaceSearch.groups.heading": "グループを管理",
"xpack.enterpriseSearch.workplaceSearch.groups.inviteUsers.action": "ユーザーを招待",
@@ -8118,7 +8117,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "グループはWorkplace Searchから削除されます。{name}を削除してよろしいですか?",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "確認",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription": "コンテンツソースはこのグループと共有されていません。",
- "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptyUsersDescription": "このグループにはユーザーがありません。",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesDescription": "「{name}」グループのすべてのユーザーによって検索可能です。",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesTitle": "グループコンテンツソース",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription": "メンバーはグループのソースを検索できます。",
@@ -13641,7 +13639,6 @@
"xpack.ml.annotationsTable.byColumnSMVName": "グループ基準",
"xpack.ml.annotationsTable.detectorColumnName": "検知器",
"xpack.ml.annotationsTable.editAnnotationsTooltip": "注釈を編集します",
- "xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel": "注釈を編集します",
"xpack.ml.annotationsTable.eventColumnName": "イベント",
"xpack.ml.annotationsTable.fromColumnName": "開始:",
"xpack.ml.annotationsTable.howToCreateAnnotationDescription": "注釈を作成するには、{linkToSingleMetricView} を開きます",
@@ -18565,16 +18562,13 @@
"xpack.securitySolution.administration.os.linux": "Linux",
"xpack.securitySolution.administration.os.macos": "Mac",
"xpack.securitySolution.administration.os.windows": "Windows",
- "xpack.securitySolution.alertDetails.alertSummary": "アラート概要",
"xpack.securitySolution.alertDetails.checkDocs": "マニュアルをご確認ください。",
"xpack.securitySolution.alertDetails.ifCtiNotEnabled": "脅威インテリジェンスソースを有効にしていない場合で、この機能について関心がある場合は、",
- "xpack.securitySolution.alertDetails.noEnrichmentFound": "Threat Intel Enrichmentが見つかりません",
"xpack.securitySolution.alertDetails.summary": "まとめ",
"xpack.securitySolution.alertDetails.summary.investigationGuide": "調査ガイド",
"xpack.securitySolution.alertDetails.summary.readLess": "表示を減らす",
"xpack.securitySolution.alertDetails.summary.readMore": "続きを読む",
"xpack.securitySolution.alertDetails.threatIntel": "Threat Intel",
- "xpack.securitySolution.alertDetails.threatSummary": "脅威概要",
"xpack.securitySolution.alerts.riskScoreMapping.defaultDescriptionLabel": "このルールで生成されたすべてのアラートのリスクスコアを選択します。",
"xpack.securitySolution.alerts.riskScoreMapping.defaultRiskScoreTitle": "デフォルトリスクスコア",
"xpack.securitySolution.alerts.riskScoreMapping.mappingDescriptionLabel": "ソースイベント値を使用して、デフォルトリスクスコアを上書きします。",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index 9704070feb8ab..04394a1ac1704 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -8173,7 +8173,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.groupSourcesUpdated": "已成功更新共享内容源。",
"xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.groupTableHeader": "组",
"xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.sourcesTableHeader": "内容源",
- "xpack.enterpriseSearch.workplaceSearch.groups.groupsTable.usersTableHeader": "用户",
"xpack.enterpriseSearch.workplaceSearch.groups.groupUpdatedText": "上次更新于 {updatedAt}。",
"xpack.enterpriseSearch.workplaceSearch.groups.heading": "管理组",
"xpack.enterpriseSearch.workplaceSearch.groups.inviteUsers.action": "邀请用户",
@@ -8186,7 +8185,6 @@
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmRemoveDescription": "您的组将从 Workplace Search 中删除。确定要移除 {name}?",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.confirmTitleText": "确认",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.emptySourcesDescription": "未与此组共享任何内容源。",
- "xpack.enterpriseSearch.workplaceSearch.groups.overview.emptyUsersDescription": "此组中没有用户。",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesDescription": "可按“{name}”组中的所有用户搜索。",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupSourcesTitle": "组内容源",
"xpack.enterpriseSearch.workplaceSearch.groups.overview.groupUsersDescription": "成员将可以对该组的源进行搜索。",
@@ -13820,7 +13818,6 @@
"xpack.ml.annotationsTable.byColumnSMVName": "依据",
"xpack.ml.annotationsTable.detectorColumnName": "检测工具",
"xpack.ml.annotationsTable.editAnnotationsTooltip": "编辑注释",
- "xpack.ml.annotationsTable.editAnnotationsTooltipAriaLabel": "编辑注释",
"xpack.ml.annotationsTable.eventColumnName": "事件",
"xpack.ml.annotationsTable.fromColumnName": "自",
"xpack.ml.annotationsTable.howToCreateAnnotationDescription": "要创建注释,请打开 {linkToSingleMetricView}",
@@ -18829,16 +18826,13 @@
"xpack.securitySolution.administration.os.linux": "Linux",
"xpack.securitySolution.administration.os.macos": "Mac",
"xpack.securitySolution.administration.os.windows": "Windows",
- "xpack.securitySolution.alertDetails.alertSummary": "告警摘要",
"xpack.securitySolution.alertDetails.checkDocs": "请查看我们的文档。",
"xpack.securitySolution.alertDetails.ifCtiNotEnabled": "如果尚未启用任何威胁情报来源,并希望更多了解此功能,",
- "xpack.securitySolution.alertDetails.noEnrichmentFound": "未找到威胁情报扩充",
"xpack.securitySolution.alertDetails.summary": "摘要",
"xpack.securitySolution.alertDetails.summary.investigationGuide": "调查指南",
"xpack.securitySolution.alertDetails.summary.readLess": "阅读更少内容",
"xpack.securitySolution.alertDetails.summary.readMore": "阅读更多内容",
"xpack.securitySolution.alertDetails.threatIntel": "威胁情报",
- "xpack.securitySolution.alertDetails.threatSummary": "威胁摘要",
"xpack.securitySolution.alerts.riskScoreMapping.defaultDescriptionLabel": "选择此规则生成的所有告警的风险分数。",
"xpack.securitySolution.alerts.riskScoreMapping.defaultRiskScoreTitle": "默认风险分数",
"xpack.securitySolution.alerts.riskScoreMapping.mappingDescriptionLabel": "使用源事件值覆盖默认风险分数。",
diff --git a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx
index 5d526e74564c5..56f333396908b 100644
--- a/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx
+++ b/x-pack/plugins/triggers_actions_ui/public/application/components/builtin_action_types/es_index/es_index_params.tsx
@@ -43,6 +43,7 @@ export const IndexParamsFields = ({
ALERT_HISTORY_PREFIX,
''
);
+ const [isActionConnectorChanged, setIsActionConnectorChanged] = useState(false);
const getDocumentToIndex = (doc: Array> | undefined) =>
doc && doc.length > 0 ? ((doc[0] as unknown) as string) : undefined;
@@ -67,11 +68,12 @@ export const IndexParamsFields = ({
setUsePreconfiguredSchema(true);
editAction('documents', [JSON.stringify(AlertHistoryDocumentTemplate)], index);
setDocumentToIndex(JSON.stringify(AlertHistoryDocumentTemplate));
- } else {
+ } else if (isActionConnectorChanged) {
setUsePreconfiguredSchema(false);
editAction('documents', undefined, index);
setDocumentToIndex(undefined);
}
+ setIsActionConnectorChanged(true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [actionConnector?.id]);
diff --git a/x-pack/test/accessibility/apps/reporting.ts b/x-pack/test/accessibility/apps/reporting.ts
new file mode 100644
index 0000000000000..bccb650fa08ca
--- /dev/null
+++ b/x-pack/test/accessibility/apps/reporting.ts
@@ -0,0 +1,76 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../ftr_provider_context';
+
+import { JOB_PARAMS_RISON_CSV_DEPRECATED } from '../../reporting_api_integration/services/fixtures';
+
+export default function ({ getService, getPageObjects }: FtrProviderContext) {
+ const { common } = getPageObjects(['common']);
+ const retry = getService('retry');
+ const a11y = getService('a11y');
+ const testSubjects = getService('testSubjects');
+ const supertestWithoutAuth = getService('supertestWithoutAuth');
+ const reporting = getService('reporting');
+ const esArchiver = getService('esArchiver');
+ const security = getService('security');
+
+ describe('Reporting', () => {
+ const createReportingUser = async () => {
+ await security.user.create(reporting.REPORTING_USER_USERNAME, {
+ password: reporting.REPORTING_USER_PASSWORD,
+ roles: ['reporting_user', 'data_analyst', 'kibana_user'], // Deprecated: using built-in `reporting_user` role grants all Reporting privileges
+ full_name: 'a reporting user',
+ });
+ };
+
+ const deleteReportingUser = async () => {
+ await security.user.delete(reporting.REPORTING_USER_USERNAME);
+ };
+
+ before(async () => {
+ await esArchiver.load('x-pack/test/functional/es_archives/reporting/logs');
+ await esArchiver.load('x-pack/test/functional/es_archives/logstash_functional');
+
+ await createReportingUser();
+ await reporting.loginReportingUser();
+ });
+
+ after(async () => {
+ await esArchiver.unload('x-pack/test/functional/es_archives/reporting/logs');
+ await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional');
+
+ await deleteReportingUser();
+ });
+
+ beforeEach(async () => {
+ // Add one report
+ await supertestWithoutAuth
+ .post(`/api/reporting/generate/csv`)
+ .auth(reporting.REPORTING_USER_USERNAME, reporting.REPORTING_USER_PASSWORD)
+ .set('kbn-xsrf', 'xxx')
+ .send({ jobParams: JOB_PARAMS_RISON_CSV_DEPRECATED })
+ .expect(200);
+
+ await retry.waitFor('Reporting app', async () => {
+ await common.navigateToApp('reporting');
+ return testSubjects.exists('reportingPageHeader');
+ });
+ });
+
+ afterEach(async () => {
+ await reporting.deleteAllReports();
+ });
+
+ it('List reports view', async () => {
+ await retry.waitForWithTimeout('A reporting list item', 5000, () => {
+ return testSubjects.exists('reportingListItemObjectTitle');
+ });
+ await a11y.testAppSnapshot();
+ });
+ });
+}
diff --git a/x-pack/test/accessibility/config.ts b/x-pack/test/accessibility/config.ts
index 81cfd70a23956..e79bbdb86a88a 100644
--- a/x-pack/test/accessibility/config.ts
+++ b/x-pack/test/accessibility/config.ts
@@ -37,6 +37,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
require.resolve('./apps/security_solution'),
require.resolve('./apps/ml_embeddables_in_dashboard'),
require.resolve('./apps/remote_clusters'),
+ require.resolve('./apps/reporting'),
],
pageObjects,
diff --git a/x-pack/test/api_integration/apis/ml/index.ts b/x-pack/test/api_integration/apis/ml/index.ts
index 7154debc3e195..394672ac07fc5 100644
--- a/x-pack/test/api_integration/apis/ml/index.ts
+++ b/x-pack/test/api_integration/apis/ml/index.ts
@@ -82,5 +82,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./results'));
loadTestFile(require.resolve('./saved_objects'));
loadTestFile(require.resolve('./system'));
+ loadTestFile(require.resolve('./trained_models'));
});
}
diff --git a/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts b/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts
new file mode 100644
index 0000000000000..3848330a95fb9
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/trained_models/delete_model.ts
@@ -0,0 +1,67 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { USER } from '../../../../functional/services/ml/security_common';
+import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
+
+export default ({ getService }: FtrProviderContext) => {
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ describe('DELETE trained_models', () => {
+ before(async () => {
+ await ml.testResources.setKibanaTimeZoneToUTC();
+ await ml.api.createdTestTrainedModels('regression', 2);
+ });
+
+ after(async () => {
+ await ml.api.cleanMlIndices();
+ });
+
+ it('deletes trained model by id', async () => {
+ const { body: deleteResponseBody } = await supertest
+ .delete(`/api/ml/trained_models/dfa_regression_model_n_0`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+
+ expect(deleteResponseBody).to.eql({ acknowledged: true });
+
+ // verify that model is actually deleted
+ await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_0`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(404);
+ });
+
+ it('returns 404 if requested trained model does not exist', async () => {
+ await supertest
+ .delete(`/api/ml/trained_models/not_existing_model`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(404);
+ });
+
+ it('does not allow to delete trained model if the user does not have required permissions', async () => {
+ await supertest
+ .delete(`/api/ml/trained_models/dfa_regression_model_n_1`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(403);
+
+ // verify that model has not been deleted
+ await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_1`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts
new file mode 100644
index 0000000000000..cc347056f02a3
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/trained_models/get_model_pipelines.ts
@@ -0,0 +1,51 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { USER } from '../../../../functional/services/ml/security_common';
+import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
+
+export default ({ getService }: FtrProviderContext) => {
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ describe('GET trained_models/pipelines', () => {
+ let testModelIds: string[] = [];
+
+ before(async () => {
+ await ml.testResources.setKibanaTimeZoneToUTC();
+ testModelIds = await ml.api.createdTestTrainedModels('regression', 2, true);
+ });
+
+ after(async () => {
+ // delete all created ingest pipelines
+ await Promise.all(testModelIds.map((modelId) => ml.api.deleteIngestPipeline(modelId)));
+ await ml.api.cleanMlIndices();
+ });
+
+ it('returns trained model pipelines by id', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_0/pipelines`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+
+ expect(body.length).to.eql(1);
+ expect(body[0].model_id).to.eql('dfa_regression_model_n_0');
+ expect(Object.keys(body[0].pipelines).length).to.eql(1);
+ });
+
+ it('returns an error in case user does not have required permission', async () => {
+ await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_0/pipelines`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(403);
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts
new file mode 100644
index 0000000000000..76f108836996f
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/trained_models/get_model_stats.ts
@@ -0,0 +1,54 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { USER } from '../../../../functional/services/ml/security_common';
+import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
+
+export default ({ getService }: FtrProviderContext) => {
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ describe('GET trained_models/_stats', () => {
+ before(async () => {
+ await ml.testResources.setKibanaTimeZoneToUTC();
+ await ml.api.createdTestTrainedModels('regression', 2);
+ });
+
+ after(async () => {
+ await ml.api.cleanMlIndices();
+ });
+
+ it('returns trained model stats by id', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_0/_stats`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+
+ expect(body.count).to.eql(1);
+ expect(body.trained_model_stats[0].model_id).to.eql('dfa_regression_model_n_0');
+ });
+
+ it('returns 404 if requested trained model does not exist', async () => {
+ await supertest
+ .get(`/api/ml/trained_models/not_existing_model/_stats`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(404);
+ });
+
+ it('returns an error for unauthorized user', async () => {
+ await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_0/_stats`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(403);
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts
new file mode 100644
index 0000000000000..604dff6a98a9a
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts
@@ -0,0 +1,88 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import expect from '@kbn/expect';
+import { FtrProviderContext } from '../../../ftr_provider_context';
+import { USER } from '../../../../functional/services/ml/security_common';
+import { COMMON_REQUEST_HEADERS } from '../../../../functional/services/ml/common_api';
+
+export default ({ getService }: FtrProviderContext) => {
+ const supertest = getService('supertestWithoutAuth');
+ const ml = getService('ml');
+
+ describe('GET trained_models', () => {
+ let testModelIds: string[] = [];
+
+ before(async () => {
+ await ml.testResources.setKibanaTimeZoneToUTC();
+ testModelIds = await ml.api.createdTestTrainedModels('regression', 5, true);
+ await ml.api.createModelAlias('dfa_regression_model_n_0', 'dfa_regression_model_alias');
+ await ml.api.createIngestPipeline('dfa_regression_model_alias');
+ });
+
+ after(async () => {
+ // delete created ingest pipelines
+ await Promise.all(
+ ['dfa_regression_model_alias', ...testModelIds].map((modelId) =>
+ ml.api.deleteIngestPipeline(modelId)
+ )
+ );
+ await ml.api.cleanMlIndices();
+ });
+
+ it('returns all trained models with associated pipelines including aliases', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/trained_models?with_pipelines=true`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+ // Created models + system model
+ expect(body.length).to.eql(6);
+
+ const sampleModel = body.find((v: any) => v.model_id === 'dfa_regression_model_n_0');
+ expect(Object.keys(sampleModel.pipelines).length).to.eql(2);
+ });
+
+ it('returns models without pipeline in case user does not have required permission', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/trained_models?with_pipelines=true`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+ // Created models + system model
+ expect(body.length).to.eql(6);
+ const sampleModel = body.find((v: any) => v.model_id === 'dfa_regression_model_n_0');
+ expect(sampleModel.pipelines).to.eql(undefined);
+ });
+
+ it('returns trained model by id', async () => {
+ const { body } = await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_1`)
+ .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(200);
+ expect(body.length).to.eql(1);
+ expect(body[0].model_id).to.eql('dfa_regression_model_n_1');
+ });
+
+ it('returns 404 if requested trained model does not exist', async () => {
+ await supertest
+ .get(`/api/ml/trained_models/not_existing_model`)
+ .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(404);
+ });
+
+ it('returns an error for unauthorized user', async () => {
+ await supertest
+ .get(`/api/ml/trained_models/dfa_regression_model_n_1`)
+ .auth(USER.ML_UNAUTHORIZED, ml.securityCommon.getPasswordForUser(USER.ML_UNAUTHORIZED))
+ .set(COMMON_REQUEST_HEADERS)
+ .expect(403);
+ });
+ });
+};
diff --git a/x-pack/test/api_integration/apis/ml/trained_models/index.ts b/x-pack/test/api_integration/apis/ml/trained_models/index.ts
new file mode 100644
index 0000000000000..d1812dc188b00
--- /dev/null
+++ b/x-pack/test/api_integration/apis/ml/trained_models/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { FtrProviderContext } from '../../../ftr_provider_context';
+
+export default function ({ loadTestFile }: FtrProviderContext) {
+ describe('trained models', function () {
+ loadTestFile(require.resolve('./get_models'));
+ loadTestFile(require.resolve('./get_model_stats'));
+ loadTestFile(require.resolve('./get_model_pipelines'));
+ loadTestFile(require.resolve('./delete_model'));
+ });
+}
diff --git a/x-pack/test/functional/apps/lens/formula.ts b/x-pack/test/functional/apps/lens/formula.ts
index 8b87db21a1ffe..6148215d8b6d2 100644
--- a/x-pack/test/functional/apps/lens/formula.ts
+++ b/x-pack/test/functional/apps/lens/formula.ts
@@ -16,7 +16,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const fieldEditor = getService('fieldEditor');
- describe('lens formula', () => {
+ // FLAKY: https://github.com/elastic/kibana/issues/105016
+ describe.skip('lens formula', () => {
it('should transition from count to formula', async () => {
await PageObjects.visualize.gotoVisualizationLandingPage();
await listingTable.searchForItemWithName('lnsXYvis');
diff --git a/x-pack/test/functional/services/index.ts b/x-pack/test/functional/services/index.ts
index 99293c71676b4..273db212400ab 100644
--- a/x-pack/test/functional/services/index.ts
+++ b/x-pack/test/functional/services/index.ts
@@ -9,6 +9,7 @@ import { services as kibanaFunctionalServices } from '../../../../test/functiona
import { services as kibanaApiIntegrationServices } from '../../../../test/api_integration/services';
import { services as kibanaXPackApiIntegrationServices } from '../../api_integration/services';
import { services as commonServices } from '../../common/services';
+import { ReportingFunctionalProvider } from '../../reporting_functional/services';
import {
MonitoringNoDataProvider,
@@ -107,5 +108,6 @@ export const services = {
dashboardDrilldownPanelActions: DashboardDrilldownPanelActionsProvider,
dashboardDrilldownsManage: DashboardDrilldownsManageProvider,
dashboardPanelTimeRange: DashboardPanelTimeRangeProvider,
+ reporting: ReportingFunctionalProvider,
searchSessions: SearchSessionsService,
};
diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts
index 728e3ff8fc8e6..ec5ca4c661157 100644
--- a/x-pack/test/functional/services/ml/api.ts
+++ b/x-pack/test/functional/services/ml/api.ts
@@ -8,6 +8,8 @@
import { estypes } from '@elastic/elasticsearch';
import expect from '@kbn/expect';
import { ProvidedType } from '@kbn/test';
+import fs from 'fs';
+import path from 'path';
import { Calendar } from '../../../../plugins/ml/server/models/calendar/index';
import { Annotation } from '../../../../plugins/ml/common/types/annotations';
import { DataFrameAnalyticsConfig } from '../../../../plugins/ml/public/application/data_frame_analytics/common';
@@ -25,6 +27,8 @@ import {
import { COMMON_REQUEST_HEADERS } from '../../../functional/services/ml/common_api';
import { PutTrainedModelConfig } from '../../../../plugins/ml/common/types/trained_models';
+type ModelType = 'regression' | 'classification';
+
export function MachineLearningAPIProvider({ getService }: FtrProviderContext) {
const es = getService('es');
const log = getService('log');
@@ -943,5 +947,93 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) {
log.debug('> Trained model crated');
return model;
},
+
+ async createdTestTrainedModels(
+ modelType: ModelType,
+ count: number = 10,
+ withIngestPipelines = false
+ ) {
+ const compressedDefinition = this.getCompressedModelDefinition(modelType);
+
+ const modelIds = new Array(count).fill(null).map((v, i) => `dfa_${modelType}_model_n_${i}`);
+
+ const models = modelIds.map((id) => {
+ return {
+ model_id: id,
+ body: {
+ compressed_definition: compressedDefinition,
+ inference_config: {
+ [modelType]: {},
+ },
+ input: {
+ field_names: ['common_field'],
+ },
+ } as PutTrainedModelConfig,
+ };
+ });
+
+ for (const model of models) {
+ await this.createTrainedModel(model.model_id, model.body);
+ if (withIngestPipelines) {
+ await this.createIngestPipeline(model.model_id);
+ }
+ }
+
+ return modelIds;
+ },
+
+ /**
+ * Retrieves compressed model definition from the test resources.
+ * @param modelType
+ */
+ getCompressedModelDefinition(modelType: ModelType) {
+ return fs.readFileSync(
+ path.resolve(
+ __dirname,
+ 'resources',
+ 'trained_model_definitions',
+ `minimum_valid_config_${modelType}.json.gz.b64`
+ ),
+ 'utf-8'
+ );
+ },
+
+ async createModelAlias(modelId: string, modelAlias: string) {
+ log.debug(`Creating alias for model "${modelId}"`);
+ await esSupertest
+ .put(`/_ml/trained_models/${modelId}/model_aliases/${modelAlias}`)
+ .expect(200);
+ log.debug('> Model alias created');
+ },
+
+ /**
+ * Creates ingest pipelines for trained model
+ * @param modelId
+ */
+ async createIngestPipeline(modelId: string) {
+ log.debug(`Creating ingest pipeline for trained model with id "${modelId}"`);
+ const ingestPipeline = await esSupertest
+ .put(`/_ingest/pipeline/pipeline_${modelId}`)
+ .send({
+ processors: [
+ {
+ inference: {
+ model_id: modelId,
+ },
+ },
+ ],
+ })
+ .expect(200)
+ .then((res) => res.body);
+
+ log.debug('> Ingest pipeline crated');
+ return ingestPipeline;
+ },
+
+ async deleteIngestPipeline(modelId: string) {
+ log.debug(`Deleting ingest pipeline for trained model with id "${modelId}"`);
+ await esSupertest.delete(`/_ingest/pipeline/pipeline_${modelId}`).expect(200);
+ log.debug('> Ingest pipeline deleted');
+ },
};
}
diff --git a/x-pack/test/functional/services/ml/trained_models.ts b/x-pack/test/functional/services/ml/trained_models.ts
index ae799efbbd30c..7a1fa1714ca14 100644
--- a/x-pack/test/functional/services/ml/trained_models.ts
+++ b/x-pack/test/functional/services/ml/trained_models.ts
@@ -5,12 +5,9 @@
* 2.0.
*/
-import fs from 'fs';
-import path from 'path';
import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';
import { MlApi } from './api';
-import { PutTrainedModelConfig } from '../../../../plugins/ml/common/types/trained_models';
import { MlCommonUI } from './common_ui';
type ModelType = 'regression' | 'classification';
@@ -24,38 +21,7 @@ export function TrainedModelsProvider(
return {
async createdTestTrainedModels(modelType: ModelType, count: number = 10) {
- const compressedDefinition = this.getCompressedModelDefinition(modelType);
-
- const models = new Array(count).fill(null).map((v, i) => {
- return {
- model_id: `dfa_${modelType}_model_n_${i}`,
- body: {
- compressed_definition: compressedDefinition,
- inference_config: {
- [modelType]: {},
- },
- input: {
- field_names: ['common_field'],
- },
- } as PutTrainedModelConfig,
- };
- });
-
- for (const model of models) {
- await mlApi.createTrainedModel(model.model_id, model.body);
- }
- },
-
- getCompressedModelDefinition(modelType: ModelType) {
- return fs.readFileSync(
- path.resolve(
- __dirname,
- 'resources',
- 'trained_model_definitions',
- `minimum_valid_config_${modelType}.json.gz.b64`
- ),
- 'utf-8'
- );
+ await mlApi.createdTestTrainedModels(modelType, count);
},
async assertStats(expectedTotalCount: number) {
diff --git a/x-pack/test/reporting_api_integration/reporting_without_security/ilm_migration_apis.ts b/x-pack/test/reporting_api_integration/reporting_without_security/ilm_migration_apis.ts
index a0f4a3f91fe32..a9b6798a0224f 100644
--- a/x-pack/test/reporting_api_integration/reporting_without_security/ilm_migration_apis.ts
+++ b/x-pack/test/reporting_api_integration/reporting_without_security/ilm_migration_apis.ts
@@ -47,7 +47,7 @@ export default function ({ getService }: FtrProviderContext) {
});
it('detects when reporting indices should be migrated due to missing ILM policy', async () => {
- await reportingAPI.makeAllReportingPoliciesUnmanaged();
+ await reportingAPI.makeAllReportingIndicesUnmanaged();
// TODO: Remove "any" when no longer through type issue "policy_id" missing
await es.ilm.deleteLifecycle({ policy: ILM_POLICY_NAME } as any);
@@ -63,7 +63,7 @@ export default function ({ getService }: FtrProviderContext) {
});
it('detects when reporting indices should be migrated due to unmanaged indices', async () => {
- await reportingAPI.makeAllReportingPoliciesUnmanaged();
+ await reportingAPI.makeAllReportingIndicesUnmanaged();
await supertestNoAuth
.post(`/api/reporting/generate/csv`)
.set('kbn-xsrf', 'xxx')
diff --git a/x-pack/test/reporting_api_integration/services/scenarios.ts b/x-pack/test/reporting_api_integration/services/scenarios.ts
index eb32de9d0dc9c..08c07e0e257ed 100644
--- a/x-pack/test/reporting_api_integration/services/scenarios.ts
+++ b/x-pack/test/reporting_api_integration/services/scenarios.ts
@@ -181,8 +181,8 @@ export function createScenarios({ getService }: Pick {
- log.debug('ReportingAPI.makeAllReportingPoliciesUnmanaged');
+ const makeAllReportingIndicesUnmanaged = async () => {
+ log.debug('ReportingAPI.makeAllReportingIndicesUnmanaged');
const settings: any = {
'index.lifecycle.name': null,
};
@@ -214,6 +214,6 @@ export function createScenarios({ getService }: Pick {
@@ -148,7 +145,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(2);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
it('metadata api should return page based on filters and paging passed.', async () => {
@@ -186,7 +182,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(2);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
it('metadata api should return page based on host.os.Ext.variant filter.', async () => {
@@ -208,7 +203,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(2);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
it('metadata api should return the latest event for all the events for an endpoint', async () => {
@@ -231,7 +225,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(1);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
it('metadata api should return the latest event for all the events where policy status is not success', async () => {
@@ -275,7 +268,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(1);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
it('metadata api should return all hosts when filter is empty string', async () => {
@@ -292,7 +284,6 @@ export default function ({ getService }: FtrProviderContext) {
expect(body.hosts.length).to.eql(numberOfHostsInFixture);
expect(body.request_page_size).to.eql(10);
expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_2);
});
});
});
diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts
deleted file mode 100644
index d8cf1a11fac0a..0000000000000
--- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata_v1.ts
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-import expect from '@kbn/expect';
-import { FtrProviderContext } from '../ftr_provider_context';
-import { deleteMetadataStream } from './data_stream_helper';
-import { METADATA_REQUEST_V1_ROUTE } from '../../../plugins/security_solution/server/endpoint/routes/metadata';
-import { MetadataQueryStrategyVersions } from '../../../plugins/security_solution/common/endpoint/types';
-
-/**
- * The number of host documents in the es archive.
- */
-const numberOfHostsInFixture = 3;
-
-export default function ({ getService }: FtrProviderContext) {
- const esArchiver = getService('esArchiver');
- const supertest = getService('supertest');
- describe('test metadata api v1', () => {
- describe(`POST ${METADATA_REQUEST_V1_ROUTE} when index is empty`, () => {
- it('metadata api should return empty result when index is empty', async () => {
- // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need
- // to do it manually
- await deleteMetadataStream(getService);
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send()
- .expect(200);
- expect(body.total).to.eql(0);
- expect(body.hosts.length).to.eql(0);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
- });
-
- describe(`POST ${METADATA_REQUEST_V1_ROUTE} when index is not empty`, () => {
- before(
- async () =>
- await esArchiver.load(
- 'x-pack/test/functional/es_archives/endpoint/metadata/api_feature',
- { useCreate: true }
- )
- );
- // the endpoint uses data streams and es archiver does not support deleting them at the moment so we need
- // to do it manually
- after(async () => await deleteMetadataStream(getService));
- it('metadata api should return one entry for each host with default paging', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send()
- .expect(200);
- expect(body.total).to.eql(numberOfHostsInFixture);
- expect(body.hosts.length).to.eql(numberOfHostsInFixture);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return page based on paging properties passed.', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- paging_properties: [
- {
- page_size: 1,
- },
- {
- page_index: 1,
- },
- ],
- })
- .expect(200);
- expect(body.total).to.eql(numberOfHostsInFixture);
- expect(body.hosts.length).to.eql(1);
- expect(body.request_page_size).to.eql(1);
- expect(body.request_page_index).to.eql(1);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- /* test that when paging properties produces no result, the total should reflect the actual number of metadata
- in the index.
- */
- it('metadata api should return accurate total metadata if page index produces no result', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- paging_properties: [
- {
- page_size: 10,
- },
- {
- page_index: 3,
- },
- ],
- })
- .expect(200);
- expect(body.total).to.eql(numberOfHostsInFixture);
- expect(body.hosts.length).to.eql(0);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(30);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return 400 when pagingProperties is below boundaries.', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- paging_properties: [
- {
- page_size: 0,
- },
- {
- page_index: 1,
- },
- ],
- })
- .expect(400);
- expect(body.message).to.contain('Value must be equal to or greater than [1]');
- });
-
- it('metadata api should return page based on filters passed.', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: 'not host.ip:10.46.229.234',
- },
- })
- .expect(200);
- expect(body.total).to.eql(2);
- expect(body.hosts.length).to.eql(2);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return page based on filters and paging passed.', async () => {
- const notIncludedIp = '10.46.229.234';
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- paging_properties: [
- {
- page_size: 10,
- },
- {
- page_index: 0,
- },
- ],
- filters: {
- kql: `not host.ip:${notIncludedIp}`,
- },
- })
- .expect(200);
- expect(body.total).to.eql(2);
- const resultIps: string[] = [].concat(
- ...body.hosts.map((hostInfo: Record) => hostInfo.metadata.host.ip)
- );
- expect(resultIps).to.eql([
- '10.192.213.130',
- '10.70.28.129',
- '10.101.149.26',
- '2606:a000:ffc0:39:11ef:37b9:3371:578c',
- ]);
- expect(resultIps).not.include.eql(notIncludedIp);
- expect(body.hosts.length).to.eql(2);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return page based on host.os.Ext.variant filter.', async () => {
- const variantValue = 'Windows Pro';
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: `host.os.Ext.variant:${variantValue}`,
- },
- })
- .expect(200);
- expect(body.total).to.eql(2);
- const resultOsVariantValue: Set = new Set(
- body.hosts.map((hostInfo: Record) => hostInfo.metadata.host.os.Ext.variant)
- );
- expect(Array.from(resultOsVariantValue)).to.eql([variantValue]);
- expect(body.hosts.length).to.eql(2);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return the latest event for all the events for an endpoint', async () => {
- const targetEndpointIp = '10.46.229.234';
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: `host.ip:${targetEndpointIp}`,
- },
- })
- .expect(200);
- expect(body.total).to.eql(1);
- const resultIp: string = body.hosts[0].metadata.host.ip.filter(
- (ip: string) => ip === targetEndpointIp
- );
- expect(resultIp).to.eql([targetEndpointIp]);
- expect(body.hosts[0].metadata.event.created).to.eql(1618841405309);
- expect(body.hosts.length).to.eql(1);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return the latest event for all the events where policy status is not success', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: `not Endpoint.policy.applied.status:success`,
- },
- })
- .expect(200);
- const statuses: Set = new Set(
- body.hosts.map(
- (hostInfo: Record) => hostInfo.metadata.Endpoint.policy.applied.status
- )
- );
- expect(statuses.size).to.eql(1);
- expect(Array.from(statuses)).to.eql(['failure']);
- });
-
- it('metadata api should return the endpoint based on the elastic agent id, and status should be unhealthy', async () => {
- const targetEndpointId = 'fc0ff548-feba-41b6-8367-65e8790d0eaf';
- const targetElasticAgentId = '023fa40c-411d-4188-a941-4147bfadd095';
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: `elastic.agent.id:${targetElasticAgentId}`,
- },
- })
- .expect(200);
- expect(body.total).to.eql(1);
- const resultHostId: string = body.hosts[0].metadata.host.id;
- const resultElasticAgentId: string = body.hosts[0].metadata.elastic.agent.id;
- expect(resultHostId).to.eql(targetEndpointId);
- expect(resultElasticAgentId).to.eql(targetElasticAgentId);
- expect(body.hosts[0].metadata.event.created).to.eql(1618841405309);
- expect(body.hosts[0].host_status).to.eql('unhealthy');
- expect(body.hosts.length).to.eql(1);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
-
- it('metadata api should return all hosts when filter is empty string', async () => {
- const { body } = await supertest
- .post(`${METADATA_REQUEST_V1_ROUTE}`)
- .set('kbn-xsrf', 'xxx')
- .send({
- filters: {
- kql: '',
- },
- })
- .expect(200);
- expect(body.total).to.eql(numberOfHostsInFixture);
- expect(body.hosts.length).to.eql(numberOfHostsInFixture);
- expect(body.request_page_size).to.eql(10);
- expect(body.request_page_index).to.eql(0);
- expect(body.query_strategy_version).to.eql(MetadataQueryStrategyVersions.VERSION_1);
- });
- });
- });
-}
diff --git a/yarn.lock b/yarn.lock
index c64f4e1c4b281..dccbd8f91a429 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -209,6 +209,13 @@
dependencies:
"@babel/types" "^7.12.5"
+"@babel/helper-module-imports@^7.7.0":
+ version "7.13.12"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977"
+ integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==
+ dependencies:
+ "@babel/types" "^7.13.12"
+
"@babel/helper-module-transforms@^7.12.1":
version "7.12.1"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c"
@@ -548,6 +555,13 @@
dependencies:
"@babel/helper-plugin-utils" "^7.10.4"
+"@babel/plugin-syntax-jsx@^7.2.0":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz#044fb81ebad6698fe62c478875575bcbb9b70f15"
+ integrity sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
version "7.10.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
@@ -1154,6 +1168,13 @@
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.13.10":
+ version "7.13.17"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.13.17.tgz#8966d1fc9593bf848602f0662d6b4d0069e3a7ec"
+ integrity sha512-NCdgJEelPTSh+FEFylhnP1ylq848l1z9t9N0j1Lfbcw0+KXGjsTvUmkxy+voLLXB5SOKMbLLx4jxYliGrYQseA==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
"@babel/template@^7.10.4", "@babel/template@^7.12.13", "@babel/template@^7.12.7", "@babel/template@^7.3.3", "@babel/template@^7.4.4":
version "7.12.13"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327"
@@ -1187,6 +1208,15 @@
lodash "^4.17.19"
to-fast-properties "^2.0.0"
+"@babel/types@^7.13.12":
+ version "7.13.14"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.14.tgz#c35a4abb15c7cd45a2746d78ab328e362cbace0d"
+ integrity sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.12.11"
+ lodash "^4.17.19"
+ to-fast-properties "^2.0.0"
+
"@base2/pretty-print-object@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@base2/pretty-print-object/-/pretty-print-object-1.0.0.tgz#860ce718b0b73f4009e153541faff2cb6b85d047"
@@ -1592,6 +1622,41 @@
resolved "https://registry.yarnpkg.com/@elastic/ui-ace/-/ui-ace-0.2.3.tgz#5281aed47a79b7216c55542b0675e435692f20cd"
integrity sha512-Nti5s2dplBPhSKRwJxG9JXTMOev4jVOWcnTJD1TOkJr1MUBYKVZcNcJtIVMSvahWGmP0B/UfO9q9lyRqdivkvQ==
+"@emotion/babel-plugin-jsx-pragmatic@^0.1.5":
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-plugin-jsx-pragmatic/-/babel-plugin-jsx-pragmatic-0.1.5.tgz#27debfe9c27c4d83574d509787ae553bf8a34d7e"
+ integrity sha512-y+3AJ0SItMDaAgGPVkQBC/S/BaqaPACkQ6MyCI2CUlrjTxKttTVfD3TMtcs7vLEcLxqzZ1xiG0vzwCXjhopawQ==
+ dependencies:
+ "@babel/plugin-syntax-jsx" "^7.2.0"
+
+"@emotion/babel-plugin@^11.2.0":
+ version "11.2.0"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.2.0.tgz#f25c6df8ec045dad5ae6ca63df0791673b98c920"
+ integrity sha512-lsnQBnl3l4wu/FJoyHnYRpHJeIPNkOBMbtDUIXcO8luulwRKZXPvA10zd2eXVN6dABIWNX4E34en/jkejIg/yA==
+ dependencies:
+ "@babel/helper-module-imports" "^7.7.0"
+ "@babel/plugin-syntax-jsx" "^7.12.1"
+ "@babel/runtime" "^7.7.2"
+ "@emotion/hash" "^0.8.0"
+ "@emotion/memoize" "^0.7.5"
+ "@emotion/serialize" "^1.0.0"
+ babel-plugin-macros "^2.6.1"
+ convert-source-map "^1.5.0"
+ escape-string-regexp "^4.0.0"
+ find-root "^1.1.0"
+ source-map "^0.5.7"
+ stylis "^4.0.3"
+
+"@emotion/babel-preset-css-prop@^11.2.0":
+ version "11.2.0"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-preset-css-prop/-/babel-preset-css-prop-11.2.0.tgz#c7e945f56b2610b438f0dc8ae5253fc55488de0e"
+ integrity sha512-9XLQm2eLPYTho+Cx1LQTDA1rATjoAaB4O+ds55XDvoAa+Z16Hhg8y5Vihj3C8E6+ilDM8SV5A9Z6z+yj0YIRBg==
+ dependencies:
+ "@babel/plugin-transform-react-jsx" "^7.12.1"
+ "@babel/runtime" "^7.7.2"
+ "@emotion/babel-plugin" "^11.2.0"
+ "@emotion/babel-plugin-jsx-pragmatic" "^0.1.5"
+
"@emotion/babel-utils@^0.6.4":
version "0.6.10"
resolved "https://registry.yarnpkg.com/@emotion/babel-utils/-/babel-utils-0.6.10.tgz#83dbf3dfa933fae9fc566e54fbb45f14674c6ccc"
@@ -1614,6 +1679,17 @@
"@emotion/utils" "0.11.3"
"@emotion/weak-memoize" "0.2.5"
+"@emotion/cache@^11.4.0":
+ version "11.4.0"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.4.0.tgz#293fc9d9a7a38b9aad8e9337e5014366c3b09ac0"
+ integrity sha512-Zx70bjE7LErRO9OaZrhf22Qye1y4F7iDl+ITjet0J+i+B88PrAOBkKvaAWhxsZf72tDLajwCgfCjJ2dvH77C3g==
+ dependencies:
+ "@emotion/memoize" "^0.7.4"
+ "@emotion/sheet" "^1.0.0"
+ "@emotion/utils" "^1.0.0"
+ "@emotion/weak-memoize" "^0.2.5"
+ stylis "^4.0.3"
+
"@emotion/core@^10.0.9", "@emotion/core@^10.1.1":
version "10.1.1"
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3"
@@ -1626,6 +1702,14 @@
"@emotion/sheet" "0.9.4"
"@emotion/utils" "0.11.3"
+"@emotion/css-prettifier@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@emotion/css-prettifier/-/css-prettifier-1.0.0.tgz#3ed4240d93c9798c001cedf27dd0aa960bdddd1a"
+ integrity sha512-efxSrRTiTqHTQVKW15Gz5H4pNAw8OqcG8NaiwkJIkqIdNXTD4Qr1zC1Ou6r2acd1oJJ2s56nb1ClnXMiWoj6gQ==
+ dependencies:
+ "@emotion/memoize" "^0.7.4"
+ stylis "^4.0.3"
+
"@emotion/css@^10.0.27", "@emotion/css@^10.0.9":
version "10.0.27"
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
@@ -1635,7 +1719,7 @@
"@emotion/utils" "0.11.3"
babel-plugin-emotion "^10.0.27"
-"@emotion/hash@0.8.0":
+"@emotion/hash@0.8.0", "@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
@@ -1652,6 +1736,17 @@
dependencies:
"@emotion/memoize" "0.7.4"
+"@emotion/jest@^11.3.0":
+ version "11.3.0"
+ resolved "https://registry.yarnpkg.com/@emotion/jest/-/jest-11.3.0.tgz#43bed6dcb47c8691b346cee231861ebc8f9b0016"
+ integrity sha512-LZqYc3yerhic1IvAcEwBLRs1DsUt3oY7Oz6n+e+HU32iYOK/vpfzlhgmQURE94BHfv6eCOj6DV38f3jSnIkBkQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@emotion/css-prettifier" "^1.0.0"
+ chalk "^4.1.0"
+ specificity "^0.4.1"
+ stylis "^4.0.3"
+
"@emotion/memoize@0.7.4":
version "0.7.4"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
@@ -1662,6 +1757,24 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b"
integrity sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ==
+"@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5":
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50"
+ integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==
+
+"@emotion/react@^11.4.0":
+ version "11.4.0"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.4.0.tgz#2465ad7b073a691409b88dfd96dc17097ddad9b7"
+ integrity sha512-4XklWsl9BdtatLoJpSjusXhpKv9YVteYKh9hPKP1Sxl+mswEFoUe0WtmtWjxEjkA51DQ2QRMCNOvKcSlCQ7ivg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@emotion/cache" "^11.4.0"
+ "@emotion/serialize" "^1.0.2"
+ "@emotion/sheet" "^1.0.1"
+ "@emotion/utils" "^1.0.0"
+ "@emotion/weak-memoize" "^0.2.5"
+ hoist-non-react-statics "^3.3.1"
+
"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
version "0.11.16"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
@@ -1683,11 +1796,27 @@
"@emotion/unitless" "^0.6.7"
"@emotion/utils" "^0.8.2"
+"@emotion/serialize@^1.0.0", "@emotion/serialize@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965"
+ integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==
+ dependencies:
+ "@emotion/hash" "^0.8.0"
+ "@emotion/memoize" "^0.7.4"
+ "@emotion/unitless" "^0.7.5"
+ "@emotion/utils" "^1.0.0"
+ csstype "^3.0.2"
+
"@emotion/sheet@0.9.4":
version "0.9.4"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
+"@emotion/sheet@^1.0.0", "@emotion/sheet@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.0.1.tgz#245f54abb02dfd82326e28689f34c27aa9b2a698"
+ integrity sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g==
+
"@emotion/styled-base@^10.0.27":
version "10.0.31"
resolved "https://registry.yarnpkg.com/@emotion/styled-base/-/styled-base-10.0.31.tgz#940957ee0aa15c6974adc7d494ff19765a2f742a"
@@ -1716,7 +1845,7 @@
resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.7.1.tgz#50f63225e712d99e2b2b39c19c70fff023793ca5"
integrity sha512-/SLmSIkN13M//53TtNxgxo57mcJk/UJIDFRKwOiLIBEyBHEcipgR6hNMQ/59Sl4VjCJ0Z/3zeAZyvnSLPG/1HQ==
-"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4":
+"@emotion/unitless@0.7.5", "@emotion/unitless@^0.7.4", "@emotion/unitless@^0.7.5":
version "0.7.5"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
@@ -1736,7 +1865,12 @@
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.8.2.tgz#576ff7fb1230185b619a75d258cbc98f0867a8dc"
integrity sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw==
-"@emotion/weak-memoize@0.2.5":
+"@emotion/utils@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.0.0.tgz#abe06a83160b10570816c913990245813a2fd6af"
+ integrity sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==
+
+"@emotion/weak-memoize@0.2.5", "@emotion/weak-memoize@^0.2.5":
version "0.2.5"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
@@ -7790,7 +7924,7 @@ babel-plugin-jest-hoist@^26.6.2:
"@types/babel__core" "^7.0.0"
"@types/babel__traverse" "^7.0.6"
-babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.8.0:
+babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0:
version "2.8.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
@@ -9487,15 +9621,6 @@ cli-width@^3.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
-clipboard@^2.0.0:
- version "2.0.4"
- resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.4.tgz#836dafd66cf0fea5d71ce5d5b0bf6e958009112d"
- integrity sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==
- dependencies:
- good-listener "^1.2.2"
- select "^1.1.2"
- tiny-emitter "^2.0.0"
-
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@@ -10718,6 +10843,11 @@ csstype@^2.5.2:
resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.14.tgz#004822a4050345b55ad4dcc00be1d9cf2f4296de"
integrity sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==
+csstype@^3.0.2:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b"
+ integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==
+
cucumber-expressions@^5.0.13:
version "5.0.18"
resolved "https://registry.yarnpkg.com/cucumber-expressions/-/cucumber-expressions-5.0.18.tgz#6c70779efd3aebc5e9e7853938b1110322429596"
@@ -11589,11 +11719,6 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-delegate@^3.1.2:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
- integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
-
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -13489,9 +13614,9 @@ fast-redact@^3.0.0:
integrity sha512-a/S/Hp6aoIjx7EmugtzLqXmcNsyFszqbt6qQ99BdG61QjBZF6shNis0BYR6TsZOQ1twYc0FN2Xdhwwbv6+KD0w==
fast-safe-stringify@2.x.x, fast-safe-stringify@^2.0.4, fast-safe-stringify@^2.0.7:
- version "2.0.7"
- resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
- integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f"
+ integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==
fast-shallow-equal@^1.0.0:
version "1.0.0"
@@ -14789,13 +14914,6 @@ gonzales-pe@^4.3.0:
dependencies:
minimist "^1.2.5"
-good-listener@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
- integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
- dependencies:
- delegate "^3.1.2"
-
got@5.6.0:
version "5.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-5.6.0.tgz#bb1d7ee163b78082bbc8eb836f3f395004ea6fbf"
@@ -15410,7 +15528,7 @@ hmac-drbg@^1.0.1:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.1"
-hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.5, hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
+hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.5, hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -22172,8 +22290,6 @@ prismjs@1.24.0, prismjs@^1.22.0, prismjs@~1.23.0:
version "1.24.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.0.tgz#0409c30068a6c52c89ef7f1089b3ca4de56be2ac"
integrity sha512-SqV5GRsNqnzCL8k5dfAjCNhUrF3pR0A9lTDSCUZeh/LIshheXJEaP0hwLz2t4XHivd2J/v2HR+gRnigzeKe3cQ==
- optionalDependencies:
- clipboard "^2.0.0"
private@^0.1.8, private@~0.1.5:
version "0.1.8"
@@ -24791,11 +24907,6 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
-select@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
- integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
-
selenium-webdriver@^4.0.0-alpha.7:
version "4.0.0-alpha.7"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz#e3879d8457fd7ad8e4424094b7dc0540d99e6797"
@@ -26207,6 +26318,11 @@ stylis@^3.5.0:
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.4.tgz#f665f25f5e299cf3d64654ab949a57c768b73fbe"
integrity sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==
+stylis@^4.0.3:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.7.tgz#412a90c28079417f3d27c028035095e4232d2904"
+ integrity sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA==
+
subarg@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2"
@@ -26828,11 +26944,6 @@ timsort@^0.3.0, timsort@~0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
-tiny-emitter@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"
- integrity sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==
-
tiny-inflate@^1.0.0, tiny-inflate@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz#122715494913a1805166aaf7c93467933eea26c4"