From bb6c2ef3d01048eda5f6bca887816b1ec8fb40e1 Mon Sep 17 00:00:00 2001 From: Pete Hampton Date: Mon, 24 May 2021 17:41:19 +0100 Subject: [PATCH 01/22] Add remaining descriptions to security usage telemetry schema. (#100454) --- .../server/usage/collector.ts | 88 +++++++++++++++---- .../schema/xpack_plugins.json | 85 ++++++++++++++---- 2 files changed, 139 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/security_solution/server/usage/collector.ts b/x-pack/plugins/security_solution/server/usage/collector.ts index 51c5c956574e7..3db1e7034c5e4 100644 --- a/x-pack/plugins/security_solution/server/usage/collector.ts +++ b/x-pack/plugins/security_solution/server/usage/collector.ts @@ -46,22 +46,46 @@ export const registerCollector: RegisterCollector = ({ detections: { detection_rules: { custom: { - enabled: { type: 'long' }, - disabled: { type: 'long' }, + enabled: { + type: 'long', + _meta: { description: 'The number of custom detection rules enabled' }, + }, + disabled: { + type: 'long', + _meta: { description: 'The number of custom detection rules disabled' }, + }, }, elastic: { - enabled: { type: 'long' }, - disabled: { type: 'long' }, + enabled: { + type: 'long', + _meta: { description: 'The number of elastic prebuilt detection rules enabled' }, + }, + disabled: { + type: 'long', + _meta: { description: 'The number of elastic prebuilt detection rules disabled' }, + }, }, }, ml_jobs: { custom: { - enabled: { type: 'long' }, - disabled: { type: 'long' }, + enabled: { + type: 'long', + _meta: { description: 'The number of custom ML jobs rules enabled' }, + }, + disabled: { + type: 'long', + _meta: { description: 'The number of custom ML jobs rules disabled' }, + }, }, elastic: { - enabled: { type: 'long' }, - disabled: { type: 'long' }, + enabled: { + type: 'long', + _meta: { description: 'The number of elastic provided ML jobs rules enabled' }, + }, + disabled: { + type: 'long', + _meta: { description: 'The number of elastic provided ML jobs rules disabled' }, + }, }, }, }, @@ -398,22 +422,52 @@ export const registerCollector: RegisterCollector = ({ }, }, endpoints: { - total_installed: { type: 'long' }, - active_within_last_24_hours: { type: 'long' }, + total_installed: { + type: 'long', + _meta: { description: 'The number of installed endpoints' }, + }, + active_within_last_24_hours: { + type: 'long', + _meta: { description: 'The number of active endpoints' }, + }, os: { type: 'array', items: { - full_name: { type: 'keyword' }, - platform: { type: 'keyword' }, - version: { type: 'keyword' }, - count: { type: 'long' }, + full_name: { + type: 'keyword', + _meta: { description: 'Full name of the operating system' }, + }, + platform: { + type: 'keyword', + _meta: { description: 'OS Platform. eg Centos, Ubuntu' }, + }, + version: { + type: 'keyword', + _meta: { + description: + 'The version of the operating system, eg 16.04.7 LTS (Xenial Xerus), 8 (Core)', + }, + }, + count: { + type: 'long', + _meta: { description: 'The total number of endpoints from that platform' }, + }, }, }, policies: { malware: { - active: { type: 'long' }, - inactive: { type: 'long' }, - failure: { type: 'long' }, + active: { + type: 'long', + _meta: { description: 'The total number of active malware policies' }, + }, + inactive: { + type: 'long', + _meta: { description: 'The total number of inactive malware policies' }, + }, + failure: { + type: 'long', + _meta: { description: 'The total number of failing malware policies' }, + }, }, }, }, diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index feb6d66060ebc..b85fd8bf8989e 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -4671,20 +4671,32 @@ "custom": { "properties": { "enabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of custom detection rules enabled" + } }, "disabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of custom detection rules disabled" + } } } }, "elastic": { "properties": { "enabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of elastic prebuilt detection rules enabled" + } }, "disabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of elastic prebuilt detection rules disabled" + } } } } @@ -4695,20 +4707,32 @@ "custom": { "properties": { "enabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of custom ML jobs rules enabled" + } }, "disabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of custom ML jobs rules disabled" + } } } }, "elastic": { "properties": { "enabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of elastic provided ML jobs rules enabled" + } }, "disabled": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of elastic provided ML jobs rules disabled" + } } } } @@ -5195,26 +5219,44 @@ "endpoints": { "properties": { "total_installed": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of installed endpoints" + } }, "active_within_last_24_hours": { - "type": "long" + "type": "long", + "_meta": { + "description": "The number of active endpoints" + } }, "os": { "type": "array", "items": { "properties": { "full_name": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "Full name of the operating system" + } }, "platform": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "OS Platform. eg Centos, Ubuntu" + } }, "version": { - "type": "keyword" + "type": "keyword", + "_meta": { + "description": "The version of the operating system, eg 16.04.7 LTS (Xenial Xerus), 8 (Core)" + } }, "count": { - "type": "long" + "type": "long", + "_meta": { + "description": "The total number of endpoints from that platform" + } } } } @@ -5224,13 +5266,22 @@ "malware": { "properties": { "active": { - "type": "long" + "type": "long", + "_meta": { + "description": "The total number of active malware policies" + } }, "inactive": { - "type": "long" + "type": "long", + "_meta": { + "description": "The total number of inactive malware policies" + } }, "failure": { - "type": "long" + "type": "long", + "_meta": { + "description": "The total number of failing malware policies" + } } } } From 9793a8fefb7e002360ef02039a4755e8996bb216 Mon Sep 17 00:00:00 2001 From: Quynh Nguyen <43350163+qn895@users.noreply.github.com> Date: Mon, 24 May 2021 11:56:09 -0500 Subject: [PATCH 02/22] [ML] Fix missing selected-interval styling for Explorer anomaly charts and mismatched scheduled markers styling (#100272) * [ML] Fix missing selected-interval sass * [ML] Only show interval box in explorer page and not in dashboard * [ML] Remove console * [ML] Move showSelectedInterval up * [ML] Update snapshot * [ML] Update styling of scheduled events to match and to be visible Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../explorer/explorer_charts/_explorer_chart.scss | 11 +++++++++-- .../explorer_charts/explorer_anomalies_container.tsx | 3 +++ .../explorer_charts/explorer_chart_distribution.js | 3 ++- .../explorer_charts/explorer_chart_single_metric.js | 4 +++- .../explorer_charts/explorer_charts_container.js | 5 +++++ .../timeseriesexplorer/_timeseriesexplorer.scss | 2 +- .../embeddable_anomaly_charts_container.test.tsx.snap | 1 + .../embeddable_anomaly_charts_container.tsx | 1 + 8 files changed, 25 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/_explorer_chart.scss b/x-pack/plugins/ml/public/application/explorer/explorer_charts/_explorer_chart.scss index 5eef427226a7c..55ebfe8ab3edb 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/_explorer_chart.scss +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/_explorer_chart.scss @@ -12,10 +12,17 @@ opacity: 1; } + rect.selected-interval { + fill: rgba(200, 200, 200, .1); + stroke: $euiColorDarkShade; + stroke-width: $euiSizeXS / 2; + stroke-opacity: .8; + } + rect.scheduled-event-marker { stroke-width: 1px; - stroke: $euiColorLightShade; - fill: $euiColorLightestShade; + stroke: $euiColorDarkShade; + fill: $euiColorLightShade; pointer-events: none; } } diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx index d1e22ef21de25..0fe4d260ffced 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx @@ -31,6 +31,7 @@ interface ExplorerAnomaliesContainerProps { timeBuckets: TimeBuckets; timefilter: TimefilterContract; onSelectEntity: (fieldName: string, fieldValue: string, operation: EntityFieldOperation) => void; + showSelectedInterval?: boolean; } const tooManyBucketsCalloutMsg = i18n.translate( @@ -51,6 +52,7 @@ export const ExplorerAnomaliesContainer: FC = ( timeBuckets, timefilter, onSelectEntity, + showSelectedInterval, }) => { return ( <> @@ -96,6 +98,7 @@ export const ExplorerAnomaliesContainer: FC = ( timefilter, onSelectEntity, tooManyBucketsCalloutMsg, + showSelectedInterval, }} /> )} diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js index fa6d8acfb0e00..7efd36bbe57c6 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_distribution.js @@ -62,7 +62,7 @@ export class ExplorerChartDistribution extends React.Component { } renderChart() { - const { tooManyBuckets, tooltipService, timeBuckets } = this.props; + const { tooManyBuckets, tooltipService, timeBuckets, showSelectedInterval } = this.props; const element = this.rootNode; const config = this.props.seriesConfig; @@ -357,6 +357,7 @@ export class ExplorerChartDistribution extends React.Component { } function drawRareChartHighlightedSpan() { + if (showSelectedInterval === false) return; // Draws a rectangle which highlights the time span that has been selected for view. // Note depending on the overall time range and the bucket span, the selected time // span may be longer than the range actually being plotted. diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js index 39a3f83961d3a..dd07a7d6cbdee 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_chart_single_metric.js @@ -61,7 +61,7 @@ export class ExplorerChartSingleMetric extends React.Component { } renderChart() { - const { tooManyBuckets, tooltipService, timeBuckets } = this.props; + const { tooManyBuckets, tooltipService, timeBuckets, showSelectedInterval } = this.props; const element = this.rootNode; const config = this.props.seriesConfig; @@ -249,6 +249,8 @@ export class ExplorerChartSingleMetric extends React.Component { } function drawLineChartHighlightedSpan() { + if (showSelectedInterval === false) return; + // Draws a rectangle which highlights the time span that has been selected for view. // Note depending on the overall time range and the bucket span, the selected time // span may be longer than the range actually being plotted. diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js index 2432c6671827e..c37d8b6d51c72 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js @@ -72,6 +72,7 @@ function ExplorerChartContainer({ onSelectEntity, recentlyAccessed, tooManyBucketsCalloutMsg, + showSelectedInterval, }) { const [explorerSeriesLink, setExplorerSeriesLink] = useState(''); @@ -199,6 +200,7 @@ function ExplorerChartContainer({ seriesConfig={series} severity={severity} tooltipService={tooltipService} + showSelectedInterval={showSelectedInterval} /> )} @@ -214,6 +216,7 @@ function ExplorerChartContainer({ seriesConfig={series} severity={severity} tooltipService={tooltipService} + showSelectedInterval={showSelectedInterval} /> )} @@ -237,6 +240,7 @@ export const ExplorerChartsContainerUI = ({ timefilter, onSelectEntity, tooManyBucketsCalloutMsg, + showSelectedInterval, }) => { const { services: { @@ -296,6 +300,7 @@ export const ExplorerChartsContainerUI = ({ onSelectEntity={onSelectEntity} recentlyAccessed={recentlyAccessed} tooManyBucketsCalloutMsg={tooManyBucketsCalloutMsg} + showSelectedInterval={showSelectedInterval} /> ))} diff --git a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss index 8a56a8f0188b8..33f6c65e03e77 100644 --- a/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss +++ b/x-pack/plugins/ml/public/application/timeseriesexplorer/_timeseriesexplorer.scss @@ -133,7 +133,7 @@ rect.scheduled-event-marker { stroke-width: 1px; - stroke: $euiColorMediumShade; + stroke: $euiColorDarkShade; fill: $euiColorLightShade; pointer-events: none; } diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/__snapshots__/embeddable_anomaly_charts_container.test.tsx.snap b/x-pack/plugins/ml/public/embeddables/anomaly_charts/__snapshots__/embeddable_anomaly_charts_container.test.tsx.snap index 375b041c4db73..e0246439abe57 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/__snapshots__/embeddable_anomaly_charts_container.test.tsx.snap +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/__snapshots__/embeddable_anomaly_charts_container.test.tsx.snap @@ -19,6 +19,7 @@ Object { "val": 75, }, "showCharts": true, + "showSelectedInterval": false, "timeBuckets": TimeBuckets { "_timeBucketsConfig": Object { "dateFormat": undefined, diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/embeddable_anomaly_charts_container.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_charts/embeddable_anomaly_charts_container.tsx index e1748bd21855b..7731d9e822e3a 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/embeddable_anomaly_charts_container.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/embeddable_anomaly_charts_container.tsx @@ -181,6 +181,7 @@ export const EmbeddableAnomalyChartsContainer: FC )} From c9f7ab3f72c61091a76f3c775f1057b7185c441f Mon Sep 17 00:00:00 2001 From: Josh Dover <1813008+joshdover@users.noreply.github.com> Date: Mon, 24 May 2021 20:00:45 +0200 Subject: [PATCH 03/22] Remove `chrome.navLinks.update` (#99633) --- ...ibana-plugin-core-public.chromenavlinks.md | 1 - ...lugin-core-public.chromenavlinks.update.md | 30 ------------ ...re-public.chromenavlinkupdateablefields.md | 12 ----- .../core/public/kibana-plugin-core-public.md | 1 - src/core/public/chrome/chrome_service.mock.ts | 1 - src/core/public/chrome/index.ts | 2 +- src/core/public/chrome/nav_links/index.ts | 2 +- src/core/public/chrome/nav_links/nav_link.ts | 12 ----- .../nav_links/nav_links_service.test.ts | 46 +------------------ .../chrome/nav_links/nav_links_service.ts | 34 +------------- src/core/public/index.ts | 2 - src/core/public/public.api.md | 7 --- x-pack/plugins/apm/public/plugin.ts | 9 ++-- .../plugins/apm/public/toggleAppLinkInNav.ts | 15 ------ x-pack/plugins/graph/common/check_license.ts | 7 ++- x-pack/plugins/graph/public/application.ts | 5 +- x-pack/plugins/graph/public/plugin.ts | 30 +++++++++--- .../graph/public/services/toggle_nav_link.ts | 27 ----------- x-pack/plugins/licensing/README.md | 10 +++- 19 files changed, 50 insertions(+), 203 deletions(-) delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromenavlinks.update.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.chromenavlinkupdateablefields.md delete mode 100644 x-pack/plugins/apm/public/toggleAppLinkInNav.ts delete mode 100644 x-pack/plugins/graph/public/services/toggle_nav_link.ts diff --git a/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.md b/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.md index 2d879a468f587..c12fb45e6ab42 100644 --- a/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.md +++ b/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.md @@ -23,5 +23,4 @@ export interface ChromeNavLinks | [getNavLinks$()](./kibana-plugin-core-public.chromenavlinks.getnavlinks_.md) | Get an observable for a sorted list of navlinks. | | [has(id)](./kibana-plugin-core-public.chromenavlinks.has.md) | Check whether or not a navlink exists. | | [showOnly(id)](./kibana-plugin-core-public.chromenavlinks.showonly.md) | Remove all navlinks except the one matching the given id. | -| [update(id, values)](./kibana-plugin-core-public.chromenavlinks.update.md) | Update the navlink for the given id with the updated attributes. Returns the updated navlink or undefined if it does not exist. | diff --git a/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.update.md b/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.update.md deleted file mode 100644 index 7948f2f8543fd..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromenavlinks.update.md +++ /dev/null @@ -1,30 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeNavLinks](./kibana-plugin-core-public.chromenavlinks.md) > [update](./kibana-plugin-core-public.chromenavlinks.update.md) - -## ChromeNavLinks.update() method - -> Warning: This API is now obsolete. -> -> Uses the property when registering your application with [ApplicationSetup.register()](./kibana-plugin-core-public.applicationsetup.register.md) instead. -> - -Update the navlink for the given id with the updated attributes. Returns the updated navlink or `undefined` if it does not exist. - -Signature: - -```typescript -update(id: string, values: ChromeNavLinkUpdateableFields): ChromeNavLink | undefined; -``` - -## Parameters - -| Parameter | Type | Description | -| --- | --- | --- | -| id | string | | -| values | ChromeNavLinkUpdateableFields | | - -Returns: - -`ChromeNavLink | undefined` - diff --git a/docs/development/core/public/kibana-plugin-core-public.chromenavlinkupdateablefields.md b/docs/development/core/public/kibana-plugin-core-public.chromenavlinkupdateablefields.md deleted file mode 100644 index 0445bb28bb355..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.chromenavlinkupdateablefields.md +++ /dev/null @@ -1,12 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [ChromeNavLinkUpdateableFields](./kibana-plugin-core-public.chromenavlinkupdateablefields.md) - -## ChromeNavLinkUpdateableFields type - - -Signature: - -```typescript -export declare type ChromeNavLinkUpdateableFields = Partial>; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index ae16c1c0e5887..3972f737f6618 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -154,7 +154,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [ChromeBreadcrumb](./kibana-plugin-core-public.chromebreadcrumb.md) | | | [ChromeHelpExtensionLinkBase](./kibana-plugin-core-public.chromehelpextensionlinkbase.md) | | | [ChromeHelpExtensionMenuLink](./kibana-plugin-core-public.chromehelpextensionmenulink.md) | | -| [ChromeNavLinkUpdateableFields](./kibana-plugin-core-public.chromenavlinkupdateablefields.md) | | | [FatalErrorsStart](./kibana-plugin-core-public.fatalerrorsstart.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. | | [HttpStart](./kibana-plugin-core-public.httpstart.md) | See [HttpSetup](./kibana-plugin-core-public.httpsetup.md) | | [IToasts](./kibana-plugin-core-public.itoasts.md) | Methods for adding and removing global toast messages. See [ToastsApi](./kibana-plugin-core-public.toastsapi.md). | diff --git a/src/core/public/chrome/chrome_service.mock.ts b/src/core/public/chrome/chrome_service.mock.ts index ae9c58af69603..b624084258817 100644 --- a/src/core/public/chrome/chrome_service.mock.ts +++ b/src/core/public/chrome/chrome_service.mock.ts @@ -20,7 +20,6 @@ const createStartContractMock = () => { get: jest.fn(), getAll: jest.fn(), showOnly: jest.fn(), - update: jest.fn(), enableForcedAppSwitcherNavigation: jest.fn(), getForceAppSwitcherNavigation$: jest.fn(), }, diff --git a/src/core/public/chrome/index.ts b/src/core/public/chrome/index.ts index 73499a81f2220..dd7affcdbf7cd 100644 --- a/src/core/public/chrome/index.ts +++ b/src/core/public/chrome/index.ts @@ -16,7 +16,7 @@ export type { ChromeHelpExtensionMenuGitHubLink, } from './ui/header/header_help_menu'; export type { NavType } from './ui'; -export type { ChromeNavLink, ChromeNavLinks, ChromeNavLinkUpdateableFields } from './nav_links'; +export type { ChromeNavLink, ChromeNavLinks } from './nav_links'; export type { ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem, diff --git a/src/core/public/chrome/nav_links/index.ts b/src/core/public/chrome/nav_links/index.ts index a35a512b2a842..e41799b9918a3 100644 --- a/src/core/public/chrome/nav_links/index.ts +++ b/src/core/public/chrome/nav_links/index.ts @@ -7,5 +7,5 @@ */ export { NavLinksService } from './nav_links_service'; -export type { ChromeNavLink, ChromeNavLinkUpdateableFields } from './nav_link'; +export type { ChromeNavLink } from './nav_link'; export type { ChromeNavLinks } from './nav_links_service'; diff --git a/src/core/public/chrome/nav_links/nav_link.ts b/src/core/public/chrome/nav_links/nav_link.ts index 65d59c59e9f75..87175ea465b7f 100644 --- a/src/core/public/chrome/nav_links/nav_link.ts +++ b/src/core/public/chrome/nav_links/nav_link.ts @@ -6,7 +6,6 @@ * Side Public License, v 1. */ -import { pick } from '@kbn/std'; import { AppCategory } from '../../'; /** @@ -81,11 +80,6 @@ export interface ChromeNavLink { readonly hidden?: boolean; } -/** @public */ -export type ChromeNavLinkUpdateableFields = Partial< - Pick ->; - export class NavLinkWrapper { public readonly id: string; public readonly properties: Readonly; @@ -98,10 +92,4 @@ export class NavLinkWrapper { this.id = properties.id; this.properties = Object.freeze(properties); } - - public update(newProps: ChromeNavLinkUpdateableFields) { - // Enforce limited properties at runtime for JS code - newProps = pick(newProps, ['disabled', 'hidden', 'url', 'href']); - return new NavLinkWrapper({ ...this.properties, ...newProps }); - } } diff --git a/src/core/public/chrome/nav_links/nav_links_service.test.ts b/src/core/public/chrome/nav_links/nav_links_service.test.ts index 74128aa798e7c..afb902fd6bd83 100644 --- a/src/core/public/chrome/nav_links/nav_links_service.test.ts +++ b/src/core/public/chrome/nav_links/nav_links_service.test.ts @@ -73,13 +73,10 @@ describe('NavLinksService', () => { const navLinkIds$ = start.getNavLinks$().pipe(map((links) => links.map((l) => l.id))); const emittedLinks: string[][] = []; navLinkIds$.subscribe((r) => emittedLinks.push(r)); - start.update('app1', { href: '/foo' }); + start.showOnly('app1'); service.stop(); - expect(emittedLinks).toEqual([ - ['app2', 'app1'], - ['app2', 'app1'], - ]); + expect(emittedLinks).toEqual([['app2', 'app1'], ['app1']]); }); it('completes when service is stopped', async () => { @@ -170,45 +167,6 @@ describe('NavLinksService', () => { }); }); - describe('#update()', () => { - it('updates the navlinks and returns the updated link', async () => { - expect(start.update('app2', { hidden: true })).toEqual( - expect.objectContaining({ - hidden: true, - id: 'app2', - order: -10, - title: 'App 2', - euiIconType: 'canvasApp', - }) - ); - const hiddenLinkIds = await start - .getNavLinks$() - .pipe( - take(1), - map((links) => links.filter((l) => l.hidden).map((l) => l.id)) - ) - .toPromise(); - expect(hiddenLinkIds).toEqual(['app2']); - }); - - it('returns undefined if link does not exist', () => { - expect(start.update('fake', { hidden: true })).toBeUndefined(); - }); - - it('keeps the updated link when availableApps are re-emitted', async () => { - start.update('app2', { hidden: true }); - mockAppService.applications$.next(mockAppService.applications$.value); - const hiddenLinkIds = await start - .getNavLinks$() - .pipe( - take(1), - map((links) => links.filter((l) => l.hidden).map((l) => l.id)) - ) - .toPromise(); - expect(hiddenLinkIds).toEqual(['app2']); - }); - }); - describe('#enableForcedAppSwitcherNavigation()', () => { it('flips #getForceAppSwitcherNavigation$()', async () => { await expect(start.getForceAppSwitcherNavigation$().pipe(take(1)).toPromise()).resolves.toBe( diff --git a/src/core/public/chrome/nav_links/nav_links_service.ts b/src/core/public/chrome/nav_links/nav_links_service.ts index 7a216d584044c..d41d8ae964d62 100644 --- a/src/core/public/chrome/nav_links/nav_links_service.ts +++ b/src/core/public/chrome/nav_links/nav_links_service.ts @@ -12,7 +12,7 @@ import { map, takeUntil } from 'rxjs/operators'; import { InternalApplicationStart } from '../../application'; import { HttpStart } from '../../http'; -import { ChromeNavLink, ChromeNavLinkUpdateableFields, NavLinkWrapper } from './nav_link'; +import { ChromeNavLink, NavLinkWrapper } from './nav_link'; import { toNavLink } from './to_nav_link'; interface StartDeps { @@ -58,18 +58,6 @@ export interface ChromeNavLinks { */ showOnly(id: string): void; - /** - * Update the navlink for the given id with the updated attributes. - * Returns the updated navlink or `undefined` if it does not exist. - * - * @deprecated Uses the {@link AppBase.updater$} property when registering - * your application with {@link ApplicationSetup.register} instead. - * - * @param id - * @param values - */ - update(id: string, values: ChromeNavLinkUpdateableFields): ChromeNavLink | undefined; - /** * Enable forced navigation mode, which will trigger a page refresh * when a nav link is clicked and only the hash is updated. @@ -109,6 +97,7 @@ export class NavLinksService { // now that availableApps$ is an observable, we need to keep record of all // manual link modifications to be able to re-apply then after every // availableApps$ changes. + // Only in use by `showOnly` API, can be removed once dashboard_mode is removed in 8.0 const linkUpdaters$ = new BehaviorSubject([]); const navLinks$ = new BehaviorSubject>(new Map()); @@ -153,25 +142,6 @@ export class NavLinksService { linkUpdaters$.next([...linkUpdaters$.value, updater]); }, - update(id: string, values: ChromeNavLinkUpdateableFields) { - if (!this.has(id)) { - return; - } - - const updater: LinksUpdater = (navLinks) => - new Map( - [...navLinks.entries()].map(([linkId, link]) => { - return [linkId, link.id === id ? link.update(values) : link] as [ - string, - NavLinkWrapper - ]; - }) - ); - - linkUpdaters$.next([...linkUpdaters$.value, updater]); - return this.get(id); - }, - enableForcedAppSwitcherNavigation() { forceAppSwitcherNavigation$.next(true); }, diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 60d40aaf81036..129ae1c16f99b 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -41,7 +41,6 @@ import { ChromeNavControls, ChromeNavLink, ChromeNavLinks, - ChromeNavLinkUpdateableFields, ChromeDocTitle, ChromeStart, ChromeRecentlyAccessed, @@ -298,7 +297,6 @@ export type { ChromeNavControls, ChromeNavLink, ChromeNavLinks, - ChromeNavLinkUpdateableFields, ChromeDocTitle, ChromeRecentlyAccessed, ChromeRecentlyAccessedHistoryItem, diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 449afa8869f6f..31e7a1e2321df 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -332,15 +332,8 @@ export interface ChromeNavLinks { getNavLinks$(): Observable>>; has(id: string): boolean; showOnly(id: string): void; - // Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "AppBase" - // - // @deprecated - update(id: string, values: ChromeNavLinkUpdateableFields): ChromeNavLink | undefined; } -// @public (undocumented) -export type ChromeNavLinkUpdateableFields = Partial>; - // @public export interface ChromeRecentlyAccessed { // Warning: (ae-unresolved-link) The @link reference could not be resolved: No member was found with name "basePath" diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index b493363d98f7a..b76849ccf3011 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -9,6 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { ConfigSchema } from '.'; import { AppMountParameters, + AppNavLinkStatus, CoreSetup, CoreStart, DEFAULT_APP_CATEGORIES, @@ -40,7 +41,6 @@ import type { } from '../../triggers_actions_ui/public'; import { registerApmAlerts } from './components/alerting/register_apm_alerts'; import { featureCatalogueEntry } from './featureCatalogueEntry'; -import { toggleAppLinkInNav } from './toggleAppLinkInNav'; export type ApmPluginSetup = ReturnType; @@ -193,6 +193,9 @@ export class ApmPlugin implements Plugin { order: 8500, euiIconType: 'logoObservability', category: DEFAULT_APP_CATEGORIES.observability, + navLinkStatus: config.ui.enabled + ? AppNavLinkStatus.default + : AppNavLinkStatus.hidden, meta: { keywords: [ 'RUM', @@ -231,7 +234,5 @@ export class ApmPlugin implements Plugin { return {}; } - public start(core: CoreStart, plugins: ApmPluginStartDeps) { - toggleAppLinkInNav(core, this.initializerContext.config.get()); - } + public start(core: CoreStart, plugins: ApmPluginStartDeps) {} } diff --git a/x-pack/plugins/apm/public/toggleAppLinkInNav.ts b/x-pack/plugins/apm/public/toggleAppLinkInNav.ts deleted file mode 100644 index 2e70cdd71ded6..0000000000000 --- a/x-pack/plugins/apm/public/toggleAppLinkInNav.ts +++ /dev/null @@ -1,15 +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 { CoreStart } from 'kibana/public'; -import { ConfigSchema } from '.'; - -export function toggleAppLinkInNav(core: CoreStart, { ui }: ConfigSchema) { - if (ui.enabled === false) { - core.chrome.navLinks.update('apm', { hidden: true }); - } -} diff --git a/x-pack/plugins/graph/common/check_license.ts b/x-pack/plugins/graph/common/check_license.ts index ec43fac66551b..8357efbbba643 100644 --- a/x-pack/plugins/graph/common/check_license.ts +++ b/x-pack/plugins/graph/common/check_license.ts @@ -17,7 +17,7 @@ export function assertNever(x: never): never { export interface GraphLicenseInformation { showAppLink: boolean; enableAppLink: boolean; - message: string; + message?: string; } export function checkLicense(license: ILicense | undefined): GraphLicenseInformation { @@ -53,20 +53,19 @@ export function checkLicense(license: ILicense | undefined): GraphLicenseInforma return { showAppLink: true, enableAppLink: false, - message: check.message || '', + message: check.message, }; case 'invalid': case 'unavailable': return { showAppLink: false, enableAppLink: false, - message: check.message || '', + message: check.message, }; case 'valid': return { showAppLink: true, enableAppLink: true, - message: '', }; default: return assertNever(check.state); diff --git a/x-pack/plugins/graph/public/application.ts b/x-pack/plugins/graph/public/application.ts index acc3790a5ac6e..0b80e18f3fdb2 100644 --- a/x-pack/plugins/graph/public/application.ts +++ b/x-pack/plugins/graph/public/application.ts @@ -91,7 +91,10 @@ export const renderApp = ({ appBasePath, element, kibanaLegacy, ...deps }: Graph const licenseAllowsToShowThisPage = info.showAppLink && info.enableAppLink; if (!licenseAllowsToShowThisPage) { - deps.core.notifications.toasts.addDanger(info.message); + if (info.message) { + deps.core.notifications.toasts.addDanger(info.message); + } + // This has to happen in the next tick because otherwise the original navigation // bringing us to the graph app in the first place // never completes and the browser enters are redirect loop diff --git a/x-pack/plugins/graph/public/plugin.ts b/x-pack/plugins/graph/public/plugin.ts index d8f92e0134dce..4525b42b3feb4 100644 --- a/x-pack/plugins/graph/public/plugin.ts +++ b/x-pack/plugins/graph/public/plugin.ts @@ -6,9 +6,17 @@ */ import { i18n } from '@kbn/i18n'; -import { CoreSetup, CoreStart } from 'kibana/public'; -import { AppMountParameters, Plugin } from 'src/core/public'; -import { PluginInitializerContext } from 'kibana/public'; +import { BehaviorSubject } from 'rxjs'; +import { + AppNavLinkStatus, + AppUpdater, + CoreSetup, + CoreStart, + AppMountParameters, + Plugin, + PluginInitializerContext, + DEFAULT_APP_CATEGORIES, +} from '../../../../src/core/public'; import { Storage } from '../../../../src/plugins/kibana_utils/public'; import { @@ -18,7 +26,6 @@ import { import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public'; import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; -import { toggleNavLink } from './services/toggle_nav_link'; import { LicensingPluginStart } from '../../licensing/public'; import { checkLicense } from '../common/check_license'; import { @@ -26,7 +33,6 @@ import { HomePublicPluginSetup, HomePublicPluginStart, } from '../../../../src/plugins/home/public'; -import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/public'; import { ConfigSchema } from '../config'; import { SavedObjectsStart } from '../../../../src/plugins/saved_objects/public'; @@ -45,6 +51,8 @@ export interface GraphPluginStartDependencies { export class GraphPlugin implements Plugin { + private readonly appUpdater$ = new BehaviorSubject(() => ({})); + constructor(private initializerContext: PluginInitializerContext) {} setup(core: CoreSetup, { home }: GraphPluginSetupDependencies) { @@ -77,6 +85,7 @@ export class GraphPlugin appRoute: '/app/graph', euiIconType: 'logoKibana', category: DEFAULT_APP_CATEGORIES.kibana, + updater$: this.appUpdater$, mount: async (params: AppMountParameters) => { const [coreStart, pluginsStart] = await core.getStartServices(); coreStart.chrome.docTitle.change( @@ -112,7 +121,16 @@ export class GraphPlugin start(core: CoreStart, { home, licensing }: GraphPluginStartDependencies) { licensing.license$.subscribe((license) => { const licenseInformation = checkLicense(license); - toggleNavLink(licenseInformation, core.chrome.navLinks); + + this.appUpdater$.next(() => ({ + navLinkStatus: licenseInformation.showAppLink + ? licenseInformation.enableAppLink + ? AppNavLinkStatus.visible + : AppNavLinkStatus.disabled + : AppNavLinkStatus.hidden, + tooltip: licenseInformation.showAppLink ? licenseInformation.message : undefined, + })); + if (home && !licenseInformation.enableAppLink) { home.featureCatalogue.removeFeature('graph'); } diff --git a/x-pack/plugins/graph/public/services/toggle_nav_link.ts b/x-pack/plugins/graph/public/services/toggle_nav_link.ts deleted file mode 100644 index 364af0c277623..0000000000000 --- a/x-pack/plugins/graph/public/services/toggle_nav_link.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ChromeNavLink, ChromeNavLinks } from 'kibana/public'; -import { GraphLicenseInformation } from '../../common/check_license'; - -type Mutable = { -readonly [P in keyof T]: T[P] }; -type ChromeNavLinkUpdate = Mutable>; - -export function toggleNavLink( - licenseInformation: GraphLicenseInformation, - navLinks: ChromeNavLinks -) { - const navLinkUpdates: ChromeNavLinkUpdate = { - hidden: !licenseInformation.showAppLink, - }; - if (licenseInformation.showAppLink) { - navLinkUpdates.disabled = !licenseInformation.enableAppLink; - navLinkUpdates.tooltip = licenseInformation.message; - } - - navLinks.update('graph', navLinkUpdates); -} diff --git a/x-pack/plugins/licensing/README.md b/x-pack/plugins/licensing/README.md index a058d42fe908b..3de1fe9cae425 100644 --- a/x-pack/plugins/licensing/README.md +++ b/x-pack/plugins/licensing/README.md @@ -84,13 +84,19 @@ class MyPlugin { import { LicensingPluginSetup } from '../licensing/public' class MyPlugin { setup(core: CoreSetup, deps: SetupDeps) { + const appUpdater$ = new BehaviorSubject(() => {}); + core.application.register({ + id: 'myApp', + updater$: appUpdater$, + }); + deps.licensing.license$.subscribe(license => { const { state, message } = license.check('myPlugin', 'gold') const hasRequiredLicense = state === 'valid'; const showLinks = hasRequiredLicense && license.getFeature('name').isAvailable; - chrome.navLinks.update('myPlugin', { - hidden: !showLinks + appUpdater$.next(() => { + navLinkStatus: showLinks ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden }); }) } From 35cafecdce3a4a15ebb01ffe84f3a04dbd27d24b Mon Sep 17 00:00:00 2001 From: Jorge Sanz Date: Mon, 24 May 2021 18:05:13 +0000 Subject: [PATCH 04/22] [Maps][Docs] Fix ems server config path in compose example (#100463) --- docs/maps/connect-to-ems.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/maps/connect-to-ems.asciidoc b/docs/maps/connect-to-ems.asciidoc index 88301123bae3f..a54da6597b9b0 100644 --- a/docs/maps/connect-to-ems.asciidoc +++ b/docs/maps/connect-to-ems.asciidoc @@ -163,7 +163,7 @@ services: {hosted-ems}: image: {ems-docker-image} volumes: - - ./elastic-maps-server.yml:/usr/src/app/config/elastic-maps-server.yml + - ./elastic-maps-server.yml:/usr/src/app/server/config/elastic-maps-server.yml -------------------------------------------- [float] From 28a7bd31fdc995cffa413b7ce8104e4ea510a8ce Mon Sep 17 00:00:00 2001 From: Kaarina Tungseth Date: Mon, 24 May 2021 15:14:37 -0500 Subject: [PATCH 05/22] [DOCS] Dashboard changes for 7.13 (#99681) * [DOCS] Dashboard changes for 7.13 * Review comments * Review comments * Fixes link * Fixes lens link --- docs/concepts/index.asciidoc | 1 + docs/discover/save-search.asciidoc | 9 +- docs/setup/settings.asciidoc | 6 + .../user/dashboard/aggregation-based.asciidoc | 31 +- .../create-panels-with-editors.asciidoc | 4 +- docs/user/dashboard/dashboard.asciidoc | 320 +++++++----------- docs/user/dashboard/drilldowns.asciidoc | 2 +- .../dashboard/enhance-dashboards.asciidoc | 14 +- docs/user/dashboard/lens.asciidoc | 14 +- docs/user/dashboard/timelion.asciidoc | 53 +-- docs/user/dashboard/tsvb.asciidoc | 4 +- docs/user/dashboard/vega.asciidoc | 10 +- 12 files changed, 164 insertions(+), 304 deletions(-) diff --git a/docs/concepts/index.asciidoc b/docs/concepts/index.asciidoc index cb37dceb53564..43e5ae733a760 100644 --- a/docs/concepts/index.asciidoc +++ b/docs/concepts/index.asciidoc @@ -87,6 +87,7 @@ image:concepts/images/refresh-every.png["section of time filter where you can co [float] +[[semi-structured-search]] ==== Semi-structured search Combine free text search with field-based search using the Kibana Query Language (KQL). diff --git a/docs/discover/save-search.asciidoc b/docs/discover/save-search.asciidoc index edfdae9a6b081..b59f14180b1ff 100644 --- a/docs/discover/save-search.asciidoc +++ b/docs/discover/save-search.asciidoc @@ -35,8 +35,9 @@ image::discover/images/read-only-badge.png[Example of Discover's read only acces If the saved search is associated with a different index pattern than is currently selected, opening the saved search changes the selected index pattern. The query language used for the saved search is also automatically selected. -. To add your search results to an existing dashboard: -.. Open the dashboard, then click *Edit*. +. To add your search results to a dashboard: +.. Open the main menu, then click *Dashboard*. +.. Open or create the dashboard, then click *Edit*. .. Click *Add from library*. -.. Open the *Types* menu, then select *Saved search*. -.. Select the the saved search that you want. +.. From the *Types* dropdown, select *Saved search*. +.. Select the saved search that you want to visualize, then click *X* to close the list. diff --git a/docs/setup/settings.asciidoc b/docs/setup/settings.asciidoc index 0aab86fb5a9e2..bac2b0ebdf15f 100644 --- a/docs/setup/settings.asciidoc +++ b/docs/setup/settings.asciidoc @@ -723,6 +723,12 @@ out through *Advanced Settings*. *Default: `true`* | Set this value to true to allow Vega to use any URL to access external data sources and images. When false, Vega can only get data from {es}. *Default: `false`* +| `xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled` + | Enables the *Explore underlying data* option that allows you to open *Discover* from a dashboard panel and view the panel data. *Default: `false`* + + | `xpack.discoverEnhanced.actions.exploreDataInChart.enabled` + | Enables you to view the underlying documents in a data series from a dashboard panel. *Default: `false`* + | `xpack.license_management.enabled` | Set this value to false to disable the License Management UI. *Default: `true`* diff --git a/docs/user/dashboard/aggregation-based.asciidoc b/docs/user/dashboard/aggregation-based.asciidoc index 49c092f8baa4c..cb102b73f93b4 100644 --- a/docs/user/dashboard/aggregation-based.asciidoc +++ b/docs/user/dashboard/aggregation-based.asciidoc @@ -92,17 +92,17 @@ create visual art for a specific topic. Choose the type of visualization you want to create, then use the editor to configure the options. -. From the dashboard, click *Create panel*, then click *Aggregation based* on the *New visualization* window. +. On the dashboard, click *All types > Aggregation based*. -.. Click the type of visualization you want to create. +.. Select the visualization type you want to create. -.. Click the data source you want to visualize. +.. Select the data source you want to visualize. -. From the editor, add the <> you want to visualize, then click *Update*. +. Add the <> you want to visualize using the editor, then click *Update*. + NOTE: For the *Date Histogram* to use an *auto interval*, the date field must match the primary time field of the index pattern. -. To change the order, drag the aggregations along the editor. +. To change the order, drag and drop the aggregations in the editor. + [role="screenshot"] image:images/bar-chart-tutorial-3.png[Option to change the order of aggregations] @@ -137,13 +137,9 @@ Add the sample web logs data that you'll use to create the bar chart, then creat Open the bar chart visualization builder and change the time range. -. On the dashboard, click *Create panel*. +. On the dashboard, click *All types > Aggregation based*, select *Vertical bar*, then select *kibana_sample_data_logs*. -. On the *New visualization* window, click *Aggregation based > Vertical bar*. - -. On the *Choose a source* window, click *kibana_sample_data_logs*. - -. Change the <>> to *Last 7 days*. +. Make sure the <>> is *Last 7 days*. [float] [[tutorial-configure-the-bar-chart]] @@ -177,19 +173,6 @@ TIP: Aggregation-based panels support a maximum of three *Split series*. [role="screenshot"] image:images/bar-chart-tutorial-2.png[Bar chart with sample logs data] -[float] -===== Save the panel - -Save and add the visualization panel to the dashboard. - -. From the toolbar, click *Save*. - -. Enter the *Title* and optional *Description*. - -. From the *Tags* drop down, select any applicable tags. - -. Select *Add to Dashboard after saving*. - . Click *Save and return*. diff --git a/docs/user/dashboard/create-panels-with-editors.asciidoc b/docs/user/dashboard/create-panels-with-editors.asciidoc index 8e047819fd1c6..17d3b5fb8a8a5 100644 --- a/docs/user/dashboard/create-panels-with-editors.asciidoc +++ b/docs/user/dashboard/create-panels-with-editors.asciidoc @@ -1,13 +1,13 @@ [[create-panels-with-editors]] == Create panels with editors -{kib} provides several editors that you can use to create dashboard panels. +{kib} provides several editors that you can use to create panels of your data. [cols="2"] |=== | <> -| Create visualizations with the drag and drop editor. *Lens* is recommended for most users. +| Create visualizations with the drag and drop editor. | <> | Create visualizations with your geographical data. diff --git a/docs/user/dashboard/dashboard.asciidoc b/docs/user/dashboard/dashboard.asciidoc index 070d511ed8073..8226e9c6ed073 100644 --- a/docs/user/dashboard/dashboard.asciidoc +++ b/docs/user/dashboard/dashboard.asciidoc @@ -6,35 +6,34 @@ **_Visualize your data with dashboards._** The best way to understand your data is to visualize it. With dashboards, you can turn your data from one or more <> into a collection of panels -that bring clarity to your data, tell a story about your data, and allow you to focus on only the data that's important to you. Configure each panel to display your data in a chart, table, map, and more, -then compare the panels side-by-side to identify the patterns and connections in your data. +that bring clarity to your data, tell a story about your data, and allow you to focus on only the data that's important to you. [role="screenshot"] image:images/Dashboard_example.png[Example dashboard] -Dashboards support many types of panels, and provide several editors that you can use to create panels. +Panels display your data in charts, tables, maps, and more, which allow you to compare your data side-by-side to identify patterns and connections. Dashboards support several editors you can use to create panels, and support many types of panels to display your data. [cols="2"] |=== -| <> -| Use the *Lens*, *TSVB*, *Vega*, and *Timelion* editors to help you create visualizations of your data, or create aggregation-based visualizations using {es} <>. -*Lens* is recommended for most users. +| <> +| Use the *Lens*, *TSVB*, *Vega*, and *Timelion* editors to create visualizations of your data, or create *Aggregation based* visualizations using {es} aggregations. +*Lens* is the recommended editor. | <> | Create beautiful displays of your geographical data. -| <> -| Add context to your panels with <>, or add dynamic filters with <>. +| <> +| Display the results from machine learning anomaly detection jobs. -| <> -| Display a saved search table from <>. The table results are not aggregated. +| <> +| Display an anomaly chart from the *Anomaly Explorer. | <> | Display a table of live streaming logs. -| <> -| Display the results from machine learning anomaly detection jobs. +| <> +| Add context to your panels with <>, or add dynamic filters with <>. |=== @@ -54,10 +53,8 @@ To create dashboards, you must meet the minimum requirements. * Make sure you have {ref}/getting-started-index.html[data indexed into {es}] and an <>. -* Have an understanding of {ref}/documents-indices.html[{es} documents and indices]. - * When the read-only indicator appears, you have insufficient privileges -to create or save dashboards. The options to create and save dashboards are not visible. For more information, +to create or save dashboards, and the options to create and save dashboards are not visible. For more information, refer to <>. [float] @@ -74,281 +71,225 @@ Begin with an empty dashboard, or open an existing dashboard. * To open an existing dashboard, click the dashboard *Title* you want to open. -[float] -[[add-panels]] -=== Add panels - -To add panels to the dashboard, you can use one of the editors to create a new panel, -add an existing panel from the *Visualize Library*, add a table of live streaming logs, or the add the results from a machine learning anomaly detection job. - [float] [[create-panels-with-lens]] -==== Create panels - -To create panels, use one of the editors, then add the panel to the dashboard. - -. On the dashboard, click *Create panel*. +=== Add panels -. On the *New visualization* window, click the editor you want to use. *Lens* is recommended for most users. +Create and add panels of your data to the dashboard, or add existing panels from the library. -. To create the panel, configure the editor options. +* *Create visualization* — Opens *Lens*, the recommended editor to create visualizations of your data. -. To add the panel to the dashboard, choose one of the following options: +* *All types* — Select the editor to create the panel, or select the panel type you want to add to the dashboard. -* To add the panel to the dashboard without saving to the *Visualize Library*, click *Save and return*. +* *Add from library* — Add panels from the *Visualize Library*, including search results from <>. The search results from *Discover* are not aggregated. + -To add a title to the panel, click *No Title*, enter the *Panel title*, then click *Save*. +When a panel contains a saved query, both queries are applied. -* To save the panel to the *Visualize Library*, click *Save to Library*, configure the options, then click *Save and return*. -+ -When panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the header. +[[tsvb]] [float] -[[add-panels-from-the-library]] -==== Add panels from the library - -Add panels that you've already created from the *Visualize Library*. - -. On the dashboard, click *Add from library*. +[[save-panels]] +=== Save panels -. On the *Add from library* flyout, click the panels you want to add to the dashboard. +Consider where you want to save the panel in {kib}. You can save the panel just on the dashboard you are working on, or save the panel in the *Visualize Library*. -. To close the flyout, click *X*. -+ -When a panel contains a stored query, both queries are applied. - -. To make changes to the panel, open the panel menu, then select the following options: - -* *Edit visualization* — Opens an editor so that you can reconfigure the panel. -+ -To make changes to the panel without affecting the original version, open the panel menu, then click *More > Unlink from library*. +[float] +[[save-to-visualize-library]] +==== Save to the Visualize Library -* *Edit panel title* — Opens the *Customize panel* window to change the *Panel title* and specify whether you want to display the panel title. +To use the panel on *Canvas* workpads and other dashboards, save the panel to the *Visualize Library*. -[float] -[[add-a-table-of-live-streaming-logs]] -==== Add a logs panel +. Click *Save to library*. -Add a panel that displays a table of live streaming logs. +. Enter the *Title* and add any applicable *Tags*. -. On the dashboard, click *Add from library*. +. Make sure that *Add to Dashboard after saving* is selected. -. On the *Add from library* flyout, click *Create new*, then select *Log stream*. +. Click *Save and return*. ++ +When panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the panel header. [float] -[[add-machine-learning-results]] -==== Add machine learning results +[[save-to-the-dashboard]] +==== Save to the dashboard -Add a panel that displays the results from machine learning anomaly detection jobs. +Quickly add the panel and return to the dashboard without specifying the save options or adding the panel to the *Visualize Library*. -. On the dashboard, click *Add from library*. +. Click *Save and return*. -. On the *Add from library* flyout, click *Create new*, then select *ML Anomaly Swim Lane*. +. Add more panels to the dashboard, or specify the panel title. -[[tsvb]] +.. In the panel header, click *No Title*. -[float] -[[arrange-panels]] -[[moving-containers]] -[[resizing-containers]] -=== Arrange the panels +.. Select *Show panel title*. -To compare the data in the panels, reorganize or remove the panels on the dashboard. +.. Enter the *Panel title*. -. From the toolbar, click *Edit*, then use the following options: +If you change your mind and want to add the panel to the *Visualize Library*: -* To move, click and hold the panel header, then drag to the new location. +. Open the panel menu, then select *More > Save to library*. -* To resize, click the resize control, then drag to the new dimensions. +. Enter the panel title, then click *Save*. -* To maximize the panel to fullscreen, open the panel menu, then click *More > Maximize panel*. +[float] +[[edit-panels]] +== Edit panels -* To delete, open the panel menu, then click *More > Delete from dashboard*. +To make changes to the panel, use the panel menu options. -. To save your changes, click *Save* in the toolbar. +. In the toolbar, click *Edit*. -[float] -[[apply-design-options]] -=== Apply design options +. Open the panel menu, then use the following options: -Apply a set of design options to the entire dashboard. +* *Edit lens* — Opens *Lens* so you can make changes to the visualization. -. From the toolbar, click *Edit > Options*. - -. Select the following options: +* *Edit visualization* — Opens the editor so you can make changes to the panel. ++ +To make changes without changing the original version, open the panel menu, then click *More > Unlink from library*. -* *Use margins between panels* — Specifies a margin of space between each panel. +* *Edit panel title* — Opens the *Customize panel* window to change the *Panel title*. -* *Show panel titles* — Specifies the appearance of titles in the header of each panel. +* *More > Replace panel* — Opens the *Visualize Library* so you can select a new panel to replace the existing panel. -* *Sync color pallettes across panels* — Specifies whether the color pallette is applied to all panels. +* *More > Delete from dashboard* — Removes the panel from the dashboard. ++ +If you want to use the panel later, make sure that you save the panel to the *Visualize Library*. [float] [[search-or-filter-your-data]] -=== Search or filter your data +== Search and filter your data -{kib} provides you with several ways to search your data and apply {es} filters. You can combine the filters with any panel +{kib} supports several ways to search your data and apply {es} filters. You can combine the filters with any panel filter to display the data want to you see. -[float] -[[semi-structured-search]] -==== Semi-structured search - -Combine free text search with field-based search using the <>. -Type a search term to match across all fields, or begin typing a field name to -get prompted with field names and operators you can use to build a structured query. +For more information about {kib} and {es} filters, refer to <>. -For example, in the sample web logs data, the following query displays data only for the US: +To apply a panel-level time filter: -. Enter `g`, then select *geo.source*. +. Open the panel menu, then select *More > Customize time range*. -. Select *equals some value* and *US*, then click *Update*. +. Enter the time range you want to view, then click *Add to panel*. -. For a more complex search, try: +[float] +[[arrange-panels]] +[[moving-containers]] +[[resizing-containers]] +== Arrange panels -[source,text] -------------------- -geo.src : "US" and url.keyword : "https://www.elastic.co/downloads/beats/metricbeat" -------------------- +To compare the data side-by-side, move and arrange the panels. -[float] -[[time-filter]] -==== Time filter +In the toolbar, click *Edit*, then use the following options: -The <> restrict the data that appears on the dashboard, but you can override the time filter with panel filters. - -. To update the time filter, add a panel that displays time-based data along the x-axis. +* To move, click and hold the panel header, then drag to the new location. -. Open the panel menu, then select *More > Customize time range*. +* To resize, click the resize control, then drag to the new dimensions. -. On the *Customize panel time range* window, specify the time range, then click *Add to panel*. -+ -[role="screenshot"] -image:images/time_range_per_panel.gif[Time range per dashboard panel] +* To maximize to fullscreen, open the panel menu, then click *More > Maximize panel*. [float] -[[additional-filters-with-and]] -==== Additional filters with AND - -Add filters to a dashboard, or pin filters to multiple places in {kib}. To add filters, you can use the *Edit Filter* options, or the advanced JSON editor for the {es} {ref}/query-dsl.html[Query DSL]. -When there is one or more index patterns on the dashboard, you can select the index pattern that contains the fields you want to create the filter. +[[apply-design-options]] +== Apply design options -For example, to filter the dashboard to display only ios data from *kibana_sample_data_logs*: +Apply a set of design options to the entire dashboard. -. Click *Add filter*. +In the toolbar, click *Edit > Options*, then use the following options: -. From the *Index Pattern* dropdown, select *kibana_sample_data_logs*. +* *Use margins between panels* — Specifies a margin of space between each panel. -. Set *Field* to *machine.os*, *Operator* to *is*, and *Value* to *ios*. +* *Show panel titles* — Specifies the appearance of titles in the header of each panel. -. *Save* the filter. -+ -To remove the filter, click *x*. +* *Sync color pallettes across panels* — Specifies whether the color pallette is applied to all panels. [float] -[[add-dynamic-filters]] -==== Add dynamic filters +[[duplicate-panels]] +== Duplicate panels -When you see data in a panel that you want to use as a filter, you can dynamically create the filter. To dynamically add filters, click the data in a panel. - -. Click the data in the panel. - -. Select filters you want to apply to all of the dashboard panels, then click *Apply*. -+ -To remove the filters, click *x*. +To duplicate a panel and the configured functionality, use the clone and copy panel options. Cloned and copied panels replicate all of the functionality from the original panel, +including renaming, editing, and cloning. [float] [[clone-panels]] === Clone panels -To duplicate a panel and the configured functionality, clone the panel. Cloned panels continue to replicate all of the functionality from the original panel, -including renaming, editing, and cloning. When you clone a panel, the clone appears beside the original panel, and moves other panels to provide a space on the -dashboard. +Cloned panels appear next to the original panel, and move the other panels to provide a space on the dashboard. -. From the toolbar, click *Edit*. +. In the toolbar, click *Edit*. . Open the panel menu, then select *Clone panel*. + -[role="screenshot"] -image:images/clone_panel.gif[clone panel] -+ When cloned panels are saved in the *Visualize Library*, image:dashboard/images/visualize-library-icon.png[Visualize Library icon] appears in the header. [float] [[copy-to-dashboard]] === Copy panels -To add a panel to another dashboard, copy the panel. +Copy panels from one dashboard to another dashboard. . Open the panel menu, then select *More > Copy to dashboard*. . On the *Copy to dashboard* window, select the dashboard, then click *Copy and go to dashboard*. [float] -[[explore-the-underlying-data]] -=== Explore the underlying documents +[[explore-the-underlying-documents]] +== Explore the underlying documents -View the underlying documents in a panel, or in a data series. +To gain insight to the data, open the underlying panel or data series documents in *Discover*. The panel documents that you open in *Discover* have the same time range and filters as the source panel. -. In kibana.yml, add the following: -+ -["source","yml"] ------------ -xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled: true ------------ - -TIP: *Explore underlying data* is supported only for visualization panels with a single index pattern. +[float] +[[explore-underlying-panel-documents]] +=== Explore the underlying panel documents -To view the underlying documents in the panel: +When your visualization panel contains a single index pattern, you can open the panel documents in *Discover*. . Open the panel menu. . Click *Explore underlying data*. + -*Discover* opens with the same time range and filters as the panel. -+ [role="screenshot"] image::images/explore_data_context_menu.png[Explore underlying data from panel context menu] -To view the underlying documents in a data series: +[float] +[[explore-underlying-data-series-documents]] +=== Explore the underlying data series documents -. In kibana.yml, add the following: -+ -["source","yml"] ------------ -xpack.discoverEnhanced.actions.exploreDataInChart.enabled: true ------------ +To gain insight to a data series, open the documents in *Discover*. -. Open the dashboard, then click on the data series you want to view. +. Click the data series in the panel that you want to view. + +. Select *Explore underlying data*. + [role="screenshot"] image::images/explore_data_in_chart.png[Explore underlying data from chart] [float] [[download-csv]] -=== Download the panel data +== Download panel data Download panel data in a CSV file. You can download most panels in a CSV file, but there is a shortcut available for *Lens* panels. +[float] [role="xpack"] -To download *Lens* panel data in a CSV file: +[[download-lens-data]] +=== Download Lens data + +When you download *Lens* panel data, each layer produces a single CSV file with columns. +When you download multiple layers, the file names combine the visualization and layer index names. -. Open the *Lens* panel menu. +. Open the *Lens* panel menu . Select *More > Download as CSV*. -+ -[role="screenshot"] -image::images/download_csv_context_menu.png[Download as CSV from panel context menu] -Each layer produces a single CSV file with columns. -When you download multiple layers, the file names combine the visualization and layer index names. +[float] +[[download-other-panel-data]] +=== Download all other panel data -To download all other panel data in a CSV file: +Download the data for non-*Lens* panels. . Open the panel menu, then select *Inspect*. . Click *Download CSV*, then select the CSV type from the dropdown: + * *Formatted CSV* — Contains human-readable dates and numbers. * *Unformatted* — Best used for computer use. @@ -356,40 +297,17 @@ To download all other panel data in a CSV file: [role="screenshot"] image:images/Dashboard_inspect.png[Inspect in dashboard] -[float] -[[save-the-dashboard]] -=== Save the dashboard - -When you're finished making changes, save the dashboard. - -From the toolbar, choose one of the following options: - -* *Save as* — Opens the *Save dashboard* window, which allows you to specify the title and dashboard options. - -* *Save* — Allows you to save the changes you've made to an existing dashboard. - -* *Switch to view mode* — Allows you to exit *Edit* mode without saving your changes, or you can discard the changes you've made. All dashboards with unsaved changes display *Unsaved changes* in the toolbar. - [float] [[share-the-dashboard]] -=== Share the dashboard - -To share the dashboard with a larger audience, click *Share* in the toolbar, then choose one of the following options: - -* *Embed code* — Embed a fully interactive dashboard as an iframe on a web page. To access embedded dashboards, you can require users to -log in using their {kib} credentials, via reverse proxy, or enable <>. - -* *Permalinks* — Share a direct link to a {kib} dashboard. User authentication is required. - -* *PDF Reports* — Generate a PDF report. For more information, refer to <>. +== Share dashboards -* *PNG Reports* — Generate a PNG report. For more information, refer to <>. +To share the dashboard with a larger audience, click *Share* in the toolbar. For detailed information, refer to <>. [float] [[import-dashboards]] -=== Export the dashboard +== Export dashboards -To automate {kib}, you can export dashboards as JSON using the <>. It is important to export dashboards with all references needed. +To automate {kib}, you can export dashboards as JSON using the <>. It is important to export dashboards with all necessary references. -- include::tutorial-create-a-dashboard-of-lens-panels.asciidoc[] diff --git a/docs/user/dashboard/drilldowns.asciidoc b/docs/user/dashboard/drilldowns.asciidoc index fc25f84030ee2..0eb4b43466ff9 100644 --- a/docs/user/dashboard/drilldowns.asciidoc +++ b/docs/user/dashboard/drilldowns.asciidoc @@ -152,7 +152,7 @@ To create dashboard drilldowns, you create or locate the dashboards you want to * *[Logs] Total Requests and Bytes* * *[Logs] Visitors by OS* + -If you don’t see the data on a panel, try changing the <>. +If you don’t see the data on a panel, change the <>. . Save the dashboard. In the *Title* field, enter `Host Overview`. diff --git a/docs/user/dashboard/enhance-dashboards.asciidoc b/docs/user/dashboard/enhance-dashboards.asciidoc index 7176a2e283457..c999ec9b68251 100644 --- a/docs/user/dashboard/enhance-dashboards.asciidoc +++ b/docs/user/dashboard/enhance-dashboards.asciidoc @@ -1,7 +1,7 @@ [[enhance-dashboards]] == Enhance dashboards -Now that you have added panels to your dashboard, you can add filter panels to interact with the data, and Markdown panels to add context to the data. +You can add filter panels to interact with the data in your visualization panels, and Markdown panels to add context to the data. To make your dashboard look the way you want, use the editing options. [float] @@ -21,11 +21,9 @@ min and max aggregation. For example, use the range slider when you want to filt [role="screenshot"] image::images/dashboard-controls.png[] -. From the dashboard, click *Create panel*. +. On the dashboard, click *All types*, then select *Controls*. -. On the *New Visualization* window, click *Controls*. - -. Click *Options*, then configure the following, then click *Update*: +. Click *Options*, then configure the following options: * *Update {kib} filters on each change* — When selected, all interactive inputs create filters that refresh the dashboard. When unselected, {kib} filters are created only when you click *Apply changes*. @@ -34,6 +32,8 @@ image::images/dashboard-controls.png[] * *Pin filters for all applications* — When selected, all filters created by interacting with the inputs are automatically pinned. +. Click *Update* + [float] [[add-text]] === Add text @@ -42,9 +42,7 @@ Add text panels with *Markdown* when you want to provide context to the other pa *Markdown* is a text entry field that accepts GitHub-flavored Markdown text. For information about GitHub-flavored Markdown text, click *Help*. -. From the dashboard, click *Create panel*. - -. On the *New Visualization* window, click *Text*. +. From the dashboard, click *All types*, then select *Text*. . In the *Markdown* field, enter the text, then click *Update*. diff --git a/docs/user/dashboard/lens.asciidoc b/docs/user/dashboard/lens.asciidoc index 94c9db1462760..613432908df3d 100644 --- a/docs/user/dashboard/lens.asciidoc +++ b/docs/user/dashboard/lens.asciidoc @@ -13,11 +13,9 @@ image:dashboard/images/lens.png[Lens] Open *Lens*, then explore the fields in your data. The list of fields are determined by the index pattern and time filter. -. On the dashboard, click *Create panel*. +. On the dashboard, click *Create visualization*. -. On the *New visualization* window, click *Lens*. - -. <>. +. In *Lens*, <>. . To view the fields in the a different index pattern, click the index pattern, then select a different index pattern from the dropdown. @@ -56,11 +54,11 @@ TIP: *Other* can equal more than 100% by a small amount. [float] [[create-the-visualization-panel]] -==== Create the visualization panel +==== Create visualizations -Drag and drop the fields on to the visualization builder, then +Drag and drop the fields on to the visualization builder, then customize the visualization. -. Drag and drop the fields to the visualization builder. +. Drag and drop the fields on to the visualization builder. . To change the visualization type, use the following options: @@ -102,7 +100,7 @@ For more information about adding fields to index patterns and Painless scriptin [float] [[drag-and-drop-keyboard-navigation]] -===== Create visualization panels with keyboard navigation +===== Create visualizations with keyboard navigation *Lens* has a fully accessible, continuously improved drag and drop system, which allows you to use a keyboard instead of a mouse. diff --git a/docs/user/dashboard/timelion.asciidoc b/docs/user/dashboard/timelion.asciidoc index 12d0169c13f66..675fd03df3648 100644 --- a/docs/user/dashboard/timelion.asciidoc +++ b/docs/user/dashboard/timelion.asciidoc @@ -1,7 +1,7 @@ [[timelion]] === Timelion -Instead of using a visual editor to create charts, you define a graph by chaining functions together, using the *Timelion*-specific syntax. +To use *Timelion*, you define a graph by chaining functions together, using the *Timelion*-specific syntax. The syntax enables some features that classical point series charts don't offer, such as pulling data from different indices or data sources into one graph. deprecated::[7.0.0,"*Timelion* is still supported. The *Timelion app* is deprecated in 7.0, replaced by dashboard features. In the last 7.x minor version and later, the *Timelion app* is removed from {kib}. To prepare for the removal of *Timelion app*, you must migrate *Timelion app* worksheets to a dashboard. For information on how to migrate *Timelion app* worksheets, refer to the link:https://www.elastic.co/guide/en/kibana/7.10/release-notes-7.10.0.html#deprecation-v7.10.0[7.10.0 Release Notes]."] @@ -90,11 +90,9 @@ Set up Metricbeat, then create the dashboard. Open *Timelion* and change the time range. -. On the dashboard, click *Create panel*. +. On the dashboard, click *All types > Aggregation based*, then select *Timelion*. -. On the *New visualization* window, click *Aggregation based > Timelion*. - -. Change the <> to *Last 7 days*. +. Make sure the <> is *Last 7 days*. [float] [[timelion-tutorial-create-time-series-visualizations]] @@ -242,20 +240,7 @@ Move the legend to the north west position with two columns, then click *Update image::images/timelion-customize04.png[Final time series visualization] {nbsp} -[float] -==== Save the panel - -Save and add the panel to the dashboard. - -. From the toolbar, click *Save*. - -. Enter the *Title* and optional *Description*. - -. From the *Tags* drop down, select any applicable tags. - -. Select *Add to Dashboard after saving*. - -. Click *Save and return*. +To save the panel, click *Save and return* in the toolbar. [float] [[timelion-tutorial-create-visualizations-with-mathematical-functions]] @@ -364,20 +349,7 @@ Customize and format the visualization using the following functions, then click image::images/timelion-math05.png[Final visualization that displays inbound and outbound network traffic] {nbsp} -[float] -==== Save the panel - -Save and add the panel to the dashboard. - -. From the toolbar, click *Save*. - -. Enter the *Title* and optional *Description*. - -. From the *Tags* drop down, select any applicable tags. - -. Select *Add to Dashboard after saving*. - -. Click *Save and return*. +To save the panel, click *Save and return* in the toolbar. [float] [[timelion-tutorial-create-visualizations-withconditional-logic-and-tracking-trends]] @@ -539,19 +511,6 @@ Customize and format the visualization using the following functions, then click image::images/timelion-conditional04.png[Final visualization that displays outliers and patterns over time] {nbsp} -[float] -==== Save the panel - -Save and add the panel to the dashboard. - -. From the toolbar, click *Save*. - -. Enter the *Title* and optional *Description*. - -. From the *Tags* drop down, select any applicable tags. - -. Select *Add to Dashboard after saving*. - -. Click *Save and return*. +To save the panel, click *Save and return* in the toolbar. For more information about *Timelion* conditions, refer to https://www.elastic.co/blog/timeseries-if-then-else-with-timelion[I have but one .condition()]. diff --git a/docs/user/dashboard/tsvb.asciidoc b/docs/user/dashboard/tsvb.asciidoc index 5c4ce8e365e86..b69df7c7d26d6 100644 --- a/docs/user/dashboard/tsvb.asciidoc +++ b/docs/user/dashboard/tsvb.asciidoc @@ -14,9 +14,7 @@ image::visualize/images/tsvb-screenshot.png[TSVB overview] Open *TSVB*, then make sure the required settings are configured. -. On the dashboard, click *Create panel*. - -. On the *New visualization* window, click *TSVB*. +. On the dashboard, click *All types*, then select *TSVB*. . In *TSVB*, click *Panel options*, then specify the required *Data* settings. diff --git a/docs/user/dashboard/vega.asciidoc b/docs/user/dashboard/vega.asciidoc index b90370af5a12a..faf54e2b7acfc 100644 --- a/docs/user/dashboard/vega.asciidoc +++ b/docs/user/dashboard/vega.asciidoc @@ -37,13 +37,11 @@ Before starting, add the eCommerce sample data that you'll use in your spec, the Open *Vega-Lite* and change the time range. -. On the dashboard, click *Create panel*. - -. On the *New visualization* window, click *Custom visualization*. +. On the dashboard, click *All types*, then select *Custom visualization*. + A pre-populated line chart displays the total number of documents. -. Change the <> to *Last 7 days*. +. Make sure the <> is *Last 7 days*. [float] [[vega-tutorial-create-a-stacked-area-chart]] @@ -595,9 +593,9 @@ Add the {es} search query with the `data` block, then click *Update*: ``` [float] -===== Change the X- and Y-axes +===== Change the x- and y-axes -Display labels for the X- and Y-axes. +Display labels for the x- and y-axes. In the *Vega* spec, add the `scales` block, then click *Update*: From eb0deac8d08ecfbf29d34edd11564ee6f2860ce6 Mon Sep 17 00:00:00 2001 From: ymao1 Date: Mon, 24 May 2021 16:24:15 -0400 Subject: [PATCH 06/22] [Alerting] Update README (#100478) * Updating readme * Updating readme * Fix plugin list docs --- docs/developer/plugin-list.asciidoc | 2 +- x-pack/plugins/alerting/README.md | 386 ++++++++++++++++------------ 2 files changed, 216 insertions(+), 172 deletions(-) diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 4ba5e32eec8b5..94384024e0935 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -321,7 +321,7 @@ which will load the visualization's editor. |{kib-repo}blob/{branch}/x-pack/plugins/alerting/README.md[alerting] -|The Kibana alerting plugin provides a common place to set up alerts. You can: +|The Kibana Alerting plugin provides a common place to set up rules. You can: |{kib-repo}blob/{branch}/x-pack/plugins/apm/readme.md[apm] diff --git a/x-pack/plugins/alerting/README.md b/x-pack/plugins/alerting/README.md index eb64d71be565e..0d5b0bf415fed 100644 --- a/x-pack/plugins/alerting/README.md +++ b/x-pack/plugins/alerting/README.md @@ -1,21 +1,21 @@ -# Kibana alerting +# Kibana Alerting -The Kibana alerting plugin provides a common place to set up alerts. You can: +The Kibana Alerting plugin provides a common place to set up rules. You can: -- Register types of alerts -- List the types of registered alerts -- Perform CRUD actions on alerts +- Register types of rules +- List the types of registered rules +- Perform CRUD actions on rules ---- Table of Contents -- [Kibana alerting](#kibana-alerting) +- [Kibana Alerting](#kibana-alerting) - [Terminology](#terminology) - [Usage](#usage) - - [Alerts API keys](#alerts-api-keys) - - [Plugin status](#plugin-status) - - [Alert types](#alert-types) + - [Alerting API Keys](#alerting-api-keys) + - [Plugin Status](#plugin-status) + - [Rule Types](#rule-types) - [Methods](#methods) - [Executor](#executor) - [Action variables](#action-variables) @@ -24,52 +24,62 @@ Table of Contents - [Tests](#tests) - [Example](#example) - [Role Based Access-Control](#role-based-access-control) - - [Alert Navigation](#alert-navigation) - - [Experimental RESTful API](#restful-api) - - [`GET /api/alerts/alert/{id}/state`: Get alert state](#get-apialertidstate-get-alert-state) - - [`GET /api/alerts/alert/{id}/_instance_summary`: Get alert instance summary](#get-apialertidstate-get-alert-instance-summary) - - [`POST /api/alerts/alert/{id}/_update_api_key`: Update alert API key](#post-apialertidupdateapikey-update-alert-api-key) - - [Alert instance factory](#alert-instance-factory) - - [Templating actions](#templating-actions) + - [Alerting Navigation](#alert-navigation) + - [Internal HTTP APIs](#internal-http-apis) + - [`GET /internal/alerting/rule/{id}/state`: Get rule state](#get-internalalertingruleidstate-get-rule-state) + - [`GET /internal/alerting/rule/{id}/_alert_summary`: Get rule alert summary](#get-internalalertingruleidalertsummary-get-rule-alert-summary) + - [`POST /internal/alerting/rule/{id}/_update_api_key`: Update rule API key](#post-internalalertingruleidupdateapikey-update-rule-api-key) + - [Alert Factory](#alert-factory) + - [Templating Actions](#templating-actions) - [Examples](#examples) - ## Terminology -**Alert Type**: A function that takes parameters and executes actions to alert instances. +> Disclaimer: We are actively working to update the terminology of the Alerting Framework. While all user-facing terminology has been updated, much of the codebase is still a work in progress. + + +> References to `rule` and `rule type` entities are still named `AlertType` within the codebase. -**Alert**: A configuration that defines a schedule, an alert type w/ parameters, state information and actions. +> References to `alert` and `alert factory` entities are still named `AlertInstance` and `alertInstanceFactory` within the codebase. -**Alert Instance**: The instance(s) created from an alert type execution. +**Rule Type**: A function that takes parameters and executes actions on alerts. -A Kibana alert detects a condition and executes one or more actions when that condition occurs. Alerts work by going through the followings steps: +**Rule**: A configuration that defines a schedule, a rule type w/ parameters, state information and actions. -1. Run a periodic check to detect a condition (the check is provided by an Alert Type) -2. Convert that condition into one or more stateful Alert Instances -3. Map Alert Instances to pre-defined Actions, using templating -4. Execute the Actions +**Alert**: The alert(s) created from a rule execution. + +A Kibana rule detects a condition and executes one or more actions when that condition occurs. Rules work by going through the followings steps: + +1. Run a periodic check to detect a condition (the check is provided by a rule type). +2. Convert that condition into one or more stateful alerts. +3. Map alerts to pre-defined actions, using templating. +4. Execute the actions. ## Usage -1. Develop and register an alert type (see alert types -> example). -2. Configure feature level privileges using RBAC -3. Create an alert using the RESTful API [Documentation](https://www.elastic.co/guide/en/kibana/master/alerts-api-update.html) (see alerts -> create). +1. Develop and register a rule type (see rule types -> example). +2. Configure feature level privileges using RBAC. +3. Create a rule using the RESTful API [Documentation](https://www.elastic.co/guide/en/kibana/master/alerting-apis.html) (see rules -> create). + +## Alerting API Keys -## Alerts API keys +When we create a rule, we generate a new API key. -When we create an alert, we generate a new API key. +When we update, enable, or disable a rule, we must invalidate the old API key and create a new one. -When we update, enable, or disable an alert, we must invalidate the old API key and create a new one. +To manage the invalidation process for API keys, we use the saved object type `api_key_pending_invalidation`. This saved object stores all API keys that were marked for invalidation anytime rules were updated, enabled or disabled. + +For security plugin invalidation, we schedule a task to check if the `api_key_pending_invalidation` saved object contains new API keys that were marked for invalidation earlier than the configured delay. The default schedule for running this task is every 5 minutes. -To manage the invalidation process for API keys, we use the saved object `api_key_pending_invalidation`. This object stores all API keys that were marked for invalidation when alerts were updated. -For security plugin invalidation, we schedule a task to check if the`api_key_pending_invalidation` saved object contains new API keys that are marked for invalidation earlier than the configured delay. The default value for running the task is 5 mins. To change the schedule for the invalidation task, use the kibana.yml configuration option `xpack.alerting.invalidateApiKeysTask.interval`. + To change the default delay for the API key invalidation, use the kibana.yml configuration option `xpack.alerting.invalidateApiKeysTask.removalDelay`. -## Plugin status +## Plugin Status -The plugin status of an alert is customized by including information about checking failures for the framework decryption: -``` +The plugin status of the Alerting Framework is customized by including information about checking for failures during framework decryption: + +```js core.status.set( combineLatest([ core.status.derivedStatus$, @@ -85,9 +95,10 @@ core.status.set( ) ); ``` + To check for framework decryption failures, we use the task `alerting_health_check`, which runs every 60 minutes by default. To change the default schedule, use the kibana.yml configuration option `xpack.alerting.healthCheck.interval`. -## Alert types +## Rule Types ### Methods @@ -97,44 +108,59 @@ The following table describes the properties of the `options` object. |Property|Description|Type| |---|---|---| -|id|Unique identifier for the alert type. For convention purposes, ids starting with `.` are reserved for built in alert types. We recommend using a convention like `.mySpecialAlert` for your alert types to avoid conflicting with another plugin.|string| -|name|A user-friendly name for the alert type. These will be displayed in dropdowns when choosing alert types.|string| -|actionGroups|An explicit list of groups the alert type may schedule actions for, each specifying the ActionGroup's unique ID and human readable name. Alert `actions` validation will use this configuartion to ensure groups are valid. We highly encourage using `kbn-i18n` to translate the names of actionGroup when registering the AlertType. |Array<{id:string, name:string}>| -|defaultActionGroupId|Default ID value for the group of the alert type.|string| -|recoveryActionGroup|An action group to use when an alert instance goes from an active state, to an inactive one. This action group should not be specified under the `actionGroups` property. If no recoveryActionGroup is specified, the default `recovered` action group will be used. |{id:string, name:string}| -|actionVariables|An explicit list of action variables the alert type makes available via context and state in action parameter templates, and a short human readable description. Alert UI will use this to display prompts for the users for these variables, in action parameter editors. We highly encourage using `kbn-i18n` to translate the descriptions. |{ context: Array<{name:string, description:string}, state: Array<{name:string, description:string}>| -|validate.params|When developing an alert type, you can choose to accept a series of parameters. You may also have the parameters validated before they are passed to the `executor` function or created as an alert saved object. In order to do this, provide a `@kbn/config-schema` schema that we will use to validate the `params` attribute.|@kbn/config-schema| -|executor|This is where the code of the alert type lives. This is a function to be called when executing an alert on an interval basis. For full details, see executor section below.|Function| -|producer|The id of the application producing this alert type.|string| -|minimumLicenseRequired|The value of a minimum license. Most of the alerts are licensed as "basic".|string| +|id|Unique identifier for the rule type. By convention, IDs starting with `.` are reserved for built-in rule types. We recommend using a convention like `.mySpecialRule` for your rule types to avoid conflicting with another plugin.|string| +|name|A user-friendly name for the rule type. These will be displayed in dropdowns when choosing rule types.|string| +|actionGroups|An explicit list of groups the rule type may schedule actions for, each specifying the ActionGroup's unique ID and human readable name. Each rule type's `actions` validation will use this list to ensure configured groups are valid. We highly encourage using `kbn-i18n` to translate the names of actionGroup when registering the rule type. |Array<{id:string, name:string}>| +|defaultActionGroupId|ID value for the default action group for the rule type.|string| +|recoveryActionGroup|The action group to use when an alert goes from an active state to an inactive one. This action group should not be specified under the `actionGroups` property. If no recoveryActionGroup is specified, the default `recovered` action group will be used. |{id:string, name:string}| +|actionVariables|An explicit list of action variables that the rule type makes available via context and state in action parameter templates, and a short human readable description for each. The Alerting UI will use this to display prompts for the users for these variables, in action parameter editors. We highly encourage using `kbn-i18n` to translate the descriptions. |{ context: Array<{name:string, description:string}, state: Array<{name:string, description:string}>| +|validate.params|When developing a rule type, you can choose to accept a series of parameters. You may also choose to have the parameters validated before they are passed to the `executor` function or created as a saved object. In order to do this, provide a `@kbn/config-schema` schema that we will use to validate the `params` attribute.|@kbn/config-schema| +|executor|This is where the code for the rule type lives. This is a function to be called when executing a rule on an interval basis. For full details, see the executor section below.|Function| +|producer|The id of the application producing this rule type.|string| +|minimumLicenseRequired|The value of a minimum license. Most of the rules are licensed as "basic".|string| ### Executor -This is the primary function for an alert type. Whenever the alert needs to execute, this function will perform the execution. It receives a variety of parameters. The following table describes the properties the executor receives. +This is the primary function for a rule type. Whenever the rule needs to execute, this function will perform the execution. It receives a variety of parameters. The following table describes the properties the executor receives. **executor(options)** |Property|Description| |---|---| |services.scopedClusterClient|This is an instance of the Elasticsearch client. Use this to do Elasticsearch queries in the context of the user who created the alert when security is enabled.| -|services.savedObjectsClient|This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

The scope of the saved objects client is tied to the user who created the alert (only when security isenabled).| -|services.alertInstanceFactory(id)|This [alert instance factory](#alert-instance-factory) creates instances of alerts and must be used in order to execute actions. The id you give to the alert instance factory is a unique identifier to the alert instance.| +|services.savedObjectsClient|This is an instance of the saved objects client. This provides the ability to perform CRUD operations on any saved object that lives in the same space as the rule.

The scope of the saved objects client is tied to the user who created the rule (only when security is enabled).| +|services.alertInstanceFactory(id)|This [alert factory](#alert-factory) creates alerts and must be used in order to execute actions. The id you give to the alert factory is a unique identifier for the alert.| |services.log(tags, [data], [timestamp])|Use this to create server logs. (This is the same function as server.log)| -|startedAt|The date and time the alert type started execution.| -|previousStartedAt|The previous date and time the alert type started a successful execution.| -|params|Parameters for the execution. This is where the parameters you require will be passed in. (example threshold). Use alert type validation to ensure values are set before execution.| -|state|State returned from previous execution. This is the alert level state. What the executor returns will be serialized and provided here at the next execution.| -|alertId|The id of this alert.| -|spaceId|The id of the space of this alert.| -|namespace|The namespace of the space of this alert; same as spaceId, unless spaceId === 'default', then namespace = undefined.| -|name|The name of this alert.| -|tags|The tags associated with this alert.| -|createdBy|The userid that created this alert.| -|updatedBy|The userid that last updated this alert.| +|startedAt|The date and time the rule type started execution.| +|previousStartedAt|The previous date and time the rule type started a successful execution.| +|params|Parameters for the execution. This is where the parameters you require will be passed in. (e.g. threshold). Use rule type validation to ensure values are set before execution.| +|state|State returned from the previous execution. This is the rule level state. What the executor returns will be serialized and provided here at the next execution.| +|alertId|The id of this rule.| +|spaceId|The id of the space of this rule.| +|namespace|The namespace of the space of this rule. This is the same as `spaceId`, unless `spaceId === "default"`, in which case the namespace = `undefined`.| +|name|The name of this rule. This will eventually be removed in favor of `rule.name`.| +|tags|The tags associated with this rule. This will eventually be removed in favor of `rule.tags`.| +|createdBy|The user ID of the user that created this rule. This will eventually be removed in favor of `rule.createdBy`.| +|updatedBy|The user ID of the user that last updated this rule. This will eventually be removed in favor of `rule.updatedBy`.| +|rule.name|The name of this rule.| +|rule.tags|The tags associated with this rule.| +|rule.consumer|The consumer of this rule type.| +|rule.producer|The producer of this rule type.| +|rule.ruleTypeId|The ID of the rule type for this rule.| +|rule.ruleTypeName|The user-friendly name of the rule type for this rule.| +|rule.enabled|Whether this rule is currently enabled.| +|rule.schedule|The configured schedule interval of this rule.| +|rule.actions|The configured actions for this rule.| +|rule.createdBy|The user ID of the user that created this rule.| +|rule.updatedBy|The user ID of the user that last updated this rule.| +|rule.createdAt|The date and time this rule was created.| +|rule.updatedAt|The date and this this rule was last updated.| +|rule.throttle|The configured throttle interval for this rule.| +|rule.notifyWhen|The configured notification type for this rule.| ### Action Variables -The `actionVariables` property should contain the **flattened** names of the state and context variables available when an executor calls `alertInstance.scheduleActions(actionGroup, context)`. These names are meant to be used in prompters in the alerting user interface, are used as text values for display, and can be inserted into to an action parameter text entry field via UI gesture (eg, clicking a menu item from a menu built with these names). They should be flattened, so if a state or context variable is an object with properties, these should be listed with the "parent" property/properties in the name, separated by a `.` (period). +The `actionVariables` property should contain the **flattened** names of the state and context variables available when an executor calls `alertInstance.scheduleActions(actionGroup, context)`. These names are meant to be used in prompters in the Alerting UI, are used as text values for display, and can be inserted into to an action parameter text entry field via a UI gesture (e.g., clicking a menu item from a menu built with these names). They should be flattened, so if a state or context variable is an object with properties, these should be listed with the "parent" property/properties in the name, separated by a `.` (period). For example, if the `context` has one variable `foo` which is an object that has one property `bar`, and there are no `state` variables, the `actionVariables` value would be in the following shape: @@ -148,65 +174,67 @@ For example, if the `context` has one variable `foo` which is an object that has ## Licensing -Currently most of the alerts are free features. But some alert types are subscription features, such as the tracking containment alert. +Currently most rule types are free features. But some rule types are subscription features, such as the tracking containment rule. ## Documentation -You should create asciidoc for the new alert type. -* For stack alerts, add an entry to the alert type index - [`docs/user/alerting/alert-types.asciidoc`](../../../docs/user/alerting/alert-types.asciidoc) which points to a new document for the alert type that should be in the directory [`docs/user/alerting/stack-alerts`](../../../docs/user/alerting/stack-alerts). +You should create asciidoc for each new rule type you develop: -* Solution specific alert documentation should live within the docs for the solution. +- For stack rules, add an entry to the rule type index - [`docs/user/alerting/stack-rules.asciidoc`](../../../docs/user/alerting/stack-rules.asciidoc) which points to a new document for the rule type that should live in the directory [`docs/user/alerting/stack-rules`](../../../docs/user/alerting/stack-rules). -We suggest following the template provided in `docs/alert-type-template.asciidoc`. The [Index Threshold alert type](https://www.elastic.co/guide/en/kibana/master/alert-type-index-threshold.html) is an example of documentation created following the template. +- Solution specific rule documentation should live within the docs for the solution. + +We suggest following the template provided in `docs/rule-type-template.asciidoc`. The [Index Threshold rule type](https://www.elastic.co/guide/en/kibana/master/rule-type-index-threshold.html) is an example of documentation created following the template. ## Tests -The alert type should have jest tests and optionaly functional tests. -In the the tests we recomend to test the expected alert execution result with a different input params, the structure of the created alert and the params validation. The rest will be guaranteed as a framework functionality. +The rule type should have jest tests and, optionally, functional tests. +In the tests, we recommend testing the expected rule execution result with different input params, testing the structure of the created rule and testing the parameter validation. The rest will be guaranteed as a framework functionality. ### Example -This example receives server and threshold as parameters. It will read the CPU usage of the server and schedule actions to be executed (asynchronously by the task manager) if the reading is greater than the threshold. +This example rule type receives server and threshold as parameters. It will read the CPU usage of the server and schedule actions to be executed (asynchronously by the task manager) if the usage is greater than the threshold. ```typescript import { schema } from '@kbn/config-schema'; import { AlertType, AlertExecutorOptions } from '../../../alerting/server'; +// These type names will eventually be updated to reflect the new terminology import { - AlertTypeParams, - AlertTypeState, - AlertInstanceState, - AlertInstanceContext, + AlertTypeParams, + AlertTypeState, + AlertInstanceState, + AlertInstanceContext, } from '../../../alerting/common'; ... -interface MyAlertTypeParams extends AlertTypeParams { +interface MyRuleTypeParams extends AlertTypeParams { server: string; threshold: number; } -interface MyAlertTypeState extends AlertTypeState { +interface MyRuleTypeState extends AlertTypeState { lastChecked: Date; } -interface MyAlertTypeInstanceState extends AlertInstanceState { +interface MyRuleTypeAlertState extends AlertInstanceState { cpuUsage: number; } -interface MyAlertTypeInstanceContext extends AlertInstanceContext { +interface MyRuleTypeAlertContext extends AlertInstanceContext { server: string; hasCpuUsageIncreased: boolean; } -type MyAlertTypeActionGroups = 'default' | 'warning'; +type MyRuleTypeActionGroups = 'default' | 'warning'; -const myAlertType: AlertType< - MyAlertTypeParams, - MyAlertTypeState, - MyAlertTypeInstanceState, - MyAlertTypeInstanceContext, - MyAlertTypeActionGroups +const myRuleType: AlertType< + MyRuleTypeParams, + MyRuleTypeState, + MyRuleTypeAlertState, + MyRuleTypeAlertContext, + MyRuleTypeActionGroups > = { - id: 'my-alert-type', - name: 'My alert type', + id: 'my-rule-type', + name: 'My rule type', validate: { params: schema.object({ server: schema.string(), @@ -235,13 +263,20 @@ const myAlertType: AlertType< }, minimumLicenseRequired: 'basic', async executor({ - alertId, + alertId, startedAt, previousStartedAt, services, params, state, - }: AlertExecutorOptions) { + rule, + }: AlertExecutorOptions< + MyRuleTypeParams, + MyRuleTypeState, + MyRuleTypeAlertState, + MyRuleTypeAlertContext, + MyRuleTypeActionGroups + >) { // Let's assume params is { server: 'server_1', threshold: 0.8 } const { server, threshold } = params; @@ -250,47 +285,50 @@ const myAlertType: AlertType< // Only execute if CPU usage is greater than threshold if (currentCpuUsage > threshold) { - // The first argument is a unique identifier the alert instance is about. In this scenario - // the provided server will be used. Also, this id will be used to make `getState()` return - // previous state, if any, on matching identifiers. - const alertInstance = services.alertInstanceFactory(server); + // The first argument is a unique identifier for the alert. In this + // scenario the provided server will be used. Also, this ID will be + // used to make `getState()` return previous state, if any, on + // matching identifiers. + const alert = services.alertInstanceFactory(server); - // State from last execution. This will exist if an alert instance was created and executed - // in the previous execution - const { cpuUsage: previousCpuUsage } = alertInstance.getState(); + // State from the last execution. This will exist if an alert was + // created and executed in the previous execution + const { cpuUsage: previousCpuUsage } = alert.getState(); // Replace state entirely with new values - alertInstance.replaceState({ + alert.replaceState({ cpuUsage: currentCpuUsage, }); - // 'default' refers to the id of a group of actions to be scheduled for execution, see 'actions' in create alert section - alertInstance.scheduleActions('default', { + // 'default' refers to the id of a group of actions to be scheduled + // for execution, see 'actions' in create rule section + alert.scheduleActions('default', { server, hasCpuUsageIncreased: currentCpuUsage > previousCpuUsage, }); } - // Returning updated alert type level state, this will become available + // Returning updated rule type level state, this will become available // within the `state` function parameter at the next execution return { - // This is an example attribute you could set, it makes more sense to use this state when - // the alert type executes multiple instances but wants a single place to track certain values. + // This is an example attribute you could set, it makes more sense + // to use this state when the rule type executes multiple + // alerts but wants a single place to track certain values. lastChecked: new Date(), }; }, producer: 'alerting', }; -server.newPlatform.setup.plugins.alerting.registerType(myAlertType); +server.newPlatform.setup.plugins.alerting.registerType(myRuleType); ``` ## Role Based Access-Control -Once you have registered your AlertType, you need to grant your users privileges to use it. -When registering a feature in Kibana you can specify multiple types of privileges which are granted to users when they're assigned certain roles. +Once you have registered your AlertType, you need to grant your users privileges to use it. +When registering a feature in Kibana, you can specify multiple types of privileges which are granted to users when they're assigned certain roles. Assuming your feature introduces its own AlertTypes, you'll want to control which roles have all/read privileges for these AlertTypes when they're inside the feature. -In addition, when users are inside your feature you might want to grant them access to AlertTypes from other features, such as built-in AlertTypes or AlertTypes provided by other features. +In addition, when users are inside your feature, you might want to grant them access to AlertTypes from other features, such as built-in stack rules or rule types provided by other features. You can control all of these abilities by assigning privileges to the Alerting Framework from within your own feature, for example: @@ -304,11 +342,11 @@ features.registerKibanaFeature({ alerting: { all: [ // grant `all` over our own types - 'my-application-id.my-alert-type', - 'my-application-id.my-restricted-alert-type', + 'my-application-id.my-rule-type', + 'my-application-id.my-restricted-rule-type', // grant `all` over the built-in IndexThreshold '.index-threshold', - // grant `all` over Uptime's TLS AlertType + // grant `all` over Uptime's TLS rule type 'xpack.uptime.alerts.actionGroups.tls' ], }, @@ -317,10 +355,10 @@ features.registerKibanaFeature({ alerting: { read: [ // grant `read` over our own type - 'my-application-id.my-alert-type', + 'my-application-id.my-rule-type', // grant `read` over the built-in IndexThreshold '.index-threshold', - // grant `read` over Uptime's TLS AlertType + // grant `read` over Uptime's TLS rule type 'xpack.uptime.alerts.actionGroups.tls' ], }, @@ -330,11 +368,12 @@ features.registerKibanaFeature({ ``` In this example we can see the following: -- Our feature grants any user who's assigned the `all` role in our feature the `all` role in the Alerting framework over every alert of the `my-application-id.my-alert-type` type which is created _inside_ the feature. What that means is that this privilege will allow the user to execute any of the `all` operations (listed below) on these alerts as long as their `consumer` is `my-application-id`. Below that you'll notice we've done the same with the `read` role, which is grants the Alerting Framework's `read` role privileges over these very same alerts. -- In addition, our feature grants the same privileges over any alert of type `my-application-id.my-restricted-alert-type`, which is another hypothetical alertType registered by this feature. It's worth noting though that this type has been omitted from the `read` role. What this means is that only users with the `all` role will be able to interact with alerts of this type. -- Next, lets look at the `.index-threshold` and `xpack.uptime.alerts.actionGroups.tls` types. These have been specified in both `read` and `all`, which means that all the users in the feature will gain privileges over alerts of these types (as long as their `consumer` is `my-application-id`). The difference between these two and the previous two is that they are _produced_ by other features! `.index-threshold` is a built-in type, provided by the _Built-In Alerts_ feature, and `xpack.uptime.alerts.actionGroups.tls` is an AlertType provided by the _Uptime_ feature. Specifying these type here tells the Alerting Framework that as far as the `my-application-id` feature is concerned, the user is privileged to use them (with `all` and `read` applied), but that isn't enough. Using another feature's AlertType is only possible if both the producer of the AlertType, and the consumer of the AlertType, explicitly grant privileges to do so. In this case, the _Built-In Alerts_ & _Uptime_ features would have to explicitly add these privileges to a role and this role would have to be granted to this user. -It's important to note that any role can be granted a mix of `all` and `read` privileges accross multiple type, for example: +- Our feature grants any user who's assigned the `all` role in our feature the `all` role in the Alerting framework over every rule of the `my-application-id.my-rule-type` type which is created _inside_ the feature. What that means is that this privilege will allow the user to execute any of the `all` operations (listed below) on these rules as long as their `consumer` is `my-application-id`. Below that you'll notice we've done the same with the `read` role, which grants the Alerting Framework's `read` role privileges over these very same rules. +- In addition, our feature grants the same privileges over any rule of type `my-application-id.my-restricted-rule-type`, which is another hypothetical rule type registered by this feature. It's worth noting that this type has been omitted from the `read` role. What this means is that only users with the `all` role will be able to interact with rules of this type. +- Next, lets look at the `.index-threshold` and `xpack.uptime.alerts.actionGroups.tls` types. These have been specified in both `read` and `all`, which means that all the users in the feature will gain privileges over rules of these types (as long as their `consumer` is `my-application-id`). The difference between these two and the previous two is that they are _produced_ by other features! `.index-threshold` is a built-in stack rule type, provided by the _Stack Rules_ feature, and `xpack.uptime.alerts.actionGroups.tls` is a rule type provided by the _Uptime_ feature. Specifying these types here tells the Alerting Framework that as far as the `my-application-id` feature is concerned, the user is privileged to use them (with `all` and `read` applied), but that isn't enough. Using another feature's rule type is only possible if both the producer of the rule type and the consumer of the rule type explicitly grant privileges to do so. In this case, the _Stack Rules_ & _Uptime_ features would have to explicitly add these privileges to a role and this role would have to be granted to this user. + +It's important to note that any role can be granted a mix of `all` and `read` privileges accross multiple types, for example: ```typescript features.registerKibanaFeature({ @@ -355,10 +394,10 @@ features.registerKibanaFeature({ app: ['lens', 'kibana'], alerting: { all: [ - 'my-application-id.my-alert-type' + 'my-application-id.my-rule-type' ], read: [ - 'my-application-id.my-restricted-alert-type' + 'my-application-id.my-restricted-rule-type' ], }, savedObject: { @@ -372,16 +411,19 @@ features.registerKibanaFeature({ }); ``` -In the above example, you note that instead of denying users with the `read` role any access to the `my-application-id.my-restricted-alert-type` type, we've decided that these users _should_ be granted `read` privileges over the _resitricted_ AlertType. -As part of that same change, we also decided that not only should they be allowed to `read` the _restricted_ AlertType, but actually, despite having `read` privileges to the feature as a whole, we do actually want to allow them to create our basic 'my-application-id.my-alert-type' AlertType, as we consider it an extension of _reading_ data in our feature, rather than _writing_ it. +In the above example, note that instead of denying users with the `read` role any access to the `my-application-id.my-restricted-rule-type` type, we've decided that these users _should_ be granted `read` privileges over the _restricted_ rule type. +As part of that same change, we also decided that not only should they be allowed to `read` the _restricted_ rule type, but actually, despite having `read` privileges to the feature as a whole, we do actually want to allow them to create our basic 'my-application-id.my-rule-type' rule type, as we consider it an extension of _reading_ data in our feature, rather than _writing_ it. ### `read` privileges vs. `all` privileges When a user is granted the `read` role in the Alerting Framework, they will be able to execute the following api calls: + - `get` -- `getAlertState` +- `getRuleState` +- `getAlertSummary` - `find` When a user is granted the `all` role in the Alerting Framework, they will be able to execute all of the `read` privileged api calls, but in addition they'll be granted the following calls: + - `create` - `delete` - `update` @@ -390,24 +432,26 @@ When a user is granted the `all` role in the Alerting Framework, they will be ab - `updateApiKey` - `muteAll` - `unmuteAll` -- `muteInstance` -- `unmuteInstance` +- `muteAlert` +- `unmuteAlert` Finally, all users, whether they're granted any role or not, are privileged to call the following: -- `listAlertTypes`, but the output is limited to displaying the AlertTypes the user is perivileged to `get` + +- `listAlertTypes`, but the output is limited to displaying the rule types the user is privileged to `get`. Attempting to execute any operation the user isn't privileged to execute will result in an Authorization error thrown by the AlertsClient. ## Alert Navigation -When registering an Alert Type, you'll likely want to provide a way of viewing alerts of that type within your own plugin, or perhaps you want to provide a view for all alerts created from within your solution within your own UI. -In order for the Alerting framework to know that your plugin has its own internal view for displaying an alert, you must resigter a navigation handler within the framework. +When registering a rule type, you'll likely want to provide a way of viewing rules of that type within your own plugin, or perhaps you want to provide a view for all rules created from within your solution within your own UI. + +In order for the Alerting Framework to know that your plugin has its own internal view for displaying a rule, you must register a navigation handler within the framework. -A navigation handler is nothing more than a function that receives an Alert and its corresponding AlertType, and is expected to then return the path *within your plugin* which knows how to display this alert. +A navigation handler is nothing more than a function that receives a rule and its corresponding AlertType, and is expected to then return the path *within your plugin* which knows how to display this rule. The signature of such a handler is: -``` +```typescript type AlertNavigationHandler = ( alert: SanitizedAlert, alertType: AlertType @@ -420,43 +464,43 @@ By specifying _alerting_ as a dependency of your *public* (client side) plugin, ### registerNavigation The _registerNavigation_ api allows you to register a handler for a specific alert type within your solution: -``` +```typescript alerting.registerNavigation( 'my-application-id', - 'my-application-id.my-alert-type', - (alert: SanitizedAlert, alertType: AlertType) => `/my-unique-alert/${alert.id}` + 'my-application-id.my-rule-type', + (alert: SanitizedAlert, alertType: AlertType) => `/my-unique-rule/${rule.id}` ); ``` -This tells the Alerting framework that, given an alert of the AlertType whose ID is `my-application-id.my-unique-alert-type`, if that Alert's `consumer` value (which is set when the alert is created by your plugin) is your application (whose id is `my-application-id`), then it will navigate to your application using the path `/my-unique-alert/${the id of the alert}`. +This tells the Alerting Framework that, given a rule of the AlertType whose ID is `my-application-id.my-unique-rule-type`, if that rule's `consumer` value (which is set when the rule is created by your plugin) is your application (whose id is `my-application-id`), then it will navigate to your application using the path `/my-unique-rule/${the id of the rule}`. -The navigation is handled using the `navigateToApp` api, meaning that the path will be automatically picked up by your `react-router-dom` **Route** component, so all you have top do is configure a Route that handles the path `/my-unique-alert/:id`. +The navigation is handled using the `navigateToApp` API, meaning that the path will be automatically picked up by your `react-router-dom` **Route** component, so all you have top do is configure a Route that handles the path `/my-unique-rule/:id`. You can look at the `alerting-example` plugin to see an example of using this API, which is enabled using the `--run-examples` flag when you run `yarn start`. ### registerDefaultNavigation -The _registerDefaultNavigation_ api allows you to register a handler for any alert type within your solution: +The _registerDefaultNavigation_ API allows you to register a handler for any rule type within your solution: ``` alerting.registerDefaultNavigation( 'my-application-id', - (alert: SanitizedAlert, alertType: AlertType) => `/my-other-alerts/${alert.id}` + (alert: SanitizedAlert, alertType: AlertType) => `/my-other-rules/${rule.id}` ); ``` -This tells the Alerting framework that, given any alert whose `consumer` value is your application, as long as then it will navigate to your application using the path `/my-other-alerts/${the id of the alert}`. +This tells the Alerting Framework that any rule whose `consumer` value is your application can be navigated to in your application using the path `/my-other-rules/${the id of the rule}`. -### balancing both APIs side by side -As we mentioned, using `registerDefaultNavigation` will tell the Alerting Framework that your application can handle any type of Alert we throw at it, as long as your application created it, using the handler you provide it. +### Balancing both APIs side by side +As we mentioned, using `registerDefaultNavigation` will tell the Alerting Framework that your application can handle any type of rule we throw at it, as long as your application created it, using the handler you provided. -The only case in which this handler will not be used to evaluate the navigation for an alert (assuming your application is the `consumer`) is if you have also used `registerNavigation` api, along side your `registerDefaultNavigation` usage, to handle that alert's specific AlertType. +The only case in which this handler will not be used to evaluate the navigation for a rule (assuming your application is the `consumer`) is if you have also used the `registerNavigation` API, alongside your `registerDefaultNavigation` usage, to handle that rule's specific AlertType. -You can use the `registerNavigation` api to specify as many AlertType specific handlers as you like, but you can only use it once per AlertType as we wouldn't know which handler to use if you specified two for the same AlertType. For the same reason, you can only use `registerDefaultNavigation` once per plugin, as it covers all cases for your specific plugin. +You can use the `registerNavigation` API to specify as many AlertType specific handlers as you like, but you can only use it once per AlertType as we wouldn't know which handler to use if you specified two for the same AlertType. For the same reason, you can only use `registerDefaultNavigation` once per plugin, as it covers all cases for your specific plugin. ## Internal HTTP APIs -Using of the rule type requires you to create a rule that will contain parameters and actions for a given rule type. API description for CRUD operations is a part of the [user documentation](https://www.elastic.co/guide/en/kibana/master/alerting-apis.html). -API listed below are internal and should not be consumed by plugin outside the alerting plugins. +We provide public APIs for performing CRUD operations on rules. Descriptions for these APIs are available in the [user documentation](https://www.elastic.co/guide/en/kibana/master/alerting-apis.html). +In addition to the public APIs, we provide the following internal APIs. Internal APIs should not be consumed by plugins outside of the alerting plugins. ### `GET /internal/alerting/rule/{id}/state`: Get rule state @@ -489,56 +533,56 @@ Query: |---|---|---| |id|The id of the rule you're trying to update the API key for. System will use user in request context to generate an API key for.|string| -## Alert instance factory +## Alert Factory **alertInstanceFactory(id)** -One service passed in to alert types is an alert instance factory. This factory creates instances of alerts and must be used in order to execute actions. The `id` you give to the alert instance factory is a unique identifier to the alert instance (ex: server identifier if the instance is about the server). The instance factory will use this identifier to retrieve the state of previous instances with the same `id`. These instances support state persisting between alert type execution, but will clear out once the alert instance stops executing. +One service passed in to each rule type is the alert factory. This factory creates alerts and must be used in order to execute actions. The `id` you give to the alert factory is the unique identifier for the alert (e.g. the server identifier if the alert is about servers). The alert factory will use this identifier to retrieve the state of previous alerts with the same `id`. These alerts support persisting state between rule executions, but will clear out once the alert stops firing. -Note that the `id` only needs to be unique **within the scope of a specific alert**, not unique across all alerts or alert types. For example, Alert 1 and Alert 2 can both create an alert instance with an `id` of `"a"` without conflicting with one another. But if Alert 1 creates 2 alert instances, then they must be differentiated with `id`s of `"a"` and `"b"`. +Note that the `id` only needs to be unique **within the scope of a specific rule**, not unique across all rules or rule types. For example, Rule 1 and Rule 2 can both create an alert with an `id` of `"a"` without conflicting with one another. But if Rule 1 creates 2 alerts, then they must be differentiated with `id`s of `"a"` and `"b"`. -This factory returns an instance of `AlertInstance`. The alert instance class has the following methods, note that we have removed the methods that you shouldn't touch. +This factory returns an instance of `AlertInstance`. The `AlertInstance` class has the following methods. Note that we have removed the methods that you shouldn't touch. |Method|Description| |---|---| -|getState()|Get the current state of the alert instance.| -|scheduleActions(actionGroup, context)|Called to schedule the execution of actions. The actionGroup is a string `id` that relates to the group of alert `actions` to execute and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert instance.| -|scheduleActionsWithSubGroup(actionGroup, subgroup, context)|Called to schedule the execution of actions within a subgroup. The actionGroup is a string `id` that relates to the group of alert `actions` to execute, the `subgroup` is a dynamic string that denotes a subgroup within the actionGroup and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert instance.| -|replaceState(state)|Used to replace the current state of the alert instance. This doesn't work like react, the entire state must be provided. Use this feature as you see fit. The state that is set will persist between alert type executions whenever you re-create an alert instance with the same id. The instance state will be erased when `scheduleActions` or `scheduleActionsWithSubGroup` aren't called during an execution.| +|getState()|Get the current state of the alert.| +|scheduleActions(actionGroup, context)|Call this to schedule the execution of actions. The actionGroup is a string `id` that relates to the group of alert `actions` to execute and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert.| +|scheduleActionsWithSubGroup(actionGroup, subgroup, context)|Call this to schedule the execution of actions within a subgroup. The actionGroup is a string `id` that relates to the group of alert `actions` to execute, the `subgroup` is a dynamic string that denotes a subgroup within the actionGroup and the context will be used for templating purposes. `scheduleActions` or `scheduleActionsWithSubGroup` should only be called once per alert.| +|replaceState(state)|Used to replace the current state of the alert. This doesn't work like React, the entire state must be provided. Use this feature as you see fit. The state that is set will persist between rule executions whenever you re-create an alert with the same id. The alert state will be erased when `scheduleActions` or `scheduleActionsWithSubGroup` aren't called during an execution.| -### when should I use `scheduleActions` and `scheduleActionsWithSubGroup`? +### When should I use `scheduleActions` and `scheduleActionsWithSubGroup`? The `scheduleActions` or `scheduleActionsWithSubGroup` methods are both used to achieve the same thing: schedule actions to be run under a specific action group. -It's important to note though, that when an actions are scheduled for an instance, we check whether the instance was already active in this action group after the previous execution. If it was, then we might throttle the actions (adhering to the user's configuration), as we don't consider this a change in the instance. +It's important to note that when actions are scheduled for an alert, we check whether the alert was already active in this action group after the previous execution. If it was, then we might throttle the actions (adhering to the user's configuration), as we don't consider this a change in the alert. -What happens though, if the instance _has_ changed, but they just happen to be in the same action group after this change? This is where subgroups come in. By specifying a subgroup (using the `scheduleActionsWithSubGroup` method), the instance becomes active within the action group, but it will also keep track of the subgroup. -If the subgroup changes, then the framework will treat the instance as if it had been placed in a new action group. It is important to note though, we only use the subgroup to denote a change if both the current execution and the previous one specified a subgroup. +What happens though, if the alert _has_ changed, but they just happen to be in the same action group after this change? This is where subgroups come in. By specifying a subgroup (using the `scheduleActionsWithSubGroup` method), the alert becomes active within the action group, but it will also keep track of the subgroup. +If the subgroup changes, then the framework will treat the alert as if it had been placed in a new action group. It is important to note that we only use the subgroup to denote a change if both the current execution and the previous one specified a subgroup. You might wonder, why bother using a subgroup if you can just add a new action group? -Action Groups are static, and have to be define when the Alert Type is defined. +Action Groups are static, and have to be define when the rule type is defined. Action Subgroups are dynamic, and can be defined on the fly. This approach enables users to specify actions under specific action groups, but they can't specify actions that are specific to subgroups. As subgroups fall under action groups, we will schedule the actions specified for the action group, but the subgroup allows the AlertType implementer to reuse the same action group for multiple different active subgroups. -## Templating actions +## Templating Actions -There needs to be a way to map alert context into action parameters. For this, we started off by adding template support. Any string within the `params` of an alert saved object's `actions` will be processed as a template and can inject context or state values. +There needs to be a way to map rule context into action parameters. For this, we started off by adding template support. Any string within the `params` of a rule saved object's `actions` will be processed as a template and can inject context or state values. -When an alert instance executes, the first argument is the `group` of actions to execute and the second is the context the alert exposes to templates. We iterate through each action params attributes recursively and render templates if they are a string. Templates have access to the following "variables": +When an alert executes, the first argument is the `group` of actions to execute and the second is the context the rule exposes to templates. We iterate through each action parameter attributes recursively and render templates if they are a string. Templates have access to the following "variables": -- `context` - provided by context argument of `.scheduleActions(...)` and `.scheduleActionsWithSubGroup(...)` on an alert instance -- `state` - the alert instance's `state` provided by the most recent `replaceState` call on an alert instance -- `alertId` - the id of the alert -- `alertInstanceId` - the alert instance id -- `alertName` - the name of the alert -- `spaceId` - the id of the space the alert exists in -- `tags` - the tags set in the alert +- `context` - provided by context argument of `.scheduleActions(...)` and `.scheduleActionsWithSubGroup(...)` on an alert. +- `state` - the alert's `state` provided by the most recent `replaceState` call on an alert. +- `alertId` - the id of the rule +- `alertInstanceId` - the alert id +- `alertName` - the name of the rule +- `spaceId` - the id of the space the rule exists in +- `tags` - the tags set in the rule -The templating engine is [mustache]. General definition for the [mustache variable] is a double-brace {{}}. All variables are HTML-escaped by default and if there is a requirement to render unescaped HTML, it should be applied the triple mustache: `{{{name}}}`. Also, can be used `&` to unescape a variable. +The templating engine is [mustache]. General definition for the [mustache variable] is a double-brace {{}}. All variables are HTML-escaped by default and if there is a requirement to render unescaped HTML, it should be applied with the triple mustache: `{{{name}}}`. Also, `&` can be used to unescape a variable. ### Examples -The following code would be within an alert type. As you can see `cpuUsage ` will replace the state of the alert instance and `server` is the context for the alert instance to execute. The difference between the two is `cpuUsage ` will be accessible at the next execution. +The following code would be within a rule type. As you can see `cpuUsage` will replace the state of the alert and `server` is the context for the alert to execute. The difference between the two is that `cpuUsage` will be accessible at the next execution. ``` alertInstanceFactory('server_1') @@ -550,13 +594,13 @@ alertInstanceFactory('server_1') }); ``` -Below is an example of an alert that takes advantage of templating: +Below is an example of a rule that takes advantage of templating: ``` { ... "id": "123", - "name": "cpu alert", + "name": "cpu rule", "actions": [ { "group": "default", @@ -565,21 +609,21 @@ Below is an example of an alert that takes advantage of templating: "from": "example@elastic.co", "to": ["destination@elastic.co"], "subject": "A notification about {{context.server}}", - "body": "The server {{context.server}} has a CPU usage of {{state.cpuUsage}}%. This message for {{alertInstanceId}} was created by the alert {{alertId}} {{alertName}}." + "body": "The server {{context.server}} has a CPU usage of {{state.cpuUsage}}%. This message for {{alertInstanceId}} was created by the rule {{alertId}} {{alertName}}." } } ] } ``` -The templating system will take the alert and alert type as described above and convert the action parameters to the following: +The templating system will take the rule and rule type as described above and convert the action parameters to the following: ``` { "from": "example@elastic.co", "to": ["destination@elastic.co"], "subject": "A notification about server_1" - "body": "The server server_1 has a CPU usage of 80%. This message for server_1 was created by the alert 123 cpu alert" + "body": "The server server_1 has a CPU usage of 80%. This message for server_1 was created by the rule 123 cpu rule" } ``` From cc9c5be022b063bee777c531870336cf13dc6e73 Mon Sep 17 00:00:00 2001 From: Jen Huang Date: Mon, 24 May 2021 15:02:23 -0700 Subject: [PATCH 07/22] [Fleet] Pass policy namespace to agent monitoring settings (#100500) * Pass agent policy namespace to agent monitoring settings * Adjust copy --- x-pack/plugins/fleet/common/types/models/agent_policy.ts | 1 + .../sections/agent_policy/components/agent_policy_form.tsx | 2 +- x-pack/plugins/fleet/server/services/agent_policy.test.ts | 4 ++++ x-pack/plugins/fleet/server/services/agent_policy.ts | 1 + 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index a8e1f6ce584d4..753100f622556 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -91,6 +91,7 @@ export interface FullAgentPolicy { revision?: number; agent?: { monitoring: { + namespace?: string; use_output?: string; enabled: boolean; metrics: boolean; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx index 7bfb2961a6d65..a44edb5ce9a42 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_form.tsx @@ -223,7 +223,7 @@ export const AgentPolicyForm: React.FunctionComponent = ({ description={ } > diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index 68bd9e721d714..a020b95ca3302 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -185,6 +185,7 @@ describe('agent policy', () => { it('should return a policy with monitoring if monitoring is enabled for logs', async () => { const soClient = getSavedObjectMock({ + namespace: 'default', revision: 1, monitoring_enabled: ['logs'], }); @@ -207,6 +208,7 @@ describe('agent policy', () => { }, agent: { monitoring: { + namespace: 'default', use_output: 'default', enabled: true, logs: true, @@ -218,6 +220,7 @@ describe('agent policy', () => { it('should return a policy with monitoring if monitoring is enabled for metrics', async () => { const soClient = getSavedObjectMock({ + namespace: 'default', revision: 1, monitoring_enabled: ['metrics'], }); @@ -240,6 +243,7 @@ describe('agent policy', () => { }, agent: { monitoring: { + namespace: 'default', use_output: 'default', enabled: true, logs: false, diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index b575c1de1616d..62b4578ab87b2 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -730,6 +730,7 @@ class AgentPolicyService { ? { agent: { monitoring: { + namespace: agentPolicy.namespace, use_output: defaultOutput.name, enabled: true, logs: agentPolicy.monitoring_enabled.includes(dataTypes.Logs), From f95bbb38c9de338009a4ef25871b0ef56a754604 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Mon, 24 May 2021 17:29:27 -0500 Subject: [PATCH 08/22] [Fleet] Fix incomplete agent count message on policy tab (#100497) --- .../fleet/components/linked_agent_count.tsx | 22 +++++++++++++++---- .../agent_policy/details_page/index.tsx | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/linked_agent_count.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/linked_agent_count.tsx index e42917700284e..dddb1f6531afd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/linked_agent_count.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/linked_agent_count.tsx @@ -6,6 +6,7 @@ */ import React, { memo } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; import type { EuiLinkAnchorProps } from '@elastic/eui'; import { EuiLink } from '@elastic/eui'; @@ -16,9 +17,22 @@ import { AGENT_SAVED_OBJECT_TYPE } from '../constants'; * Displays the provided `count` number as a link to the Agents list if it is greater than zero */ export const LinkedAgentCount = memo< - Omit & { count: number; agentPolicyId: string } ->(({ count, agentPolicyId, ...otherEuiLinkProps }) => { + Omit & { + count: number; + agentPolicyId: string; + showAgentText?: boolean; + } +>(({ count, agentPolicyId, showAgentText, ...otherEuiLinkProps }) => { const { getHref } = useLink(); + const displayValue = showAgentText ? ( + + ) : ( + count + ); return count > 0 ? ( - {count} + {displayValue} ) : ( - {count} + {displayValue} ); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx index 65cf62a279a22..e96ef83224013 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/index.tsx @@ -173,6 +173,7 @@ export const AgentPolicyDetailsPage: React.FunctionComponent = () => { ), }, From 71acd98082f73aacefa830fc0d5e8f27f6460c30 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Mon, 24 May 2021 17:30:06 -0500 Subject: [PATCH 09/22] [Fleet] Add color distinction between offline and inactive agents (#100490) --- .../fleet/sections/agents/services/agent_status.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx index 02b3a941437ec..275d0c83da65e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/agent_status.tsx @@ -19,6 +19,7 @@ const colorToHexMap = { accent: visColors[2], warning: visColors[5], danger: visColors[9], + inactive: '#98A2B3', }; export const AGENT_STATUSES: SimplifiedAgentStatus[] = [ @@ -34,8 +35,9 @@ export function getColorForAgentStatus(agentStatus: SimplifiedAgentStatus): stri case 'healthy': return colorToHexMap.secondary; case 'offline': - case 'inactive': return colorToHexMap.default; + case 'inactive': + return colorToHexMap.inactive; case 'unhealthy': return colorToHexMap.warning; case 'updating': From 676d40ebbe5dc222313c5d368f5b31e6a6058ce6 Mon Sep 17 00:00:00 2001 From: Zacqary Adam Xeper Date: Mon, 24 May 2021 17:30:18 -0500 Subject: [PATCH 10/22] [Fleet] Add clear button to search input bars (#100476) --- .../fleet/public/applications/fleet/components/search_bar.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx index a5b937d4590d7..f064cf1e72f18 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/components/search_bar.tsx @@ -97,6 +97,7 @@ export const SearchBar: React.FunctionComponent = ({ onChange(newQuery.query as string, true); }} submitOnBlur + isClearable /> ); }; From aa2f5b535d0c0a7bcdaa34eb9807246d4e858f01 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Mon, 24 May 2021 18:38:14 -0600 Subject: [PATCH 11/22] [Security Solution] Utilizes constants package and deletes duplicate code (#100513) ## Summary Utilizes constants package and deletes duplicate code * Renames the `securitysolution-constants` to be `securitysolution-list-constants` to be specific * Deletes duplicated code found during cleanup * Moves more tests into the packages found along the way with the duplicated code * Moves `parseScheduleDates` from `@kbn/securitysolution-io-ts-types` to `@kbn/securitysolution-io-ts-utils` ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../monorepo-packages.asciidoc | 2 +- package.json | 2 +- packages/BUILD.bazel | 2 +- .../kbn-securitysolution-constants/README.md | 6 - .../package.json | 9 - .../src/constants/index.ts | 12 +- .../src/from/index.ts | 2 +- .../src/index.ts | 1 - .../src/common/lists/index.mock.ts | 2 +- .../src/constants/index.ts | 34 --- .../src/index.ts | 1 - .../exception_list_schema/index.mock.ts | 2 +- .../src/index.ts | 1 - .../src/index.ts | 1 + .../src/parse_schedule_dates/index.test.ts | 38 +++ .../src/parse_schedule_dates/index.ts | 0 .../kbn-securitysolution-list-api/BUILD.bazel | 1 + .../src/api/index.ts | 4 +- .../src/constants/index.ts | 39 --- .../src/list_api/index.ts | 8 +- .../BUILD.bazel | 4 +- .../README.md | 6 + .../jest.config.js | 2 +- .../package.json | 9 + .../src/index.ts | 3 - .../tsconfig.json | 2 +- .../BUILD.bazel | 2 + .../src/constants/index.ts | 34 --- .../src/index.ts | 1 - .../src/use_api/index.ts | 2 +- .../src/use_exception_list_items/index.ts | 2 +- .../src/use_exception_lists/index.ts | 2 +- .../src/utils/index.test.ts | 272 ------------------ .../src/utils/index.ts | 118 -------- .../BUILD.bazel | 1 + .../src/get_exception_list_type/index.ts | 23 ++ .../src/get_filters/index.test.ts | 117 ++++++++ .../src/get_filters/index.ts | 23 ++ .../src/get_general_filters/index.test.ts | 36 +++ .../src/get_general_filters/index.ts | 32 +++ .../src/get_ids_and_namespaces/index.test.ts | 105 +++++++ .../src/get_ids_and_namespaces/index.ts | 36 +++ .../src/get_saved_object_type/index.ts | 27 ++ .../src/get_saved_object_types/index.ts | 22 ++ .../src/get_trusted_apps_filter/index.test.ts | 39 +++ .../src/get_trusted_apps_filter/index.ts | 27 ++ .../src/index.ts | 7 + .../src/types/index.ts | 10 + x-pack/plugins/lists/common/constants.ts | 71 ----- x-pack/plugins/lists/common/index.ts | 2 - .../response/exception_list_schema.mock.ts | 12 +- x-pack/plugins/lists/common/shared_exports.ts | 19 -- x-pack/plugins/lists/common/types.ts | 27 -- .../lists/public/exceptions/utils.test.ts | 271 ----------------- .../plugins/lists/public/exceptions/utils.ts | 119 -------- .../routes/create_endpoint_list_item_route.ts | 2 +- .../routes/create_endpoint_list_route.ts | 2 +- .../create_exception_list_item_route.ts | 2 +- .../routes/create_exception_list_route.ts | 2 +- .../server/routes/create_list_index_route.ts | 2 +- .../server/routes/create_list_item_route.ts | 2 +- .../lists/server/routes/create_list_route.ts | 2 +- .../routes/delete_endpoint_list_item_route.ts | 2 +- .../delete_exception_list_item_route.ts | 2 +- .../routes/delete_exception_list_route.ts | 2 +- .../server/routes/delete_list_index_route.ts | 2 +- .../server/routes/delete_list_item_route.ts | 2 +- .../lists/server/routes/delete_list_route.ts | 4 +- .../routes/export_exception_list_route.ts | 2 +- .../server/routes/export_list_item_route.ts | 2 +- .../routes/find_endpoint_list_item_route.ts | 2 +- .../routes/find_exception_list_item_route.ts | 2 +- .../routes/find_exception_list_route.ts | 2 +- .../server/routes/find_list_item_route.ts | 2 +- .../lists/server/routes/find_list_route.ts | 2 +- .../server/routes/import_list_item_route.ts | 2 +- .../server/routes/patch_list_item_route.ts | 2 +- .../lists/server/routes/patch_list_route.ts | 2 +- .../routes/read_endpoint_list_item_route.ts | 2 +- .../routes/read_exception_list_item_route.ts | 2 +- .../routes/read_exception_list_route.ts | 2 +- .../server/routes/read_list_index_route.ts | 2 +- .../server/routes/read_list_item_route.ts | 2 +- .../lists/server/routes/read_list_route.ts | 2 +- .../server/routes/read_privileges_route.ts | 2 +- .../routes/update_endpoint_list_item_route.ts | 2 +- .../update_exception_list_item_route.ts | 2 +- .../routes/update_exception_list_route.ts | 2 +- .../server/routes/update_list_item_route.ts | 2 +- .../lists/server/routes/update_list_route.ts | 2 +- .../plugins/lists/server/routes/validate.ts | 2 +- .../server/saved_objects/exception_list.ts | 3 +- .../server/saved_objects/migrations.test.ts | 5 +- .../lists/server/saved_objects/migrations.ts | 5 +- .../create_endoint_event_filters_list.ts | 7 +- .../exception_lists/create_endpoint_list.ts | 7 +- .../create_endpoint_trusted_apps_list.ts | 7 +- .../exception_lists/create_exception_list.ts | 3 +- .../create_exception_list_item.ts | 2 +- .../exception_lists/delete_exception_list.ts | 2 +- .../delete_exception_list_item.ts | 2 +- .../delete_exception_list_items_by_list.ts | 2 +- .../exception_lists/exception_list_client.ts | 3 +- .../exception_lists/find_exception_list.ts | 4 +- .../find_exception_list_items.ts | 7 +- .../exception_lists/get_exception_list.ts | 3 +- .../get_exception_list_item.ts | 3 +- .../exception_lists/update_exception_list.ts | 3 +- .../update_exception_list_item.ts | 2 +- .../server/services/exception_lists/utils.ts | 42 +-- .../detection_engine/parse_schedule_dates.ts | 21 -- .../schemas/types/lists.mock.ts | 2 +- .../common/detection_engine/utils.test.ts | 3 +- .../common/detection_engine/utils.ts | 6 +- .../data_generators/event_filter_generator.ts | 2 +- .../security_solution/common/fp_utils.ts | 21 -- .../common/shared_imports.ts | 16 -- ...se_fetch_or_create_rule_exception_list.tsx | 2 +- .../common/hooks/eql/use_eql_preview.ts | 2 +- .../detection_engine/rules/create/helpers.ts | 2 +- .../pages/detection_engine/rules/helpers.tsx | 2 +- .../pages/event_filters/constants.ts | 2 +- .../pages/event_filters/service/index.ts | 2 +- .../pages/event_filters/test_utils/index.ts | 2 +- .../public/shared_imports.ts | 2 - .../scripts/endpoint/event_filters/index.ts | 4 +- .../endpoint/lib/artifacts/lists.test.ts | 5 +- .../server/endpoint/lib/artifacts/lists.ts | 7 +- .../endpoint/routes/trusted_apps/mapping.ts | 2 +- .../routes/trusted_apps/service.test.ts | 2 +- .../endpoint/routes/trusted_apps/service.ts | 2 +- .../manifest_manager/manifest_manager.test.ts | 5 +- .../create_migration_saved_object.ts | 2 +- .../update_migration_saved_object.ts | 2 +- .../rules_notification_alert_type.ts | 2 +- .../filters/filter_events_against_list.ts | 3 +- .../signals/signal_rule_alert_type.test.ts | 22 +- .../signals/signal_rule_alert_type.ts | 5 +- .../detection_engine/signals/utils.test.ts | 29 -- .../lib/detection_engine/signals/utils.ts | 6 +- .../apis/lists/create_exception_list_item.ts | 2 +- .../tests/create_exceptions.ts | 5 +- .../detection_engine_api_integration/utils.ts | 2 +- .../tests/create_exception_list_items.ts | 5 +- .../tests/create_exception_lists.ts | 2 +- .../tests/create_list_items.ts | 2 +- .../security_and_spaces/tests/create_lists.ts | 2 +- .../tests/delete_exception_list_items.ts | 5 +- .../tests/delete_exception_lists.ts | 2 +- .../tests/delete_list_items.ts | 2 +- .../security_and_spaces/tests/delete_lists.ts | 4 +- .../tests/export_list_items.ts | 3 +- .../tests/find_exception_list_items.ts | 5 +- .../tests/find_exception_lists.ts | 2 +- .../tests/find_list_items.ts | 2 +- .../security_and_spaces/tests/find_lists.ts | 2 +- .../tests/import_list_items.ts | 3 +- .../tests/read_exception_list_items.ts | 5 +- .../tests/read_exception_lists.ts | 2 +- .../tests/read_list_items.ts | 2 +- .../tests/read_list_privileges.ts | 2 +- .../security_and_spaces/tests/read_lists.ts | 2 +- .../tests/update_exception_list_items.ts | 5 +- .../tests/update_exception_lists.ts | 2 +- .../tests/update_list_items.ts | 2 +- .../security_and_spaces/tests/update_lists.ts | 2 +- x-pack/test/lists_api_integration/utils.ts | 2 +- yarn.lock | 8 +- 168 files changed, 751 insertions(+), 1356 deletions(-) delete mode 100644 packages/kbn-securitysolution-constants/README.md delete mode 100644 packages/kbn-securitysolution-constants/package.json delete mode 100644 packages/kbn-securitysolution-io-ts-list-types/src/constants/index.ts create mode 100644 packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts rename packages/{kbn-securitysolution-io-ts-types => kbn-securitysolution-io-ts-utils}/src/parse_schedule_dates/index.ts (100%) delete mode 100644 packages/kbn-securitysolution-list-api/src/constants/index.ts rename packages/{kbn-securitysolution-constants => kbn-securitysolution-list-constants}/BUILD.bazel (91%) create mode 100644 packages/kbn-securitysolution-list-constants/README.md rename packages/{kbn-securitysolution-constants => kbn-securitysolution-list-constants}/jest.config.js (85%) create mode 100644 packages/kbn-securitysolution-list-constants/package.json rename packages/{kbn-securitysolution-constants => kbn-securitysolution-list-constants}/src/index.ts (96%) rename packages/{kbn-securitysolution-constants => kbn-securitysolution-list-constants}/tsconfig.json (78%) delete mode 100644 packages/kbn-securitysolution-list-hooks/src/constants/index.ts delete mode 100644 packages/kbn-securitysolution-list-hooks/src/utils/index.test.ts delete mode 100644 packages/kbn-securitysolution-list-hooks/src/utils/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_filters/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.test.ts create mode 100644 packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.ts delete mode 100644 x-pack/plugins/lists/common/constants.ts delete mode 100644 x-pack/plugins/lists/common/shared_exports.ts delete mode 100644 x-pack/plugins/lists/common/types.ts delete mode 100644 x-pack/plugins/lists/public/exceptions/utils.test.ts delete mode 100644 x-pack/plugins/lists/public/exceptions/utils.ts delete mode 100644 x-pack/plugins/security_solution/common/detection_engine/parse_schedule_dates.ts delete mode 100644 x-pack/plugins/security_solution/common/fp_utils.ts delete mode 100644 x-pack/plugins/security_solution/common/shared_imports.ts diff --git a/docs/developer/getting-started/monorepo-packages.asciidoc b/docs/developer/getting-started/monorepo-packages.asciidoc index 78af727f3e0db..8f033029cfac4 100644 --- a/docs/developer/getting-started/monorepo-packages.asciidoc +++ b/docs/developer/getting-started/monorepo-packages.asciidoc @@ -82,13 +82,13 @@ yarn kbn watch-bazel - @kbn/i18n - @kbn/legacy-logging - @kbn/logging -- @kbn/securitysolution-constants - @kbn/securitysolution-es-utils - kbn/securitysolution-io-ts-alerting-types - kbn/securitysolution-io-ts-list-types - kbn/securitysolution-io-ts-types - @kbn/securitysolution-io-ts-utils - @kbn/securitysolution-list-api +- @kbn/securitysolution-list-constants - @kbn/securitysolution-list-hooks - @kbn/securitysolution-list-utils - @kbn/securitysolution-utils diff --git a/package.json b/package.json index f7fe3f0fc3125..5737bce303e09 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "@kbn/legacy-logging": "link:bazel-bin/packages/kbn-legacy-logging/npm_module", "@kbn/logging": "link:bazel-bin/packages/kbn-logging/npm_module", "@kbn/monaco": "link:packages/kbn-monaco", - "@kbn/securitysolution-constants": "link:bazel-bin/packages/kbn-securitysolution-constants/npm_module", + "@kbn/securitysolution-list-constants": "link:bazel-bin/packages/kbn-securitysolution-list-constants/npm_module", "@kbn/securitysolution-es-utils": "link:bazel-bin/packages/kbn-securitysolution-es-utils/npm_module", "@kbn/securitysolution-io-ts-types": "link:bazel-bin/packages/kbn-securitysolution-io-ts-types/npm_module", "@kbn/securitysolution-io-ts-alerting-types": "link:bazel-bin/packages/kbn-securitysolution-io-ts-alerting-types/npm_module", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index d6c73da3565a3..ec8252cb6144d 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -25,7 +25,7 @@ filegroup( "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", "//packages/kbn-plugin-generator:build", - "//packages/kbn-securitysolution-constants:build", + "//packages/kbn-securitysolution-list-constants:build", "//packages/kbn-securitysolution-io-ts-types:build", "//packages/kbn-securitysolution-io-ts-alerting-types:build", "//packages/kbn-securitysolution-io-ts-list-types:build", diff --git a/packages/kbn-securitysolution-constants/README.md b/packages/kbn-securitysolution-constants/README.md deleted file mode 100644 index dd1ab8da6a2a8..0000000000000 --- a/packages/kbn-securitysolution-constants/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# kbn-securitysolution-constants - -This is where shared constants for security solution should go that are going to be shared among plugins. -This was originally created to remove the dependencies between security_solution and other projects such as lists. - - diff --git a/packages/kbn-securitysolution-constants/package.json b/packages/kbn-securitysolution-constants/package.json deleted file mode 100644 index bb60f79aa03e5..0000000000000 --- a/packages/kbn-securitysolution-constants/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "@kbn/securitysolution-constants", - "version": "1.0.0", - "description": "security solution constants to use across plugins such lists, security_solution, cases, etc...", - "license": "SSPL-1.0 OR Elastic License 2.0", - "main": "./target/index.js", - "types": "./target/index.d.ts", - "private": true -} diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts index 91a3951ef11fc..4013a3a0497db 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/constants/index.ts @@ -7,15 +7,7 @@ */ /** - * This ID is used for _both_ the Saved Object ID and for the list_id - * for the single global space agnostic endpoint list - * TODO: Create a kbn-securitysolution-constants and add this to it. - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_LIST_ID = 'endpoint_list'; - -/** - * TODO: Create a kbn-securitysolution-constants and add this to it. - * @deprecated Use the DEFAULT_MAX_SIGNALS from the kbn-securitysolution-constants. + * TODO: Create a kbn-alerting-constants and add this to it. + * @deprecated Use a DEFAULT_MAX_SIGNALS from a kbn-alerting-constants package. */ export const DEFAULT_MAX_SIGNALS = 100; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts index 37ed4b2daa510..30b3c727d87a2 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/from/index.ts @@ -8,7 +8,7 @@ import { Either } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; -import { parseScheduleDates } from '@kbn/securitysolution-io-ts-types'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; const stringValidator = (input: unknown): input is string => typeof input === 'string'; diff --git a/packages/kbn-securitysolution-io-ts-alerting-types/src/index.ts b/packages/kbn-securitysolution-io-ts-alerting-types/src/index.ts index c6f29862206e6..2b8ba39fdf4f3 100644 --- a/packages/kbn-securitysolution-io-ts-alerting-types/src/index.ts +++ b/packages/kbn-securitysolution-io-ts-alerting-types/src/index.ts @@ -7,7 +7,6 @@ */ export * from './actions'; -export * from './constants'; export * from './default_actions_array'; export * from './default_export_file_name'; export * from './default_from_string'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts index c6f54b57d937b..b5e4751025439 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/common/lists/index.mock.ts @@ -7,7 +7,7 @@ */ import { List, ListArray } from '.'; -import { ENDPOINT_LIST_ID } from '../../constants'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; export const getListMock = (): List => ({ id: 'some_uuid', diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.ts deleted file mode 100644 index 2f520e79bf42c..0000000000000 --- a/packages/kbn-securitysolution-io-ts-list-types/src/constants/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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. - */ - -/** - * This ID is used for _both_ the Saved Object ID and for the list_id - * for the single global space agnostic endpoint list. - * - * TODO: Create a kbn-securitysolution-constants and add this to it. - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_LIST_ID = 'endpoint_list'; - -/** - * Description of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION = 'Endpoint Security Trusted Apps List'; - -/** - * ID of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_ID = 'endpoint_trusted_apps'; - -/** - * Name of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_NAME = 'Endpoint Security Trusted Apps List'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/index.ts b/packages/kbn-securitysolution-io-ts-list-types/src/index.ts index 426e0f54963b8..3d1b267c01d3b 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/index.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/index.ts @@ -7,7 +7,6 @@ */ export * from './common'; -export * from './constants'; export * from './request'; export * from './response'; export * from './typescript_types'; diff --git a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts index 5928c420c88e3..c77fb35a40b60 100644 --- a/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts +++ b/packages/kbn-securitysolution-io-ts-list-types/src/response/exception_list_schema/index.mock.ts @@ -25,7 +25,7 @@ import { ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, ENDPOINT_TRUSTED_APPS_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_NAME, -} from '../..'; +} from '@kbn/securitysolution-list-constants'; import { ExceptionListSchema } from '.'; diff --git a/packages/kbn-securitysolution-io-ts-types/src/index.ts b/packages/kbn-securitysolution-io-ts-types/src/index.ts index fc0f017016e9f..2847894d63690 100644 --- a/packages/kbn-securitysolution-io-ts-types/src/index.ts +++ b/packages/kbn-securitysolution-io-ts-types/src/index.ts @@ -22,7 +22,6 @@ export * from './non_empty_string'; export * from './non_empty_string_array'; export * from './operator'; export * from './only_false_allowed'; -export * from './parse_schedule_dates'; export * from './positive_integer'; export * from './positive_integer_greater_than_zero'; export * from './string_to_positive_number'; diff --git a/packages/kbn-securitysolution-io-ts-utils/src/index.ts b/packages/kbn-securitysolution-io-ts-utils/src/index.ts index c21096e497134..8082574296e3f 100644 --- a/packages/kbn-securitysolution-io-ts-utils/src/index.ts +++ b/packages/kbn-securitysolution-io-ts-utils/src/index.ts @@ -7,6 +7,7 @@ */ export * from './format_errors'; +export * from './parse_schedule_dates'; export * from './exact_check'; export * from './format_errors'; export * from './test_utils'; diff --git a/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts b/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts new file mode 100644 index 0000000000000..8919f63aad51e --- /dev/null +++ b/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 moment from 'moment'; +import { parseScheduleDates } from '.'; + +describe('parseScheduleDates', () => { + test('it returns a moment when given an ISO string', () => { + const result = parseScheduleDates('2020-01-01T00:00:00.000Z'); + expect(result).not.toBeNull(); + expect(result).toEqual(moment('2020-01-01T00:00:00.000Z')); + }); + + test('it returns a moment when given `now`', () => { + const result = parseScheduleDates('now'); + + expect(result).not.toBeNull(); + expect(moment.isMoment(result)).toBeTruthy(); + }); + + test('it returns a moment when given `now-x`', () => { + const result = parseScheduleDates('now-6m'); + + expect(result).not.toBeNull(); + expect(moment.isMoment(result)).toBeTruthy(); + }); + + test('it returns null when given a string that is not an ISO string, `now` or `now-x`', () => { + const result = parseScheduleDates('invalid'); + + expect(result).toBeNull(); + }); +}); diff --git a/packages/kbn-securitysolution-io-ts-types/src/parse_schedule_dates/index.ts b/packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts similarity index 100% rename from packages/kbn-securitysolution-io-ts-types/src/parse_schedule_dates/index.ts rename to packages/kbn-securitysolution-io-ts-utils/src/parse_schedule_dates/index.ts diff --git a/packages/kbn-securitysolution-list-api/BUILD.bazel b/packages/kbn-securitysolution-list-api/BUILD.bazel index 149bbf9a0c5c6..9055cf0804e49 100644 --- a/packages/kbn-securitysolution-list-api/BUILD.bazel +++ b/packages/kbn-securitysolution-list-api/BUILD.bazel @@ -29,6 +29,7 @@ NPM_MODULE_EXTRA_FILES = [ SRC_DEPS = [ "//packages/kbn-securitysolution-io-ts-utils", + "//packages/kbn-securitysolution-list-constants", "//packages/kbn-securitysolution-io-ts-list-types", "@npm//fp-ts", "@npm//io-ts", diff --git a/packages/kbn-securitysolution-list-api/src/api/index.ts b/packages/kbn-securitysolution-list-api/src/api/index.ts index eb3caad2a0cab..d70417a29971f 100644 --- a/packages/kbn-securitysolution-list-api/src/api/index.ts +++ b/packages/kbn-securitysolution-list-api/src/api/index.ts @@ -31,14 +31,14 @@ import { UpdateExceptionListProps, } from '@kbn/securitysolution-io-ts-list-types'; -import { toError, toPromise } from '../fp_utils'; import { ENDPOINT_LIST_URL, EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_NAMESPACE, EXCEPTION_LIST_NAMESPACE_AGNOSTIC, EXCEPTION_LIST_URL, -} from '../constants'; +} from '@kbn/securitysolution-list-constants'; +import { toError, toPromise } from '../fp_utils'; /** * Add new ExceptionList diff --git a/packages/kbn-securitysolution-list-api/src/constants/index.ts b/packages/kbn-securitysolution-list-api/src/constants/index.ts deleted file mode 100644 index fe3de21664ca1..0000000000000 --- a/packages/kbn-securitysolution-list-api/src/constants/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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. - */ - -// TODO: These should be all replaced with constants from a shared kbn constants package - -export const LIST_URL = '/api/lists'; -export const LIST_INDEX = `${LIST_URL}/index`; -export const LIST_ITEM_URL = `${LIST_URL}/items`; -export const LIST_PRIVILEGES_URL = `${LIST_URL}/privileges`; - -/** - * Exception list routes - */ -export const EXCEPTION_LIST_URL = '/api/exception_lists'; -export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items'; - -/** - * Exception list spaces - */ -export const EXCEPTION_LIST_NAMESPACE_AGNOSTIC = 'exception-list-agnostic'; -export const EXCEPTION_LIST_NAMESPACE = 'exception-list'; - -/** - * Specific routes for the single global space agnostic endpoint list - */ -export const ENDPOINT_LIST_URL = '/api/endpoint_list'; - -/** - * Specific routes for the single global space agnostic endpoint list. These are convenience - * routes where they are going to try and create the global space agnostic endpoint list if it - * does not exist yet or if it was deleted at some point and re-create it before adding items to - * the list - */ -export const ENDPOINT_LIST_ITEM_URL = '/api/endpoint_list/items'; diff --git a/packages/kbn-securitysolution-list-api/src/list_api/index.ts b/packages/kbn-securitysolution-list-api/src/list_api/index.ts index 7914a5e59d712..b9d5417f761c0 100644 --- a/packages/kbn-securitysolution-list-api/src/list_api/index.ts +++ b/packages/kbn-securitysolution-list-api/src/list_api/index.ts @@ -30,10 +30,14 @@ import { listItemIndexExistSchema, listSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { + LIST_INDEX, + LIST_ITEM_URL, + LIST_PRIVILEGES_URL, + LIST_URL, +} from '@kbn/securitysolution-list-constants'; import { toError, toPromise } from '../fp_utils'; -import { LIST_INDEX, LIST_ITEM_URL, LIST_PRIVILEGES_URL, LIST_URL } from '../constants'; - import { ApiParams, DeleteListParams, diff --git a/packages/kbn-securitysolution-constants/BUILD.bazel b/packages/kbn-securitysolution-list-constants/BUILD.bazel similarity index 91% rename from packages/kbn-securitysolution-constants/BUILD.bazel rename to packages/kbn-securitysolution-list-constants/BUILD.bazel index 20f1b51c7d426..8d6779bfa122e 100644 --- a/packages/kbn-securitysolution-constants/BUILD.bazel +++ b/packages/kbn-securitysolution-list-constants/BUILD.bazel @@ -1,9 +1,9 @@ load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") -PKG_BASE_NAME = "kbn-securitysolution-constants" +PKG_BASE_NAME = "kbn-securitysolution-list-constants" -PKG_REQUIRE_NAME = "@kbn/securitysolution-constants" +PKG_REQUIRE_NAME = "@kbn/securitysolution-list-constants" SOURCE_FILES = glob( [ diff --git a/packages/kbn-securitysolution-list-constants/README.md b/packages/kbn-securitysolution-list-constants/README.md new file mode 100644 index 0000000000000..c6f10d3bd009b --- /dev/null +++ b/packages/kbn-securitysolution-list-constants/README.md @@ -0,0 +1,6 @@ +# kbn-securitysolution-list-constants + +This is where shared constants for security solution lists should go that are going to be shared among plugins. +This was originally created to remove the dependencies between security_solution and other projects. + + diff --git a/packages/kbn-securitysolution-constants/jest.config.js b/packages/kbn-securitysolution-list-constants/jest.config.js similarity index 85% rename from packages/kbn-securitysolution-constants/jest.config.js rename to packages/kbn-securitysolution-list-constants/jest.config.js index f0bb13e39417c..21dffdfcf5a68 100644 --- a/packages/kbn-securitysolution-constants/jest.config.js +++ b/packages/kbn-securitysolution-list-constants/jest.config.js @@ -9,5 +9,5 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/kbn-securitysolution-constants'], + roots: ['/packages/kbn-securitysolution-list-constants'], }; diff --git a/packages/kbn-securitysolution-list-constants/package.json b/packages/kbn-securitysolution-list-constants/package.json new file mode 100644 index 0000000000000..b9d65734aff56 --- /dev/null +++ b/packages/kbn-securitysolution-list-constants/package.json @@ -0,0 +1,9 @@ +{ + "name": "@kbn/securitysolution-list-constants", + "version": "1.0.0", + "description": "security solution list constants to use across plugins such lists, security_solution, cases, etc...", + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target/index.js", + "types": "./target/index.d.ts", + "private": true +} diff --git a/packages/kbn-securitysolution-constants/src/index.ts b/packages/kbn-securitysolution-list-constants/src/index.ts similarity index 96% rename from packages/kbn-securitysolution-constants/src/index.ts rename to packages/kbn-securitysolution-list-constants/src/index.ts index 06b741d761367..dae414aad0deb 100644 --- a/packages/kbn-securitysolution-constants/src/index.ts +++ b/packages/kbn-securitysolution-list-constants/src/index.ts @@ -70,6 +70,3 @@ export const ENDPOINT_EVENT_FILTERS_LIST_NAME = 'Endpoint Security Event Filters /** Description of event filters agnostic list */ export const ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION = 'Endpoint Security Event Filters List'; - -/** The default max signals without any additional configuration */ -export const DEFAULT_MAX_SIGNALS = 100; diff --git a/packages/kbn-securitysolution-constants/tsconfig.json b/packages/kbn-securitysolution-list-constants/tsconfig.json similarity index 78% rename from packages/kbn-securitysolution-constants/tsconfig.json rename to packages/kbn-securitysolution-list-constants/tsconfig.json index cf06f4ced4b9f..84edcdd1d5794 100644 --- a/packages/kbn-securitysolution-constants/tsconfig.json +++ b/packages/kbn-securitysolution-list-constants/tsconfig.json @@ -7,7 +7,7 @@ "outDir": "target", "rootDir": "src", "sourceMap": true, - "sourceRoot": "../../../../packages/kbn-securitysolution-constants/src", + "sourceRoot": "../../../../packages/kbn-securitysolution-list-constants/src", "types": [ "jest", "node" diff --git a/packages/kbn-securitysolution-list-hooks/BUILD.bazel b/packages/kbn-securitysolution-list-hooks/BUILD.bazel index 3c5444092676f..1078d9bf3d329 100644 --- a/packages/kbn-securitysolution-list-hooks/BUILD.bazel +++ b/packages/kbn-securitysolution-list-hooks/BUILD.bazel @@ -30,6 +30,8 @@ NPM_MODULE_EXTRA_FILES = [ SRC_DEPS = [ "//packages/kbn-securitysolution-io-ts-list-types", "//packages/kbn-securitysolution-list-api", + "//packages/kbn-securitysolution-list-constants", + "//packages/kbn-securitysolution-list-utils", "//packages/kbn-securitysolution-utils", "@npm//lodash", "@npm//tslib", diff --git a/packages/kbn-securitysolution-list-hooks/src/constants/index.ts b/packages/kbn-securitysolution-list-hooks/src/constants/index.ts deleted file mode 100644 index 2f520e79bf42c..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/constants/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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. - */ - -/** - * This ID is used for _both_ the Saved Object ID and for the list_id - * for the single global space agnostic endpoint list. - * - * TODO: Create a kbn-securitysolution-constants and add this to it. - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_LIST_ID = 'endpoint_list'; - -/** - * Description of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION = 'Endpoint Security Trusted Apps List'; - -/** - * ID of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_ID = 'endpoint_trusted_apps'; - -/** - * Name of trusted apps agnostic list - * @deprecated Use the ENDPOINT_LIST_ID from the kbn-securitysolution-constants. - */ -export const ENDPOINT_TRUSTED_APPS_LIST_NAME = 'Endpoint Security Trusted Apps List'; diff --git a/packages/kbn-securitysolution-list-hooks/src/index.ts b/packages/kbn-securitysolution-list-hooks/src/index.ts index a00086aa94b0d..46d6a20deb0ac 100644 --- a/packages/kbn-securitysolution-list-hooks/src/index.ts +++ b/packages/kbn-securitysolution-list-hooks/src/index.ts @@ -21,5 +21,4 @@ export * from './use_persist_exception_item'; export * from './use_persist_exception_list'; export * from './use_read_list_index'; export * from './use_read_list_privileges'; -export * from './utils'; export * from './with_optional_signal'; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts index 04ba0fc762f9c..3b980f84d82a8 100644 --- a/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts +++ b/packages/kbn-securitysolution-list-hooks/src/use_api/index.ts @@ -25,7 +25,7 @@ interface HttpStart { fetch: (...args: any) => any; } -import { getIdsAndNamespaces } from '../utils'; +import { getIdsAndNamespaces } from '@kbn/securitysolution-list-utils'; import { transformInput, transformNewItemOutput, transformOutput } from '../transforms'; export interface ExceptionsApi { diff --git a/packages/kbn-securitysolution-list-hooks/src/use_exception_list_items/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_exception_list_items/index.ts index 43f39401a81d1..4962ecee58016 100644 --- a/packages/kbn-securitysolution-list-hooks/src/use_exception_list_items/index.ts +++ b/packages/kbn-securitysolution-list-hooks/src/use_exception_list_items/index.ts @@ -15,7 +15,7 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { fetchExceptionListsItemsByListIds } from '@kbn/securitysolution-list-api'; -import { getIdsAndNamespaces } from '../utils'; +import { getIdsAndNamespaces } from '@kbn/securitysolution-list-utils'; import { transformInput } from '../transforms'; type Func = () => void; diff --git a/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts b/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts index 5d7aada4b9529..a9a93aa8df49a 100644 --- a/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts +++ b/packages/kbn-securitysolution-list-hooks/src/use_exception_lists/index.ts @@ -14,7 +14,7 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { fetchExceptionLists } from '@kbn/securitysolution-list-api'; -import { getFilters } from '../utils'; +import { getFilters } from '@kbn/securitysolution-list-utils'; export type Func = () => void; export type ReturnExceptionLists = [boolean, ExceptionListSchema[], Pagination, Func | null]; diff --git a/packages/kbn-securitysolution-list-hooks/src/utils/index.test.ts b/packages/kbn-securitysolution-list-hooks/src/utils/index.test.ts deleted file mode 100644 index 8d8c8518dc298..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/utils/index.test.ts +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import { getFilters, getGeneralFilters, getIdsAndNamespaces, getTrustedAppsFilter } from '.'; - -describe('Exceptions utils', () => { - describe('#getIdsAndNamespaces', () => { - test('it returns empty arrays if no lists found', async () => { - const output = getIdsAndNamespaces({ - lists: [], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ ids: [], namespaces: [] }); - }); - - test('it returns all lists if "showDetection" and "showEndpoint" are "false"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id', 'list_id_endpoint'], - namespaces: ['single', 'agnostic'], - }); - }); - - test('it returns only detections lists if "showDetection" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); - - test('it returns only endpoint lists if "showEndpoint" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id_endpoint'], - namespaces: ['agnostic'], - }); - }); - - test('it returns only detection lists if both "showEndpoint" and "showDetection" are "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); - }); - - describe('getGeneralFilters', () => { - test('it returns empty string if no filters', () => { - const filters = getGeneralFilters({}, ['exception-list']); - - expect(filters).toEqual(''); - }); - - test('it properly formats filters when one namespace type passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, ['exception-list']); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' - ); - }); - - test('it properly formats filters when two namespace types passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, [ - 'exception-list', - 'exception-list-agnostic', - ]); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' - ); - }); - }); - - describe('getTrustedAppsFilter', () => { - test('it returns filter to search for "exception-list" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(true, ['exception-list']); - - expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it returns filter to search for "exception-list" and "agnostic" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(true, ['exception-list', 'exception-list-agnostic']); - - expect(filter).toEqual( - '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it returns filter to exclude "exception-list" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(false, ['exception-list']); - - expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it returns filter to exclude "exception-list" and "agnostic" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(false, ['exception-list', 'exception-list-agnostic']); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('getFilters', () => { - describe('single', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['single'], false); - - expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['single'], true); - - expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], false); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it if filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], true); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('agnostic', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['agnostic'], false); - - expect(filter).toEqual( - '(not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['agnostic'], true); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], false); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it if filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], true); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('single, agnostic', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['single', 'agnostic'], false); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['single', 'agnostic'], true); - - expect(filter).toEqual( - '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters( - { created_by: 'moi', name: 'Sample' }, - ['single', 'agnostic'], - false - ); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is true', () => { - const filter = getFilters( - { created_by: 'moi', name: 'Sample' }, - ['single', 'agnostic'], - true - ); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - }); -}); diff --git a/packages/kbn-securitysolution-list-hooks/src/utils/index.ts b/packages/kbn-securitysolution-list-hooks/src/utils/index.ts deleted file mode 100644 index b08a4b49cd590..0000000000000 --- a/packages/kbn-securitysolution-list-hooks/src/utils/index.ts +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 and the Server Side Public License, v 1; you may not use this file except - * in compliance with, at your election, the Elastic License 2.0 or the Server - * Side Public License, v 1. - */ - -import type { - NamespaceType, - NamespaceTypeArray, - ExceptionListFilter, - ExceptionListIdentifiers, -} from '@kbn/securitysolution-io-ts-list-types'; -import { get } from 'lodash/fp'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../constants'; - -export const exceptionListSavedObjectType = 'exception-list'; -export const exceptionListAgnosticSavedObjectType = 'exception-list-agnostic'; -export type SavedObjectType = 'exception-list' | 'exception-list-agnostic'; - -export const getSavedObjectType = ({ - namespaceType, -}: { - namespaceType: NamespaceType; -}): SavedObjectType => { - if (namespaceType === 'agnostic') { - return exceptionListAgnosticSavedObjectType; - } else { - return exceptionListSavedObjectType; - } -}; - -export const getSavedObjectTypes = ({ - namespaceType, -}: { - namespaceType: NamespaceTypeArray; -}): SavedObjectType[] => { - return namespaceType.map((singleNamespaceType) => - getSavedObjectType({ namespaceType: singleNamespaceType }) - ); -}; - -export const getIdsAndNamespaces = ({ - lists, - showDetection, - showEndpoint, -}: { - lists: ExceptionListIdentifiers[]; - showDetection: boolean; - showEndpoint: boolean; -}): { ids: string[]; namespaces: NamespaceType[] } => - lists - .filter((list) => { - if (showDetection) { - return list.type === 'detection'; - } else if (showEndpoint) { - return list.type === 'endpoint'; - } else { - return true; - } - }) - .reduce<{ ids: string[]; namespaces: NamespaceType[] }>( - (acc, { listId, namespaceType }) => ({ - ids: [...acc.ids, listId], - namespaces: [...acc.namespaces, namespaceType], - }), - { ids: [], namespaces: [] } - ); - -export const getGeneralFilters = ( - filters: ExceptionListFilter, - namespaceTypes: SavedObjectType[] -): string => { - return Object.keys(filters) - .map((filterKey) => { - const value = get(filterKey, filters); - if (value != null && value.trim() !== '') { - const filtersByNamespace = namespaceTypes - .map((namespace) => { - const fieldToSearch = filterKey === 'name' ? 'name.text' : filterKey; - return `${namespace}.attributes.${fieldToSearch}:${value}`; - }) - .join(' OR '); - return `(${filtersByNamespace})`; - } else return null; - }) - .filter((item) => item != null) - .join(' AND '); -}; - -export const getTrustedAppsFilter = ( - showTrustedApps: boolean, - namespaceTypes: SavedObjectType[] -): string => { - if (showTrustedApps) { - const filters = namespaceTypes.map((namespace) => { - return `${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; - }); - return `(${filters.join(' OR ')})`; - } else { - const filters = namespaceTypes.map((namespace) => { - return `not ${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; - }); - return `(${filters.join(' AND ')})`; - } -}; - -export const getFilters = ( - filters: ExceptionListFilter, - namespaceTypes: NamespaceType[], - showTrustedApps: boolean -): string => { - const namespaces = getSavedObjectTypes({ namespaceType: namespaceTypes }); - const generalFilters = getGeneralFilters(filters, namespaces); - const trustedAppsFilter = getTrustedAppsFilter(showTrustedApps, namespaces); - return [generalFilters, trustedAppsFilter].filter((filter) => filter.trim() !== '').join(' AND '); -}; diff --git a/packages/kbn-securitysolution-list-utils/BUILD.bazel b/packages/kbn-securitysolution-list-utils/BUILD.bazel index f9063290d9f73..0d257a95f0259 100644 --- a/packages/kbn-securitysolution-list-utils/BUILD.bazel +++ b/packages/kbn-securitysolution-list-utils/BUILD.bazel @@ -29,6 +29,7 @@ NPM_MODULE_EXTRA_FILES = [ SRC_DEPS = [ "//packages/kbn-i18n", + "//packages/kbn-securitysolution-list-constants", "//packages/kbn-securitysolution-io-ts-list-types", "//packages/kbn-securitysolution-utils", "@npm//lodash", diff --git a/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts b/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts new file mode 100644 index 0000000000000..eb68e2486686f --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_exception_list_type/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +import { exceptionListAgnosticSavedObjectType } from '../types'; + +export const getExceptionListType = ({ + savedObjectType, +}: { + savedObjectType: string; +}): NamespaceType => { + if (savedObjectType === exceptionListAgnosticSavedObjectType) { + return 'agnostic'; + } else { + return 'single'; + } +}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts new file mode 100644 index 0000000000000..327a29dc1b987 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_filters/index.test.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { getFilters } from '.'; + +describe('getFilters', () => { + describe('single', () => { + test('it properly formats when no filters passed and "showTrustedApps" is false', () => { + const filter = getFilters({}, ['single'], false); + + expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); + }); + + test('it properly formats when no filters passed and "showTrustedApps" is true', () => { + const filter = getFilters({}, ['single'], true); + + expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); + }); + + test('it properly formats when filters passed and "showTrustedApps" is false', () => { + const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], false); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it if filters passed and "showTrustedApps" is true', () => { + const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], true); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + }); + + describe('agnostic', () => { + test('it properly formats when no filters passed and "showTrustedApps" is false', () => { + const filter = getFilters({}, ['agnostic'], false); + + expect(filter).toEqual( + '(not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it properly formats when no filters passed and "showTrustedApps" is true', () => { + const filter = getFilters({}, ['agnostic'], true); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it properly formats when filters passed and "showTrustedApps" is false', () => { + const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], false); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it if filters passed and "showTrustedApps" is true', () => { + const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], true); + + expect(filter).toEqual( + '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + }); + + describe('single, agnostic', () => { + test('it properly formats when no filters passed and "showTrustedApps" is false', () => { + const filter = getFilters({}, ['single', 'agnostic'], false); + + expect(filter).toEqual( + '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it properly formats when no filters passed and "showTrustedApps" is true', () => { + const filter = getFilters({}, ['single', 'agnostic'], true); + + expect(filter).toEqual( + '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it properly formats when filters passed and "showTrustedApps" is false', () => { + const filter = getFilters( + { created_by: 'moi', name: 'Sample' }, + ['single', 'agnostic'], + false + ); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it properly formats when filters passed and "showTrustedApps" is true', () => { + const filter = getFilters( + { created_by: 'moi', name: 'Sample' }, + ['single', 'agnostic'], + true + ); + + expect(filter).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + }); +}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts b/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts new file mode 100644 index 0000000000000..c9dd6ccae484c --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_filters/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ExceptionListFilter, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; +import { getGeneralFilters } from '../get_general_filters'; +import { getSavedObjectTypes } from '../get_saved_object_types'; +import { getTrustedAppsFilter } from '../get_trusted_apps_filter'; + +export const getFilters = ( + filters: ExceptionListFilter, + namespaceTypes: NamespaceType[], + showTrustedApps: boolean +): string => { + const namespaces = getSavedObjectTypes({ namespaceType: namespaceTypes }); + const generalFilters = getGeneralFilters(filters, namespaces); + const trustedAppsFilter = getTrustedAppsFilter(showTrustedApps, namespaces); + return [generalFilters, trustedAppsFilter].filter((filter) => filter.trim() !== '').join(' AND '); +}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts new file mode 100644 index 0000000000000..8786b48b73c82 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.test.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { getGeneralFilters } from '.'; + +describe('getGeneralFilters', () => { + test('it returns empty string if no filters', () => { + const filters = getGeneralFilters({}, ['exception-list']); + + expect(filters).toEqual(''); + }); + + test('it properly formats filters when one namespace type passed in', () => { + const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, ['exception-list']); + + expect(filters).toEqual( + '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' + ); + }); + + test('it properly formats filters when two namespace types passed in', () => { + const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, [ + 'exception-list', + 'exception-list-agnostic', + ]); + + expect(filters).toEqual( + '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' + ); + }); +}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts new file mode 100644 index 0000000000000..f44e37e547fe9 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_general_filters/index.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ExceptionListFilter } from '@kbn/securitysolution-io-ts-list-types'; +import { get } from 'lodash/fp'; +import { SavedObjectType } from '../types'; + +export const getGeneralFilters = ( + filters: ExceptionListFilter, + namespaceTypes: SavedObjectType[] +): string => { + return Object.keys(filters) + .map((filterKey) => { + const value = get(filterKey, filters); + if (value != null && value.trim() !== '') { + const filtersByNamespace = namespaceTypes + .map((namespace) => { + const fieldToSearch = filterKey === 'name' ? 'name.text' : filterKey; + return `${namespace}.attributes.${fieldToSearch}:${value}`; + }) + .join(' OR '); + return `(${filtersByNamespace})`; + } else return null; + }) + .filter((item) => item != null) + .join(' AND '); +}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts new file mode 100644 index 0000000000000..6ecba8b97207a --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.test.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { getIdsAndNamespaces } from '.'; + +describe('getIdsAndNamespaces', () => { + test('it returns empty arrays if no lists found', async () => { + const output = getIdsAndNamespaces({ + lists: [], + showDetection: false, + showEndpoint: false, + }); + + expect(output).toEqual({ ids: [], namespaces: [] }); + }); + + test('it returns all lists if "showDetection" and "showEndpoint" are "false"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: false, + showEndpoint: false, + }); + + expect(output).toEqual({ + ids: ['list_id', 'list_id_endpoint'], + namespaces: ['single', 'agnostic'], + }); + }); + + test('it returns only detections lists if "showDetection" is "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: true, + showEndpoint: false, + }); + + expect(output).toEqual({ + ids: ['list_id'], + namespaces: ['single'], + }); + }); + + test('it returns only endpoint lists if "showEndpoint" is "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: false, + showEndpoint: true, + }); + + expect(output).toEqual({ + ids: ['list_id_endpoint'], + namespaces: ['agnostic'], + }); + }); + + test('it returns only detection lists if both "showEndpoint" and "showDetection" are "true"', async () => { + const output = getIdsAndNamespaces({ + lists: [ + { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, + { + id: 'myListIdEndpoint', + listId: 'list_id_endpoint', + namespaceType: 'agnostic', + type: 'endpoint', + }, + ], + showDetection: true, + showEndpoint: true, + }); + + expect(output).toEqual({ + ids: ['list_id'], + namespaces: ['single'], + }); + }); +}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts new file mode 100644 index 0000000000000..a1ab4c14728e4 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_ids_and_namespaces/index.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ExceptionListIdentifiers, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +export const getIdsAndNamespaces = ({ + lists, + showDetection, + showEndpoint, +}: { + lists: ExceptionListIdentifiers[]; + showDetection: boolean; + showEndpoint: boolean; +}): { ids: string[]; namespaces: NamespaceType[] } => + lists + .filter((list) => { + if (showDetection) { + return list.type === 'detection'; + } else if (showEndpoint) { + return list.type === 'endpoint'; + } else { + return true; + } + }) + .reduce<{ ids: string[]; namespaces: NamespaceType[] }>( + (acc, { listId, namespaceType }) => ({ + ids: [...acc.ids, listId], + namespaces: [...acc.namespaces, namespaceType], + }), + { ids: [], namespaces: [] } + ); diff --git a/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts b/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts new file mode 100644 index 0000000000000..1d59694e43366 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_saved_object_type/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; + +import { + exceptionListAgnosticSavedObjectType, + exceptionListSavedObjectType, + SavedObjectType, +} from '../types'; + +export const getSavedObjectType = ({ + namespaceType, +}: { + namespaceType: NamespaceType; +}): SavedObjectType => { + if (namespaceType === 'agnostic') { + return exceptionListAgnosticSavedObjectType; + } else { + return exceptionListSavedObjectType; + } +}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts b/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts new file mode 100644 index 0000000000000..f61dfe071802d --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_saved_object_types/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import type { NamespaceTypeArray } from '@kbn/securitysolution-io-ts-list-types'; + +import { SavedObjectType } from '../types'; +import { getSavedObjectType } from '../get_saved_object_type'; + +export const getSavedObjectTypes = ({ + namespaceType, +}: { + namespaceType: NamespaceTypeArray; +}): SavedObjectType[] => { + return namespaceType.map((singleNamespaceType) => + getSavedObjectType({ namespaceType: singleNamespaceType }) + ); +}; diff --git a/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.test.ts b/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.test.ts new file mode 100644 index 0000000000000..da178b15390e6 --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.test.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { getTrustedAppsFilter } from '.'; + +describe('getTrustedAppsFilter', () => { + test('it returns filter to search for "exception-list" namespace trusted apps', () => { + const filter = getTrustedAppsFilter(true, ['exception-list']); + + expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); + }); + + test('it returns filter to search for "exception-list" and "agnostic" namespace trusted apps', () => { + const filter = getTrustedAppsFilter(true, ['exception-list', 'exception-list-agnostic']); + + expect(filter).toEqual( + '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); + + test('it returns filter to exclude "exception-list" namespace trusted apps', () => { + const filter = getTrustedAppsFilter(false, ['exception-list']); + + expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); + }); + + test('it returns filter to exclude "exception-list" and "agnostic" namespace trusted apps', () => { + const filter = getTrustedAppsFilter(false, ['exception-list', 'exception-list-agnostic']); + + expect(filter).toEqual( + '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' + ); + }); +}); diff --git a/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.ts b/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.ts new file mode 100644 index 0000000000000..9c969068d4edf --- /dev/null +++ b/packages/kbn-securitysolution-list-utils/src/get_trusted_apps_filter/index.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; +import { SavedObjectType } from '../types'; + +export const getTrustedAppsFilter = ( + showTrustedApps: boolean, + namespaceTypes: SavedObjectType[] +): string => { + if (showTrustedApps) { + const filters = namespaceTypes.map((namespace) => { + return `${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; + }); + return `(${filters.join(' OR ')})`; + } else { + const filters = namespaceTypes.map((namespace) => { + return `not ${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; + }); + return `(${filters.join(' AND ')})`; + } +}; diff --git a/packages/kbn-securitysolution-list-utils/src/index.ts b/packages/kbn-securitysolution-list-utils/src/index.ts index 9e3cb78c1ae25..9e88cac6b5d19 100644 --- a/packages/kbn-securitysolution-list-utils/src/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/index.ts @@ -7,6 +7,13 @@ */ export * from './autocomplete_operators'; export * from './build_exception_filter'; +export * from './get_exception_list_type'; +export * from './get_filters'; +export * from './get_general_filters'; +export * from './get_ids_and_namespaces'; +export * from './get_saved_object_type'; +export * from './get_saved_object_types'; +export * from './get_trusted_apps_filter'; export * from './has_large_value_list'; export * from './helpers'; export * from './types'; diff --git a/packages/kbn-securitysolution-list-utils/src/types/index.ts b/packages/kbn-securitysolution-list-utils/src/types/index.ts index c8603fa01157c..faf68ca157981 100644 --- a/packages/kbn-securitysolution-list-utils/src/types/index.ts +++ b/packages/kbn-securitysolution-list-utils/src/types/index.ts @@ -18,6 +18,10 @@ import type { ListOperatorEnum as OperatorEnum, ListOperatorTypeEnum as OperatorTypeEnum, } from '@kbn/securitysolution-io-ts-list-types'; +import { + EXCEPTION_LIST_NAMESPACE, + EXCEPTION_LIST_NAMESPACE_AGNOSTIC, +} from '@kbn/securitysolution-list-constants'; import type { OperatorOption } from '../autocomplete_operators/types'; @@ -98,3 +102,9 @@ export type CreateExceptionListItemBuilderSchema = Omit< export type ExceptionsBuilderExceptionItem = | ExceptionListItemBuilderSchema | CreateExceptionListItemBuilderSchema; + +export const exceptionListSavedObjectType = EXCEPTION_LIST_NAMESPACE; +export const exceptionListAgnosticSavedObjectType = EXCEPTION_LIST_NAMESPACE_AGNOSTIC; +export type SavedObjectType = + | typeof EXCEPTION_LIST_NAMESPACE + | typeof EXCEPTION_LIST_NAMESPACE_AGNOSTIC; diff --git a/x-pack/plugins/lists/common/constants.ts b/x-pack/plugins/lists/common/constants.ts deleted file mode 100644 index 4f897c83cb41d..0000000000000 --- a/x-pack/plugins/lists/common/constants.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/** - * Value list routes - */ -export const LIST_URL = '/api/lists'; -export const LIST_INDEX = `${LIST_URL}/index`; -export const LIST_ITEM_URL = `${LIST_URL}/items`; -export const LIST_PRIVILEGES_URL = `${LIST_URL}/privileges`; - -/** - * Exception list routes - */ -export const EXCEPTION_LIST_URL = '/api/exception_lists'; -export const EXCEPTION_LIST_ITEM_URL = '/api/exception_lists/items'; - -/** - * Exception list spaces - */ -export const EXCEPTION_LIST_NAMESPACE_AGNOSTIC = 'exception-list-agnostic'; -export const EXCEPTION_LIST_NAMESPACE = 'exception-list'; - -/** - * Specific routes for the single global space agnostic endpoint list - */ -export const ENDPOINT_LIST_URL = '/api/endpoint_list'; - -/** - * Specific routes for the single global space agnostic endpoint list. These are convenience - * routes where they are going to try and create the global space agnostic endpoint list if it - * does not exist yet or if it was deleted at some point and re-create it before adding items to - * the list - */ -export const ENDPOINT_LIST_ITEM_URL = '/api/endpoint_list/items'; - -/** - * This ID is used for _both_ the Saved Object ID and for the list_id - * for the single global space agnostic endpoint list - */ -export const ENDPOINT_LIST_ID = 'endpoint_list'; - -/** The name of the single global space agnostic endpoint list */ -export const ENDPOINT_LIST_NAME = 'Endpoint Security Exception List'; - -/** The description of the single global space agnostic endpoint list */ -export const ENDPOINT_LIST_DESCRIPTION = 'Endpoint Security Exception List'; - -export const MAX_EXCEPTION_LIST_SIZE = 10000; - -/** ID of trusted apps agnostic list */ -export const ENDPOINT_TRUSTED_APPS_LIST_ID = 'endpoint_trusted_apps'; - -/** Name of trusted apps agnostic list */ -export const ENDPOINT_TRUSTED_APPS_LIST_NAME = 'Endpoint Security Trusted Apps List'; - -/** Description of trusted apps agnostic list */ -export const ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION = 'Endpoint Security Trusted Apps List'; - -/** ID of event filters agnostic list */ -export const ENDPOINT_EVENT_FILTERS_LIST_ID = 'endpoint_event_filters'; - -/** Name of event filters agnostic list */ -export const ENDPOINT_EVENT_FILTERS_LIST_NAME = 'Endpoint Security Event Filters List'; - -/** Description of event filters agnostic list */ -export const ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION = 'Endpoint Security Event Filters List'; diff --git a/x-pack/plugins/lists/common/index.ts b/x-pack/plugins/lists/common/index.ts index 9f4af059632c4..1fec1c76430eb 100644 --- a/x-pack/plugins/lists/common/index.ts +++ b/x-pack/plugins/lists/common/index.ts @@ -4,5 +4,3 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -export * from './shared_exports'; diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts index 59e1138972ce0..f1062d7ff1f4a 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_schema.mock.ts @@ -6,6 +6,12 @@ */ import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, + ENDPOINT_TRUSTED_APPS_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_NAME, +} from '@kbn/securitysolution-list-constants'; import { DATE_NOW, @@ -21,12 +27,6 @@ import { VERSION, _VERSION, } from '../../constants.mock'; -import { ENDPOINT_LIST_ID } from '../..'; -import { - ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, - ENDPOINT_TRUSTED_APPS_LIST_ID, - ENDPOINT_TRUSTED_APPS_LIST_NAME, -} from '../../constants'; export const getExceptionListSchemaMock = (): ExceptionListSchema => ({ _version: _VERSION, diff --git a/x-pack/plugins/lists/common/shared_exports.ts b/x-pack/plugins/lists/common/shared_exports.ts deleted file mode 100644 index 119eab3b245de..0000000000000 --- a/x-pack/plugins/lists/common/shared_exports.ts +++ /dev/null @@ -1,19 +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. - */ - -/** DEPRECATED, TRY NOT NOT TO ADD ANYTHING HERE. INSTEAD TRY TO USE/CREATE kibana packages @kbn/... */ - -// TODO: Move this into one of the kibana packages and remove it from here -export { - ENDPOINT_LIST_ID, - ENDPOINT_TRUSTED_APPS_LIST_ID, - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, - ENDPOINT_EVENT_FILTERS_LIST_ID, - ENDPOINT_EVENT_FILTERS_LIST_NAME, - ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION, -} from './constants'; diff --git a/x-pack/plugins/lists/common/types.ts b/x-pack/plugins/lists/common/types.ts deleted file mode 100644 index a3cbb870faa5b..0000000000000 --- a/x-pack/plugins/lists/common/types.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const exceptionListSavedObjectType = 'exception-list'; -export const exceptionListAgnosticSavedObjectType = 'exception-list-agnostic'; -export type SavedObjectType = 'exception-list' | 'exception-list-agnostic'; - -/** - * This makes any optional property the same as Required would but also has the - * added benefit of keeping your undefined. - * - * For example: - * type A = RequiredKeepUndefined<{ a?: undefined; b: number }>; - * - * will yield a type of: - * type A = { a: undefined; b: number; } - * @deprecated This has no replacement. We should stop using/relying on this and just remove it. - */ -export type RequiredKeepUndefined = { [K in keyof T]-?: [T[K]] } extends infer U - ? U extends Record - ? { [K in keyof U]: U[K][0] } - : never - : never; diff --git a/x-pack/plugins/lists/public/exceptions/utils.test.ts b/x-pack/plugins/lists/public/exceptions/utils.test.ts deleted file mode 100644 index 47279de0a84c8..0000000000000 --- a/x-pack/plugins/lists/public/exceptions/utils.test.ts +++ /dev/null @@ -1,271 +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 { getFilters, getGeneralFilters, getIdsAndNamespaces, getTrustedAppsFilter } from './utils'; - -describe('Exceptions utils', () => { - describe('#getIdsAndNamespaces', () => { - test('it returns empty arrays if no lists found', async () => { - const output = getIdsAndNamespaces({ - lists: [], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ ids: [], namespaces: [] }); - }); - - test('it returns all lists if "showDetection" and "showEndpoint" are "false"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id', 'list_id_endpoint'], - namespaces: ['single', 'agnostic'], - }); - }); - - test('it returns only detections lists if "showDetection" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: false, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); - - test('it returns only endpoint lists if "showEndpoint" is "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: false, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id_endpoint'], - namespaces: ['agnostic'], - }); - }); - - test('it returns only detection lists if both "showEndpoint" and "showDetection" are "true"', async () => { - const output = getIdsAndNamespaces({ - lists: [ - { id: 'myListId', listId: 'list_id', namespaceType: 'single', type: 'detection' }, - { - id: 'myListIdEndpoint', - listId: 'list_id_endpoint', - namespaceType: 'agnostic', - type: 'endpoint', - }, - ], - showDetection: true, - showEndpoint: true, - }); - - expect(output).toEqual({ - ids: ['list_id'], - namespaces: ['single'], - }); - }); - }); - - describe('getGeneralFilters', () => { - test('it returns empty string if no filters', () => { - const filters = getGeneralFilters({}, ['exception-list']); - - expect(filters).toEqual(''); - }); - - test('it properly formats filters when one namespace type passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, ['exception-list']); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample)' - ); - }); - - test('it properly formats filters when two namespace types passed in', () => { - const filters = getGeneralFilters({ created_by: 'moi', name: 'Sample' }, [ - 'exception-list', - 'exception-list-agnostic', - ]); - - expect(filters).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample)' - ); - }); - }); - - describe('getTrustedAppsFilter', () => { - test('it returns filter to search for "exception-list" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(true, ['exception-list']); - - expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it returns filter to search for "exception-list" and "agnostic" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(true, ['exception-list', 'exception-list-agnostic']); - - expect(filter).toEqual( - '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it returns filter to exclude "exception-list" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(false, ['exception-list']); - - expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it returns filter to exclude "exception-list" and "agnostic" namespace trusted apps', () => { - const filter = getTrustedAppsFilter(false, ['exception-list', 'exception-list-agnostic']); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('getFilters', () => { - describe('single', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['single'], false); - - expect(filter).toEqual('(not exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['single'], true); - - expect(filter).toEqual('(exception-list.attributes.list_id: endpoint_trusted_apps*)'); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], false); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it if filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['single'], true); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('agnostic', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['agnostic'], false); - - expect(filter).toEqual( - '(not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['agnostic'], true); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], false); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it if filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({ created_by: 'moi', name: 'Sample' }, ['agnostic'], true); - - expect(filter).toEqual( - '(exception-list-agnostic.attributes.created_by:moi) AND (exception-list-agnostic.attributes.name.text:Sample) AND (exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - - describe('single, agnostic', () => { - test('it properly formats when no filters passed and "showTrustedApps" is false', () => { - const filter = getFilters({}, ['single', 'agnostic'], false); - - expect(filter).toEqual( - '(not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when no filters passed and "showTrustedApps" is true', () => { - const filter = getFilters({}, ['single', 'agnostic'], true); - - expect(filter).toEqual( - '(exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is false', () => { - const filter = getFilters( - { created_by: 'moi', name: 'Sample' }, - ['single', 'agnostic'], - false - ); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (not exception-list.attributes.list_id: endpoint_trusted_apps* AND not exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - - test('it properly formats when filters passed and "showTrustedApps" is true', () => { - const filter = getFilters( - { created_by: 'moi', name: 'Sample' }, - ['single', 'agnostic'], - true - ); - - expect(filter).toEqual( - '(exception-list.attributes.created_by:moi OR exception-list-agnostic.attributes.created_by:moi) AND (exception-list.attributes.name.text:Sample OR exception-list-agnostic.attributes.name.text:Sample) AND (exception-list.attributes.list_id: endpoint_trusted_apps* OR exception-list-agnostic.attributes.list_id: endpoint_trusted_apps*)' - ); - }); - }); - }); -}); diff --git a/x-pack/plugins/lists/public/exceptions/utils.ts b/x-pack/plugins/lists/public/exceptions/utils.ts deleted file mode 100644 index 69803aebc6f6c..0000000000000 --- a/x-pack/plugins/lists/public/exceptions/utils.ts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { get } from 'lodash/fp'; -import type { - ExceptionListFilter, - ExceptionListIdentifiers, - NamespaceType, - NamespaceTypeArray, -} from '@kbn/securitysolution-io-ts-list-types'; - -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants'; -import { - SavedObjectType, - exceptionListAgnosticSavedObjectType, - exceptionListSavedObjectType, -} from '../../common/types'; - -export const getSavedObjectType = ({ - namespaceType, -}: { - namespaceType: NamespaceType; -}): SavedObjectType => { - if (namespaceType === 'agnostic') { - return exceptionListAgnosticSavedObjectType; - } else { - return exceptionListSavedObjectType; - } -}; - -export const getSavedObjectTypes = ({ - namespaceType, -}: { - namespaceType: NamespaceTypeArray; -}): SavedObjectType[] => { - return namespaceType.map((singleNamespaceType) => - getSavedObjectType({ namespaceType: singleNamespaceType }) - ); -}; - -export const getIdsAndNamespaces = ({ - lists, - showDetection, - showEndpoint, -}: { - lists: ExceptionListIdentifiers[]; - showDetection: boolean; - showEndpoint: boolean; -}): { ids: string[]; namespaces: NamespaceType[] } => - lists - .filter((list) => { - if (showDetection) { - return list.type === 'detection'; - } else if (showEndpoint) { - return list.type === 'endpoint'; - } else { - return true; - } - }) - .reduce<{ ids: string[]; namespaces: NamespaceType[] }>( - (acc, { listId, namespaceType }) => ({ - ids: [...acc.ids, listId], - namespaces: [...acc.namespaces, namespaceType], - }), - { ids: [], namespaces: [] } - ); - -export const getGeneralFilters = ( - filters: ExceptionListFilter, - namespaceTypes: SavedObjectType[] -): string => { - return Object.keys(filters) - .map((filterKey) => { - const value = get(filterKey, filters); - if (value != null && value.trim() !== '') { - const filtersByNamespace = namespaceTypes - .map((namespace) => { - const fieldToSearch = filterKey === 'name' ? 'name.text' : filterKey; - return `${namespace}.attributes.${fieldToSearch}:${value}`; - }) - .join(' OR '); - return `(${filtersByNamespace})`; - } else return null; - }) - .filter((item) => item != null) - .join(' AND '); -}; - -export const getTrustedAppsFilter = ( - showTrustedApps: boolean, - namespaceTypes: SavedObjectType[] -): string => { - if (showTrustedApps) { - const filters = namespaceTypes.map((namespace) => { - return `${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; - }); - return `(${filters.join(' OR ')})`; - } else { - const filters = namespaceTypes.map((namespace) => { - return `not ${namespace}.attributes.list_id: ${ENDPOINT_TRUSTED_APPS_LIST_ID}*`; - }); - return `(${filters.join(' AND ')})`; - } -}; - -export const getFilters = ( - filters: ExceptionListFilter, - namespaceTypes: NamespaceType[], - showTrustedApps: boolean -): string => { - const namespaces = getSavedObjectTypes({ namespaceType: namespaceTypes }); - const generalFilters = getGeneralFilters(filters, namespaces); - const trustedAppsFilter = getTrustedAppsFilter(showTrustedApps, namespaces); - return [generalFilters, trustedAppsFilter].filter((filter) => filter.trim() !== '').join(' AND '); -}; diff --git a/x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts index be2125b6f250a..46c139d1f3732 100644 --- a/x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_endpoint_list_item_route.ts @@ -12,9 +12,9 @@ import { createEndpointListItemSchema, exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_ID, ENDPOINT_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_ID, ENDPOINT_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, getExceptionListClient } from './utils'; import { validateExceptionListSize } from './validate'; diff --git a/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts b/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts index 0f30b7d40217f..134682d3a4283 100644 --- a/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_endpoint_list_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { createEndpointListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_URL } from '../../common/constants'; import { buildSiemResponse } from './utils'; import { getExceptionListClient } from './utils/get_exception_list_client'; diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts index e85c6480262f0..968f341b9decf 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts @@ -12,9 +12,9 @@ import { createExceptionListItemSchema, exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; import { getExceptionListClient } from './utils/get_exception_list_client'; diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts index fb515591745e4..22be6432a70c1 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts @@ -12,9 +12,9 @@ import { createExceptionListSchema, exceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; import { getExceptionListClient } from './utils/get_exception_list_client'; diff --git a/x-pack/plugins/lists/server/routes/create_list_index_route.ts b/x-pack/plugins/lists/server/routes/create_list_index_route.ts index db085befa5a2e..cebd6140c36aa 100644 --- a/x-pack/plugins/lists/server/routes/create_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_index_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { acknowledgeSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_INDEX } from '../../common/constants'; import { buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/create_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_list_item_route.ts index 961be259cd8d5..bbdc507ebdb69 100644 --- a/x-pack/plugins/lists/server/routes/create_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_item_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { createListItemSchema, listItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/create_list_route.ts b/x-pack/plugins/lists/server/routes/create_list_route.ts index 4135d6d794188..898f9b142d9db 100644 --- a/x-pack/plugins/lists/server/routes/create_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_route.ts @@ -12,9 +12,9 @@ import { createListSchema, listSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts index 725594c4cbf9e..650d2d11b0d1f 100644 --- a/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_endpoint_list_item_route.ts @@ -12,9 +12,9 @@ import { deleteEndpointListItemSchema, exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts index 0467b46c08491..7ec220bfb3a60 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts @@ -12,9 +12,9 @@ import { deleteExceptionListItemSchema, exceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts index 7df509690ae90..b4928d0262528 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts @@ -12,9 +12,9 @@ import { deleteExceptionListSchema, exceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/delete_list_index_route.ts b/x-pack/plugins/lists/server/routes/delete_list_index_route.ts index 15b15ec746f23..448c6c7692164 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_index_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { acknowledgeSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_INDEX } from '../../common/constants'; import { buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts index e9cc035dda85a..cd6c0ee038b4d 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts @@ -12,9 +12,9 @@ import { listItemArraySchema, listItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/delete_list_route.ts b/x-pack/plugins/lists/server/routes/delete_list_route.ts index e22fdc5df121e..35ac490826703 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_route.ts @@ -15,10 +15,10 @@ import { exceptionListItemSchema, listSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; -import { getSavedObjectType } from '../services/exception_lists/utils'; import { ExceptionListClient } from '../services/exception_lists/exception_list_client'; import { escapeQuotes } from '../services/utils/escape_query'; diff --git a/x-pack/plugins/lists/server/routes/export_exception_list_route.ts b/x-pack/plugins/lists/server/routes/export_exception_list_route.ts index 8f274d10a870b..a238d0e6529ff 100644 --- a/x-pack/plugins/lists/server/routes/export_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/export_exception_list_route.ts @@ -7,9 +7,9 @@ import { transformError } from '@kbn/securitysolution-es-utils'; import { exportExceptionListQuerySchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, getExceptionListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/export_list_item_route.ts b/x-pack/plugins/lists/server/routes/export_list_item_route.ts index d104f11024e93..413c911560e10 100644 --- a/x-pack/plugins/lists/server/routes/export_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/export_list_item_route.ts @@ -9,9 +9,9 @@ import { Stream } from 'stream'; import { transformError } from '@kbn/securitysolution-es-utils'; import { exportListItemQuerySchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts index 0284321ef4619..36b5a66c2830f 100644 --- a/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_endpoint_list_item_route.ts @@ -12,9 +12,9 @@ import { findEndpointListItemSchema, foundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_ID, ENDPOINT_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_ID, ENDPOINT_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, getExceptionListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts index fc3450d2277d5..fe7ffaa066281 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts @@ -12,9 +12,9 @@ import { findExceptionListItemSchema, foundExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, getExceptionListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts index 966aa1391a312..5d1b78747a89e 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts @@ -12,9 +12,9 @@ import { findExceptionListSchema, foundExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse, getExceptionListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/find_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_list_item_route.ts index 1ae60f7faba35..b0a4a386e21e8 100644 --- a/x-pack/plugins/lists/server/routes/find_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_list_item_route.ts @@ -12,9 +12,9 @@ import { findListItemSchema, foundListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { decodeCursor } from '../services/utils'; import { buildRouteValidation, buildSiemResponse, getListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/find_list_route.ts b/x-pack/plugins/lists/server/routes/find_list_route.ts index 31e2773359ee1..98697cc79030c 100644 --- a/x-pack/plugins/lists/server/routes/find_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_list_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { findListSchema, foundListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; import { decodeCursor } from '../services/utils'; import { buildRouteValidation, buildSiemResponse, getListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/import_list_item_route.ts index 3843f8389a4ed..a911a6bc26eb0 100644 --- a/x-pack/plugins/lists/server/routes/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/import_list_item_route.ts @@ -9,9 +9,9 @@ import { schema } from '@kbn/config-schema'; import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { importListItemQuerySchema, listSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { ConfigType } from '../config'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/patch_list_item_route.ts b/x-pack/plugins/lists/server/routes/patch_list_item_route.ts index 3e85e501bd216..7bbcab1b1dd62 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_item_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listItemSchema, patchListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/patch_list_route.ts b/x-pack/plugins/lists/server/routes/patch_list_route.ts index fb88432bb1960..da2ea0b65e413 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listSchema, patchListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts index be4a258cd5fb0..aed51fbb4a5d0 100644 --- a/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_endpoint_list_item_route.ts @@ -12,9 +12,9 @@ import { exceptionListItemSchema, readEndpointListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts index e114625cde6a3..d1afb35d41a30 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts @@ -12,9 +12,9 @@ import { exceptionListItemSchema, readExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts index e88eb9cbb0745..3b652db6fab63 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts @@ -12,9 +12,9 @@ import { exceptionListSchema, readExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/read_list_index_route.ts b/x-pack/plugins/lists/server/routes/read_list_index_route.ts index 34344fb1051d2..6fd15e628edb0 100644 --- a/x-pack/plugins/lists/server/routes/read_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_index_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listItemIndexExistSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_INDEX } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_INDEX } from '../../common/constants'; import { buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/read_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_list_item_route.ts index 80a0b4b83514f..2cb2c4e042884 100644 --- a/x-pack/plugins/lists/server/routes/read_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_item_route.ts @@ -12,9 +12,9 @@ import { listItemSchema, readListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/read_list_route.ts b/x-pack/plugins/lists/server/routes/read_list_route.ts index 3446d5af7b5f1..e4806f274d511 100644 --- a/x-pack/plugins/lists/server/routes/read_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listSchema, readListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/read_privileges_route.ts b/x-pack/plugins/lists/server/routes/read_privileges_route.ts index 8c7faa7f7eb9d..e0806a9f8f82e 100644 --- a/x-pack/plugins/lists/server/routes/read_privileges_route.ts +++ b/x-pack/plugins/lists/server/routes/read_privileges_route.ts @@ -7,9 +7,9 @@ import { readPrivileges, transformError } from '@kbn/securitysolution-es-utils'; import { merge } from 'lodash/fp'; +import { LIST_PRIVILEGES_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_PRIVILEGES_URL } from '../../common/constants'; import { buildSiemResponse, getListClient } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts index 4f00c94bda73a..2c960736460dd 100644 --- a/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_endpoint_list_item_route.ts @@ -12,9 +12,9 @@ import { exceptionListItemSchema, updateEndpointListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { ENDPOINT_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts index 453fdcbdfd916..910d78e68061e 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts @@ -13,9 +13,9 @@ import { updateExceptionListItemSchema, updateExceptionListItemValidate, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index ef3da5506ab23..43279e1f1045d 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -12,9 +12,9 @@ import { exceptionListSchema, updateExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { EXCEPTION_LIST_URL } from '../../common/constants'; import { buildRouteValidation, diff --git a/x-pack/plugins/lists/server/routes/update_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_list_item_route.ts index a8a0189dbb24b..07ba8539ae624 100644 --- a/x-pack/plugins/lists/server/routes/update_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_item_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listItemSchema, updateListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_ITEM_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/update_list_route.ts b/x-pack/plugins/lists/server/routes/update_list_route.ts index c4293d7ca72f4..47ab77b444196 100644 --- a/x-pack/plugins/lists/server/routes/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_route.ts @@ -8,9 +8,9 @@ import { validate } from '@kbn/securitysolution-io-ts-utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { listSchema, updateListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import type { ListsPluginRouter } from '../types'; -import { LIST_URL } from '../../common/constants'; import { buildRouteValidation, buildSiemResponse } from './utils'; diff --git a/x-pack/plugins/lists/server/routes/validate.ts b/x-pack/plugins/lists/server/routes/validate.ts index 21e2ad187d045..5a118bf2c5ae0 100644 --- a/x-pack/plugins/lists/server/routes/validate.ts +++ b/x-pack/plugins/lists/server/routes/validate.ts @@ -15,9 +15,9 @@ import { foundExceptionListItemSchema, nonEmptyEndpointEntriesArray, } from '@kbn/securitysolution-io-ts-list-types'; +import { MAX_EXCEPTION_LIST_SIZE } from '@kbn/securitysolution-list-constants'; import { ExceptionListClient } from '../services/exception_lists/exception_list_client'; -import { MAX_EXCEPTION_LIST_SIZE } from '../../common/constants'; export const validateExceptionListSize = async ( exceptionLists: ExceptionListClient, diff --git a/x-pack/plugins/lists/server/saved_objects/exception_list.ts b/x-pack/plugins/lists/server/saved_objects/exception_list.ts index d380e821034e9..8354e64d64a6e 100644 --- a/x-pack/plugins/lists/server/saved_objects/exception_list.ts +++ b/x-pack/plugins/lists/server/saved_objects/exception_list.ts @@ -6,11 +6,10 @@ */ import { SavedObjectsType } from 'kibana/server'; - import { exceptionListAgnosticSavedObjectType, exceptionListSavedObjectType, -} from '../../common/types'; +} from '@kbn/securitysolution-list-utils'; import { migrations } from './migrations'; diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.test.ts b/x-pack/plugins/lists/server/saved_objects/migrations.test.ts index 27c883d8b9674..7fea07f479cc8 100644 --- a/x-pack/plugins/lists/server/saved_objects/migrations.test.ts +++ b/x-pack/plugins/lists/server/saved_objects/migrations.test.ts @@ -7,8 +7,11 @@ import { SavedObjectUnsanitizedDoc } from 'kibana/server'; import uuid from 'uuid'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; -import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants'; import { ExceptionListSoSchema } from '../schemas/saved_objects'; import { OldExceptionListSoSchema, migrations } from './migrations'; diff --git a/x-pack/plugins/lists/server/saved_objects/migrations.ts b/x-pack/plugins/lists/server/saved_objects/migrations.ts index 485bd493f309e..ec6617f6b4730 100644 --- a/x-pack/plugins/lists/server/saved_objects/migrations.ts +++ b/x-pack/plugins/lists/server/saved_objects/migrations.ts @@ -14,8 +14,11 @@ import { entriesNested, entry, } from '@kbn/securitysolution-io-ts-list-types'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; -import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../common/constants'; import { ExceptionListSoSchema } from '../schemas/saved_objects'; const entryType = t.union([entry, entriesNested]); diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endoint_event_filters_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_endoint_event_filters_list.ts index c2a7218f1cef8..fda8de5da8aae 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_endoint_event_filters_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_endoint_event_filters_list.ts @@ -9,15 +9,16 @@ import { SavedObjectsClientContract } from 'kibana/server'; import uuid from 'uuid'; import { Version } from '@kbn/securitysolution-io-ts-types'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; - +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION, ENDPOINT_EVENT_FILTERS_LIST_ID, ENDPOINT_EVENT_FILTERS_LIST_NAME, -} from '../../../common/constants'; +} from '@kbn/securitysolution-list-constants'; + import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; +import { transformSavedObjectToExceptionList } from './utils'; interface CreateEndpointEventFiltersListOptions { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts index aaf18362ec745..a677e260d0848 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_list.ts @@ -9,15 +9,16 @@ import { SavedObjectsClientContract } from 'kibana/server'; import uuid from 'uuid'; import { Version } from '@kbn/securitysolution-io-ts-types'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; - +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ENDPOINT_LIST_DESCRIPTION, ENDPOINT_LIST_ID, ENDPOINT_LIST_NAME, -} from '../../../common/constants'; +} from '@kbn/securitysolution-list-constants'; + import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; +import { transformSavedObjectToExceptionList } from './utils'; interface CreateEndpointListOptions { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts index a85f6da0f8b8f..4275e23032a76 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_endpoint_trusted_apps_list.ts @@ -9,15 +9,16 @@ import { SavedObjectsClientContract } from 'kibana/server'; import uuid from 'uuid'; import type { Version } from '@kbn/securitysolution-io-ts-types'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; - +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ENDPOINT_TRUSTED_APPS_LIST_DESCRIPTION, ENDPOINT_TRUSTED_APPS_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_NAME, -} from '../../../common/constants'; +} from '@kbn/securitysolution-list-constants'; + import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; +import { transformSavedObjectToExceptionList } from './utils'; interface CreateEndpointListOptions { savedObjectsClient: SavedObjectsClientContract; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts index f1d1f15a576a0..60a53af4deb75 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list.ts @@ -19,10 +19,11 @@ import type { Tags, } from '@kbn/securitysolution-io-ts-list-types'; import { Version } from '@kbn/securitysolution-io-ts-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; +import { transformSavedObjectToExceptionList } from './utils'; interface CreateExceptionListOptions { listId: ListId; diff --git a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts index 763ee8e3d85c7..9771c7d485e50 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/create_exception_list_item.ts @@ -21,11 +21,11 @@ import type { OsTypeArray, Tags, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; import { - getSavedObjectType, transformCreateCommentsToComments, transformSavedObjectToExceptionListItem, } from './utils'; diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts index def0585740d45..be71f4c79577a 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list.ts @@ -12,8 +12,8 @@ import type { ListIdOrUndefined, NamespaceType, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; -import { getSavedObjectType } from './utils'; import { getExceptionList } from './get_exception_list'; import { deleteExceptionListItemByList } from './delete_exception_list_items_by_list'; diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts index 65df08a445b58..89ea0baf22caf 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_item.ts @@ -13,8 +13,8 @@ import type { ItemIdOrUndefined, NamespaceType, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; -import { getSavedObjectType } from './utils'; import { getExceptionListItem } from './get_exception_list_item'; interface DeleteExceptionListItemOptions { diff --git a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts index b3190d174bb71..aa2bd55e24999 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/delete_exception_list_items_by_list.ts @@ -6,11 +6,11 @@ */ import type { ListId, NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { SavedObjectsClientContract } from '../../../../../../src/core/server/'; import { findExceptionListItem } from './find_exception_list_item'; -import { getSavedObjectType } from './utils'; const PER_PAGE = 100; diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts index a613219776004..803cd04c1d1b4 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.ts @@ -12,8 +12,7 @@ import type { FoundExceptionListItemSchema, FoundExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; - -import { ENDPOINT_LIST_ID } from '../../../common/constants'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { ConstructorOptions, diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts index 314cfc75e5a11..b3d5dd9ddb32b 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list.ts @@ -15,11 +15,11 @@ import type { SortFieldOrUndefined, SortOrderOrUndefined, } from '@kbn/securitysolution-io-ts-list-types'; +import { SavedObjectType, getSavedObjectTypes } from '@kbn/securitysolution-list-utils'; -import { SavedObjectType } from '../../../common/types'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectTypes, transformSavedObjectsToFoundExceptionList } from './utils'; +import { transformSavedObjectsToFoundExceptionList } from './utils'; interface FindExceptionListOptions { namespaceType: NamespaceTypeArray; diff --git a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts index 04eca6a042ace..99298c0304c7d 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/find_exception_list_items.ts @@ -19,16 +19,17 @@ import type { EmptyStringArrayDecoded, NonEmptyStringArrayDecoded, } from '@kbn/securitysolution-io-ts-types'; - import { SavedObjectType, exceptionListAgnosticSavedObjectType, exceptionListSavedObjectType, -} from '../../../common/types'; + getSavedObjectTypes, +} from '@kbn/securitysolution-list-utils'; + import { escapeQuotes } from '../utils/escape_query'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectTypes, transformSavedObjectsToFoundExceptionListItem } from './utils'; +import { transformSavedObjectsToFoundExceptionListItem } from './utils'; import { getExceptionList } from './get_exception_list'; interface FindExceptionListItemsOptions { diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts index e1dc8bfe98847..2b09642f59c9c 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list.ts @@ -11,6 +11,7 @@ import type { ListIdOrUndefined, NamespaceType, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { SavedObjectsClientContract, @@ -18,7 +19,7 @@ import { } from '../../../../../../src/core/server/'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionList } from './utils'; +import { transformSavedObjectToExceptionList } from './utils'; interface GetExceptionListOptions { id: IdOrUndefined; diff --git a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts index a8b201cff0397..ef825b4cf5e3e 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/get_exception_list_item.ts @@ -11,6 +11,7 @@ import type { ItemIdOrUndefined, NamespaceType, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { SavedObjectsClientContract, @@ -18,7 +19,7 @@ import { } from '../../../../../../src/core/server/'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectToExceptionListItem } from './utils'; +import { transformSavedObjectToExceptionListItem } from './utils'; interface GetExceptionListItemOptions { id: IdOrUndefined; diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts index 0cdae4375fa59..53e0f82a2ba76 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list.ts @@ -20,10 +20,11 @@ import type { _VersionOrUndefined, } from '@kbn/securitysolution-io-ts-list-types'; import { VersionOrUndefined } from '@kbn/securitysolution-io-ts-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -import { getSavedObjectType, transformSavedObjectUpdateToExceptionList } from './utils'; +import { transformSavedObjectUpdateToExceptionList } from './utils'; import { getExceptionList } from './get_exception_list'; interface UpdateExceptionListOptions { diff --git a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts index 2c1f5b81b2bcf..d0505a9513385 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/update_exception_list_item.ts @@ -21,11 +21,11 @@ import type { UpdateCommentsArrayOrUndefined, _VersionOrUndefined, } from '@kbn/securitysolution-io-ts-list-types'; +import { getSavedObjectType } from '@kbn/securitysolution-list-utils'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; import { - getSavedObjectType, transformSavedObjectUpdateToExceptionListItem, transformUpdateCommentsToComments, } from './utils'; diff --git a/x-pack/plugins/lists/server/services/exception_lists/utils.ts b/x-pack/plugins/lists/server/services/exception_lists/utils.ts index 7479510110709..610f73d4c2e80 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/utils.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/utils.ts @@ -15,54 +15,14 @@ import { ExceptionListSchema, FoundExceptionListItemSchema, FoundExceptionListSchema, - NamespaceType, - NamespaceTypeArray, UpdateCommentsArrayOrUndefined, exceptionListItemType, exceptionListType, } from '@kbn/securitysolution-io-ts-list-types'; +import { getExceptionListType } from '@kbn/securitysolution-list-utils'; -import { - SavedObjectType, - exceptionListAgnosticSavedObjectType, - exceptionListSavedObjectType, -} from '../../../common/types'; import { ExceptionListSoSchema } from '../../schemas/saved_objects'; -export const getSavedObjectType = ({ - namespaceType, -}: { - namespaceType: NamespaceType; -}): SavedObjectType => { - if (namespaceType === 'agnostic') { - return exceptionListAgnosticSavedObjectType; - } else { - return exceptionListSavedObjectType; - } -}; - -export const getExceptionListType = ({ - savedObjectType, -}: { - savedObjectType: string; -}): NamespaceType => { - if (savedObjectType === exceptionListAgnosticSavedObjectType) { - return 'agnostic'; - } else { - return 'single'; - } -}; - -export const getSavedObjectTypes = ({ - namespaceType, -}: { - namespaceType: NamespaceTypeArray; -}): SavedObjectType[] => { - return namespaceType.map((singleNamespaceType) => - getSavedObjectType({ namespaceType: singleNamespaceType }) - ); -}; - export const transformSavedObjectToExceptionList = ({ savedObject, }: { diff --git a/x-pack/plugins/security_solution/common/detection_engine/parse_schedule_dates.ts b/x-pack/plugins/security_solution/common/detection_engine/parse_schedule_dates.ts deleted file mode 100644 index efb015ef73175..0000000000000 --- a/x-pack/plugins/security_solution/common/detection_engine/parse_schedule_dates.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import moment from 'moment'; -import dateMath from '@elastic/datemath'; - -export const parseScheduleDates = (time: string): moment.Moment | null => { - const isValidDateString = !isNaN(Date.parse(time)); - const isValidInput = isValidDateString || time.trim().startsWith('now'); - const formattedDate = isValidDateString - ? moment(time) - : isValidInput - ? dateMath.parse(time) - : null; - - return formattedDate ?? null; -}; diff --git a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/lists.mock.ts b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/lists.mock.ts index 70f41539e8466..1114c2b5d0fe9 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/schemas/types/lists.mock.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/schemas/types/lists.mock.ts @@ -6,7 +6,7 @@ */ import { List, ListArray } from '@kbn/securitysolution-io-ts-list-types'; -import { ENDPOINT_LIST_ID } from '../../../shared_imports'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; export const getListMock = (): List => ({ id: 'some_uuid', diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts index 1e0f7e087a5b3..52cd4e79e6a6b 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.test.ts @@ -7,13 +7,14 @@ import { hasEqlSequenceQuery, - hasLargeValueList, hasNestedEntry, isThreatMatchRule, normalizeMachineLearningJobIds, normalizeThresholdField, } from './utils'; +import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; + import type { EntriesArray } from '@kbn/securitysolution-io-ts-list-types'; describe('#hasLargeValueList', () => { diff --git a/x-pack/plugins/security_solution/common/detection_engine/utils.ts b/x-pack/plugins/security_solution/common/detection_engine/utils.ts index 56f2a11900dd3..f3f2280c4b837 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/utils.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/utils.ts @@ -14,6 +14,7 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; import { JobStatus, Threshold, ThresholdNormalized } from './schemas/common/schemas'; @@ -23,11 +24,6 @@ export const hasLargeValueItem = ( return exceptionItems.some((exceptionItem) => hasLargeValueList(exceptionItem.entries)); }; -export const hasLargeValueList = (entries: EntriesArray): boolean => { - const found = entries.filter(({ type }) => type === 'list'); - return found.length > 0; -}; - export const hasNestedEntry = (entries: EntriesArray): boolean => { const found = entries.filter(({ type }) => type === 'nested'); return found.length > 0; diff --git a/x-pack/plugins/security_solution/common/endpoint/data_generators/event_filter_generator.ts b/x-pack/plugins/security_solution/common/endpoint/data_generators/event_filter_generator.ts index c09f098979160..8f0be96f61ddc 100644 --- a/x-pack/plugins/security_solution/common/endpoint/data_generators/event_filter_generator.ts +++ b/x-pack/plugins/security_solution/common/endpoint/data_generators/event_filter_generator.ts @@ -6,8 +6,8 @@ */ import type { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '@kbn/securitysolution-list-constants'; import { BaseDataGenerator } from './base_data_generator'; -import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '../../../../lists/common/constants'; import { getCreateExceptionListItemSchemaMock } from '../../../../lists/common/schemas/request/create_exception_list_item_schema.mock'; export class EventFilterGenerator extends BaseDataGenerator { diff --git a/x-pack/plugins/security_solution/common/fp_utils.ts b/x-pack/plugins/security_solution/common/fp_utils.ts deleted file mode 100644 index f6c0425073f86..0000000000000 --- a/x-pack/plugins/security_solution/common/fp_utils.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { pipe } from 'fp-ts/lib/pipeable'; -import { TaskEither } from 'fp-ts/lib/TaskEither'; -import { fold } from 'fp-ts/lib/Either'; - -export const toPromise = async (taskEither: TaskEither): Promise => - pipe( - await taskEither(), - fold( - (e) => Promise.reject(e), - (a) => Promise.resolve(a) - ) - ); - -export const toError = (e: unknown): Error => (e instanceof Error ? e : new Error(String(e))); diff --git a/x-pack/plugins/security_solution/common/shared_imports.ts b/x-pack/plugins/security_solution/common/shared_imports.ts deleted file mode 100644 index 0fb63f6a64686..0000000000000 --- a/x-pack/plugins/security_solution/common/shared_imports.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { - ENDPOINT_LIST_ID, - ENDPOINT_TRUSTED_APPS_LIST_ID, - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, - ENDPOINT_EVENT_FILTERS_LIST_ID, - ENDPOINT_EVENT_FILTERS_LIST_NAME, - ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION, -} from '../../lists/common'; diff --git a/x-pack/plugins/security_solution/public/common/components/exceptions/use_fetch_or_create_rule_exception_list.tsx b/x-pack/plugins/security_solution/public/common/components/exceptions/use_fetch_or_create_rule_exception_list.tsx index 527f470217b42..4d6464d09ee60 100644 --- a/x-pack/plugins/security_solution/public/common/components/exceptions/use_fetch_or_create_rule_exception_list.tsx +++ b/x-pack/plugins/security_solution/public/common/components/exceptions/use_fetch_or_create_rule_exception_list.tsx @@ -17,6 +17,7 @@ import { addExceptionList, addEndpointExceptionList, } from '@kbn/securitysolution-list-api'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { HttpStart } from '../../../../../../../src/core/public'; import { Rule } from '../../../detections/containers/detection_engine/rules/types'; @@ -24,7 +25,6 @@ import { fetchRuleById, patchRule, } from '../../../detections/containers/detection_engine/rules/api'; -import { ENDPOINT_LIST_ID } from '../../../../common/shared_imports'; export type ReturnUseFetchOrCreateRuleExceptionList = [boolean, ExceptionListSchema | null]; diff --git a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts index 788ce00ba1b1d..2c9e37c6930f4 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/eql/use_eql_preview.ts @@ -10,6 +10,7 @@ import { noop } from 'lodash/fp'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import * as i18n from '../translations'; import { useKibana } from '../../../common/lib/kibana'; import { @@ -24,7 +25,6 @@ import { formatInspect, getEqlAggsData } from './helpers'; import { EqlPreviewResponse, EqlPreviewRequest, Source } from './types'; import { hasEqlSequenceQuery } from '../../../../common/detection_engine/utils'; import { EqlSearchResponse } from '../../../../common/detection_engine/types'; -import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates'; import { inputsModel } from '../../../common/store'; import { EQL_SEARCH_STRATEGY } from '../../../../../data_enhanced/public'; import { useAppToasts } from '../use_app_toasts'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts index 5259b95a09ae6..44a85cb2028c0 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/create/helpers.ts @@ -20,10 +20,10 @@ import { ThreatTechnique, Type, } from '@kbn/securitysolution-io-ts-alerting-types'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { NOTIFICATION_THROTTLE_NO_ACTIONS } from '../../../../../../common/constants'; import { assertUnreachable } from '../../../../../../common/utility_types'; import { transformAlertToRuleAction } from '../../../../../../common/detection_engine/transform_actions'; -import { ENDPOINT_LIST_ID } from '../../../../../shared_imports'; import { Rule } from '../../../../containers/detection_engine/rules'; import { AboutStepRule, diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 25785f6bbcb2d..a88ff9bb2c921 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -18,13 +18,13 @@ import { SeverityMapping, Severity, } from '@kbn/securitysolution-io-ts-alerting-types'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { ActionVariables } from '../../../../../../triggers_actions_ui/public'; import { normalizeThresholdField } from '../../../../../common/detection_engine/utils'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { assertUnreachable } from '../../../../../common/utility_types'; import { transformRuleToAlertAction } from '../../../../../common/detection_engine/transform_actions'; import { Filter } from '../../../../../../../../src/plugins/data/public'; -import { ENDPOINT_LIST_ID } from '../../../../shared_imports'; import { Rule } from '../../../containers/detection_engine/rules'; import { AboutStepRule, diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts index e1fa1107fcb01..6fb6b8081596e 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/constants.ts @@ -12,7 +12,7 @@ import { ENDPOINT_EVENT_FILTERS_LIST_ID, ENDPOINT_EVENT_FILTERS_LIST_NAME, ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION, -} from '../../../../common/shared_imports'; +} from '@kbn/securitysolution-list-constants'; export const EVENT_FILTER_LIST_TYPE: ExceptionListType = ExceptionListTypeEnum.ENDPOINT_EVENTS; export const EVENT_FILTER_LIST = { diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts index 30b4c81ba0c3b..8863acaafbf5a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/service/index.ts @@ -12,7 +12,7 @@ import type { CreateExceptionListItemSchema, UpdateExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '../../../../shared_imports'; +import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '@kbn/securitysolution-list-constants'; import { Immutable } from '../../../../../common/endpoint/types'; diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/test_utils/index.ts b/x-pack/plugins/security_solution/public/management/pages/event_filters/test_utils/index.ts index 69a8ee383be8e..dc235cf511157 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/test_utils/index.ts +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/test_utils/index.ts @@ -10,13 +10,13 @@ import type { FoundExceptionListItemSchema, ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { Ecs } from '../../../../../common/ecs'; import { MANAGEMENT_STORE_GLOBAL_NAMESPACE, MANAGEMENT_STORE_EVENT_FILTERS_NAMESPACE, } from '../../../common/constants'; -import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '../../../../shared_imports'; import { eventFiltersPageReducer } from '../store/reducer'; import { diff --git a/x-pack/plugins/security_solution/public/shared_imports.ts b/x-pack/plugins/security_solution/public/shared_imports.ts index fb55d16fe9dfb..dda4179cd853c 100644 --- a/x-pack/plugins/security_solution/public/shared_imports.ts +++ b/x-pack/plugins/security_solution/public/shared_imports.ts @@ -5,8 +5,6 @@ * 2.0. */ -export * from '../common/shared_imports'; - export { getUseField, getFieldValidityAndErrorMessage, diff --git a/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts b/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts index e3579d11331de..8ccc7c3913326 100644 --- a/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts +++ b/x-pack/plugins/security_solution/scripts/endpoint/event_filters/index.ts @@ -10,14 +10,14 @@ import { KbnClient } from '@kbn/test'; import { AxiosError } from 'axios'; import bluebird from 'bluebird'; import type { CreateExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { EventFilterGenerator } from '../../../common/endpoint/data_generators/event_filter_generator'; import { ENDPOINT_EVENT_FILTERS_LIST_DESCRIPTION, ENDPOINT_EVENT_FILTERS_LIST_ID, ENDPOINT_EVENT_FILTERS_LIST_NAME, EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL, -} from '../../../../lists/common/constants'; +} from '@kbn/securitysolution-list-constants'; +import { EventFilterGenerator } from '../../../common/endpoint/data_generators/event_filter_generator'; export const cli = () => { run( diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts index 9df242469752e..16cbe618c5076 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.test.ts @@ -18,7 +18,10 @@ import { } from './lists'; import { TranslatedEntry, TranslatedExceptionListItem } from '../../schemas/artifacts'; import { ArtifactConstants } from './common'; -import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; describe('artifacts lists', () => { let mockExceptionClient: ExceptionListClient; diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts index 26212da1355db..d2fad90d9e7d6 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/lists.ts @@ -14,8 +14,12 @@ import type { } from '@kbn/securitysolution-io-ts-list-types'; import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { + ENDPOINT_EVENT_FILTERS_LIST_ID, + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; import { ExceptionListClient } from '../../../../../lists/server'; -import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../common/shared_imports'; import { internalArtifactCompleteSchema, InternalArtifactCompleteSchema, @@ -33,7 +37,6 @@ import { WrappedTranslatedExceptionList, wrappedTranslatedExceptionList, } from '../../schemas'; -import { ENDPOINT_EVENT_FILTERS_LIST_ID } from '../../../../../lists/common/constants'; export async function buildArtifact( exceptions: WrappedTranslatedExceptionList, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts index 1a4ff2812cd23..8558f9a24d213 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/mapping.ts @@ -17,7 +17,7 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common/constants'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { CreateExceptionListItemOptions, UpdateExceptionListItemOptions, diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts index 081010ea0098a..33fbcd47a1c93 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.test.ts @@ -25,7 +25,7 @@ import { import { TrustedAppNotFoundError, TrustedAppVersionConflictError } from './errors'; import { toUpdateTrustedApp } from '../../../../common/endpoint/service/trusted_apps/to_update_trusted_app'; import { updateExceptionListItemImplementationMock } from './test_utils'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; const exceptionsListClient = listMock.getExceptionListClient() as jest.Mocked; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts index c30a7a9a38cdc..4456004022261 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/trusted_apps/service.ts @@ -6,8 +6,8 @@ */ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '@kbn/securitysolution-list-constants'; import { ExceptionListClient } from '../../../../../lists/server'; -import { ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../lists/common'; import { DeleteTrustedAppsRequestParams, diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index 71be2400e2681..e1de39482428d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -7,7 +7,10 @@ import { inflateSync } from 'zlib'; import { savedObjectsClientMock } from 'src/core/server/mocks'; -import { ENDPOINT_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID } from '../../../../../../lists/common'; +import { + ENDPOINT_LIST_ID, + ENDPOINT_TRUSTED_APPS_LIST_ID, +} from '@kbn/securitysolution-list-constants'; import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; import { PackagePolicy } from '../../../../../../fleet/common/types/models'; import { getEmptyInternalArtifactMock } from '../../../schemas/artifacts/saved_objects.mock'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_saved_object.ts index 3aee9db31bf1b..bb9f7599ca6d5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/create_migration_saved_object.ts @@ -10,7 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { SavedObjectsClientContract } from 'src/core/server'; import { validateTaskEither } from '@kbn/securitysolution-io-ts-utils'; -import { toError, toPromise } from '../../../../common/fp_utils'; +import { toError, toPromise } from '@kbn/securitysolution-list-api'; import { signalsMigrationSOClient } from './saved_objects_client'; import { signalsMigrationSO, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/update_migration_saved_object.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/update_migration_saved_object.ts index 5bd8b47c3b74a..91919246c15a3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/update_migration_saved_object.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/migrations/update_migration_saved_object.ts @@ -10,7 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { SavedObjectsClientContract, SavedObjectsUpdateResponse } from 'src/core/server'; import { validateTaskEither } from '@kbn/securitysolution-io-ts-utils'; -import { toError, toPromise } from '../../../../common/fp_utils'; +import { toError, toPromise } from '@kbn/securitysolution-list-api'; import { signalsMigrationSOClient } from './saved_objects_client'; import { SignalsMigrationSOUpdateAttributes, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts index c1393924e3d29..6f8dac5b49b31 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/notifications/rules_notification_alert_type.ts @@ -7,6 +7,7 @@ import { Logger } from 'src/core/server'; import { schema } from '@kbn/config-schema'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import { DEFAULT_RULE_NOTIFICATION_QUERY_SIZE, NOTIFICATIONS_ID, @@ -18,7 +19,6 @@ import { AlertAttributes } from '../signals/types'; import { siemRuleActionGroups } from '../signals/siem_rule_action_groups'; import { scheduleNotificationActions } from './schedule_notification_actions'; import { getNotificationResultsLink } from './utils'; -import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates'; import { getSignals } from './get_signals'; export const rulesNotificationAlertType = ({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/filter_events_against_list.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/filter_events_against_list.ts index 198a1e805febe..5907cbdfb7fdd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/filter_events_against_list.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/filters/filter_events_against_list.ts @@ -8,7 +8,8 @@ import type { estypes } from '@elastic/elasticsearch'; import { entriesList, ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { hasLargeValueList } from '../../../../../common/detection_engine/utils'; +import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; + import { FilterEventsAgainstListOptions } from './types'; import { filterEvents } from './filter_events'; import { createFieldAndSetTuples } from './create_field_and_set_tuples'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts index 0f6ff40eaffb8..66f7d41df94ab 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.test.ts @@ -18,7 +18,7 @@ import { checkPrivileges, createSearchAfterReturnType, } from './utils'; -import * as parseScheduleDates from '../../../../common/detection_engine/parse_schedule_dates'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import { RuleExecutorOptions, SearchAfterAndBulkCreateReturnType } from './types'; import { scheduleNotificationActions } from '../notifications/schedule_notification_actions'; import { RuleAlertType } from '../rules/types'; @@ -48,6 +48,13 @@ jest.mock('./utils', () => { jest.mock('../notifications/schedule_notification_actions'); jest.mock('./executors/query'); jest.mock('./executors/ml'); +jest.mock('@kbn/securitysolution-io-ts-utils', () => { + const original = jest.requireActual('@kbn/securitysolution-io-ts-utils'); + return { + ...original, + parseScheduleDates: jest.fn(), + }; +}); const getPayload = ( ruleAlert: RuleAlertType, @@ -149,6 +156,7 @@ describe('signal_rule_alert_type', () => { (queryExecutor as jest.Mock).mockResolvedValue(executorReturnValue); (mlExecutor as jest.Mock).mockClear(); (mlExecutor as jest.Mock).mockResolvedValue(executorReturnValue); + (parseScheduleDates as jest.Mock).mockReturnValue(moment(100)); const value: Partial> = { statusCode: 200, body: { @@ -348,11 +356,7 @@ describe('signal_rule_alert_type', () => { }); payload.params.meta = {}; - const parseScheduleDatesSpy = jest - .spyOn(parseScheduleDates, 'parseScheduleDates') - .mockReturnValue(moment(100)); await alert.executor(payload); - parseScheduleDatesSpy.mockRestore(); expect(scheduleNotificationActions).toHaveBeenCalledWith( expect.objectContaining({ @@ -385,11 +389,7 @@ describe('signal_rule_alert_type', () => { }); delete payload.params.meta; - const parseScheduleDatesSpy = jest - .spyOn(parseScheduleDates, 'parseScheduleDates') - .mockReturnValue(moment(100)); await alert.executor(payload); - parseScheduleDatesSpy.mockRestore(); expect(scheduleNotificationActions).toHaveBeenCalledWith( expect.objectContaining({ @@ -422,11 +422,7 @@ describe('signal_rule_alert_type', () => { }); payload.params.meta = { kibana_siem_app_url: 'http://localhost' }; - const parseScheduleDatesSpy = jest - .spyOn(parseScheduleDates, 'parseScheduleDates') - .mockReturnValue(moment(100)); await alert.executor(payload); - parseScheduleDatesSpy.mockRestore(); expect(scheduleNotificationActions).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts index d00bcc2a9f11e..13a63df6ed8b6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/signal_rule_alert_type.ts @@ -12,8 +12,8 @@ import { chain, tryCatch } from 'fp-ts/lib/TaskEither'; import { flow } from 'fp-ts/lib/function'; import * as t from 'io-ts'; -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; -import { toError, toPromise } from '../../../../common/fp_utils'; +import { validateNonExact, parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; +import { toError, toPromise } from '@kbn/securitysolution-list-api'; import { SIGNALS_ID, @@ -27,7 +27,6 @@ import { isThreatMatchRule, isQueryRule, } from '../../../../common/detection_engine/utils'; -import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates'; import { SetupPlugins } from '../../../plugin'; import { getInputIndex } from './get_input_output_index'; import { AlertAttributes, SignalRuleAlertTypeDefinition } from './types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts index 37959a5ee877b..b04eab1496e96 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.test.ts @@ -15,7 +15,6 @@ import { buildRuleMessageFactory } from './rule_messages'; import { ExceptionListClient } from '../../../../../lists/server'; import { getListArrayMock } from '../../../../common/detection_engine/schemas/types/lists.mock'; import { getExceptionListItemSchemaMock } from '../../../../../lists/common/schemas/response/exception_list_item_schema.mock'; -import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates'; // @ts-expect-error moment.suppressDeprecationWarnings = true; @@ -115,34 +114,6 @@ describe('utils', () => { }); }); - describe('parseScheduleDates', () => { - test('it returns a moment when given an ISO string', () => { - const result = parseScheduleDates('2020-01-01T00:00:00.000Z'); - expect(result).not.toBeNull(); - expect(result).toEqual(moment('2020-01-01T00:00:00.000Z')); - }); - - test('it returns a moment when given `now`', () => { - const result = parseScheduleDates('now'); - - expect(result).not.toBeNull(); - expect(moment.isMoment(result)).toBeTruthy(); - }); - - test('it returns a moment when given `now-x`', () => { - const result = parseScheduleDates('now-6m'); - - expect(result).not.toBeNull(); - expect(moment.isMoment(result)).toBeTruthy(); - }); - - test('it returns null when given a string that is not an ISO string, `now` or `now-x`', () => { - const result = parseScheduleDates('invalid'); - - expect(result).toBeNull(); - }); - }); - describe('getDriftTolerance', () => { test('it returns a drift tolerance in milliseconds of 1 minute when "from" overlaps "to" by 1 minute and the interval is 5 minutes', () => { const drift = getDriftTolerance({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts index 488a46ab4748d..03a067af6066d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/utils.ts @@ -15,6 +15,9 @@ import { ApiResponse, Context } from '@elastic/elasticsearch/lib/Transport'; import { SortResults } from '@elastic/elasticsearch/api/types'; import type { ListArray, ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { MAX_EXCEPTION_LIST_SIZE } from '@kbn/securitysolution-list-constants'; +import { hasLargeValueList } from '@kbn/securitysolution-list-utils'; +import { parseScheduleDates } from '@kbn/securitysolution-io-ts-utils'; import { TimestampOverrideOrUndefined, Privilege, @@ -37,9 +40,6 @@ import { RuleRangeTuple, } from './types'; import { BuildRuleMessage } from './rule_messages'; -import { parseScheduleDates } from '../../../../common/detection_engine/parse_schedule_dates'; -import { hasLargeValueList } from '../../../../common/detection_engine/utils'; -import { MAX_EXCEPTION_LIST_SIZE } from '../../../../../lists/common/constants'; import { ShardError } from '../../types'; import { RuleStatusService } from './rule_status_service'; import { diff --git a/x-pack/test/api_integration/apis/lists/create_exception_list_item.ts b/x-pack/test/api_integration/apis/lists/create_exception_list_item.ts index d2f82b374e02a..db3cdd17a89dc 100644 --- a/x-pack/test/api_integration/apis/lists/create_exception_list_item.ts +++ b/x-pack/test/api_integration/apis/lists/create_exception_list_item.ts @@ -6,8 +6,8 @@ */ import expect from '@kbn/expect/expect.js'; +import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { ENDPOINT_LIST_ID } from '../../../../plugins/lists/common'; export default function ({ getService }: FtrProviderContext) { const esArchiver = getService('esArchiver'); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts index c014d08e91f66..6a14de3c47608 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/tests/create_exceptions.ts @@ -9,6 +9,7 @@ import expect from '@kbn/expect'; import type { CreateExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { CreateRulesSchema, EqlCreateSchema, @@ -25,10 +26,6 @@ import { } from '../../../lists_api_integration/utils'; import { RulesSchema } from '../../../../plugins/security_solution/common/detection_engine/schemas/response'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; -import { - EXCEPTION_LIST_ITEM_URL, - EXCEPTION_LIST_URL, -} from '../../../../plugins/lists/common/constants'; import { DETECTION_ENGINE_RULES_URL } from '../../../../plugins/security_solution/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; diff --git a/x-pack/test/detection_engine_api_integration/utils.ts b/x-pack/test/detection_engine_api_integration/utils.ts index 3a06ea1c8bc7a..9c5beebd64b3d 100644 --- a/x-pack/test/detection_engine_api_integration/utils.ts +++ b/x-pack/test/detection_engine_api_integration/utils.ts @@ -19,6 +19,7 @@ import type { ExceptionListItemSchema, ExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { PrePackagedRulesAndTimelinesStatusSchema } from '../../plugins/security_solution/common/detection_engine/schemas/response'; import { getCreateExceptionListDetectionSchemaMock } from '../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { @@ -27,7 +28,6 @@ import { FullResponseSchema, QueryCreateSchema, } from '../../plugins/security_solution/common/detection_engine/schemas/request'; -import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '../../plugins/lists/common/constants'; import { Signal } from '../../plugins/security_solution/server/lib/detection_engine/signals/types'; import { signalsMigrationType } from '../../plugins/security_solution/server/lib/detection_engine/migrations/saved_objects'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts index b394b0a21e59c..4541a758a02f1 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_list_items.ts @@ -8,16 +8,13 @@ import expect from '@kbn/expect'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock, getCreateExceptionListItemMinimalSchemaMockWithoutId, } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; -import { - EXCEPTION_LIST_ITEM_URL, - EXCEPTION_LIST_URL, -} from '../../../../plugins/lists/common/constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts index 840a425b4bf5e..7e34c80806cc4 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_exception_lists.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts index 1b4e671d0bc49..b084e423e88ee 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_list_items.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts index 2e48437e92412..1b955f88bf929 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/create_lists.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; -import { LIST_URL } from '../../../../plugins/lists/common/constants'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; import { getCreateMinimalListSchemaMock, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts index 4cf95daa146d3..229d5737a99bb 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_list_items.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock, @@ -15,10 +16,6 @@ import { } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, -} from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts index 4b8b9b84f5dfc..d83c4bdc2f1a9 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_exception_lists.ts @@ -8,13 +8,13 @@ import expect from '@kbn/expect'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListMinimalSchemaMockWithoutId, } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts index 48abc236b6bd6..9de5ec575ef32 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_list_items.ts @@ -7,10 +7,10 @@ import expect from '@kbn/expect'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts index 4ce3c7f0e5661..5d1abf6f74f7e 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/delete_lists.ts @@ -7,13 +7,13 @@ import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; import { EXCEPTION_LIST_ITEM_URL, EXCEPTION_LIST_URL, LIST_ITEM_URL, LIST_URL, -} from '../../../../plugins/lists/common/constants'; +} from '@kbn/securitysolution-list-constants'; +import { FtrProviderContext } from '../../common/ftr_provider_context'; import { getCreateMinimalListSchemaMock, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts index 563c0c5b3c313..efcc10518c6c0 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/export_list_items.ts @@ -7,13 +7,12 @@ import expect from '@kbn/expect'; import type { CreateListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL, LIST_URL } from '@kbn/securitysolution-list-constants'; import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { LIST_ID, NAME } from '../../../../plugins/lists/common/constants.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_ITEM_URL, LIST_URL } from '../../../../plugins/lists/common/constants'; - import { createListsIndex, deleteListsIndex, binaryToString } from '../../utils'; // eslint-disable-next-line import/no-default-export diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts index 1085498d7c3a6..7b23ab7d6f866 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_list_items.ts @@ -7,14 +7,11 @@ import expect from '@kbn/expect'; +import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, -} from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts index 111300abf3a81..9972ed6a89171 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_exception_lists.ts @@ -7,10 +7,10 @@ import expect from '@kbn/expect'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts index 7e0441baec4b7..9708abba4e206 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_list_items.ts @@ -7,11 +7,11 @@ import expect from '@kbn/expect'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { LIST_ITEM_ID, LIST_ID } from '../../../../plugins/lists/common/constants.mock'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts index 3e843dbf39012..b6677ec09cfeb 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/find_lists.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts index d80b538882bb8..db8b35a805fbc 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/import_list_items.ts @@ -7,12 +7,11 @@ import expect from '@kbn/expect'; import type { ListSchema, ListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; import { getListResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; - import { createListsIndex, deleteListsIndex, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts index b3af396e27021..0a7caed8a5e14 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_list_items.ts @@ -8,6 +8,7 @@ import expect from '@kbn/expect'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock, @@ -15,10 +16,6 @@ import { } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, -} from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListItemServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts index a53f3d1d2bded..db53a0ed18a0c 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_exception_lists.ts @@ -8,13 +8,13 @@ import expect from '@kbn/expect'; import type { ExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock, getCreateExceptionListMinimalSchemaMockWithoutId, } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts index b463ea17c419a..f53e9c7434e35 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_items.ts @@ -7,10 +7,10 @@ import expect from '@kbn/expect'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts index 0ad39e177b4f3..b90a3f86a290d 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_list_privileges.ts @@ -7,9 +7,9 @@ import expect from '@kbn/expect'; +import { LIST_PRIVILEGES_URL } from '@kbn/securitysolution-list-constants'; import { getReadPrivilegeMock } from '../../../../plugins/lists/server/routes/read_privileges_route.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_PRIVILEGES_URL } from '../../../../plugins/lists/common/constants'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts index 050aeb9ffa9c6..af81801fb5e91 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/read_lists.ts @@ -7,8 +7,8 @@ import expect from '@kbn/expect'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock, diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts index d072a96772295..b611d5c31de67 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_list_items.ts @@ -11,14 +11,11 @@ import type { UpdateExceptionListItemSchema, ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL, EXCEPTION_LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_item_schema.mock'; import { getCreateExceptionListItemMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_item_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { - EXCEPTION_LIST_URL, - EXCEPTION_LIST_ITEM_URL, -} from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts index 6f5866e8968ff..75064860da1c2 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_exception_lists.ts @@ -11,10 +11,10 @@ import type { UpdateExceptionListSchema, ExceptionListSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { EXCEPTION_LIST_URL } from '@kbn/securitysolution-list-constants'; import { getExceptionResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/exception_list_schema.mock'; import { getCreateExceptionListMinimalSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_exception_list_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { EXCEPTION_LIST_URL } from '../../../../plugins/lists/common/constants'; import { deleteAllExceptions, removeExceptionListServerGeneratedProperties } from '../../utils'; diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts index fdcb7eeacdbad..38d36ba3d7eee 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_list_items.ts @@ -12,10 +12,10 @@ import type { CreateListItemSchema, ListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getListItemResponseMockWithoutAutoGeneratedValues } from '../../../../plugins/lists/common/schemas/response/list_item_schema.mock'; import { getCreateMinimalListItemSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_item_schema.mock'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL, LIST_ITEM_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts index ad42f6f9e9e6e..2e3f48354b22a 100644 --- a/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts +++ b/x-pack/test/lists_api_integration/security_and_spaces/tests/update_lists.ts @@ -8,8 +8,8 @@ import expect from '@kbn/expect'; import type { UpdateListSchema, ListSchema } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_URL } from '@kbn/securitysolution-list-constants'; import { FtrProviderContext } from '../../common/ftr_provider_context'; -import { LIST_URL } from '../../../../plugins/lists/common/constants'; import { getCreateMinimalListSchemaMock } from '../../../../plugins/lists/common/schemas/request/create_list_schema.mock'; import { diff --git a/x-pack/test/lists_api_integration/utils.ts b/x-pack/test/lists_api_integration/utils.ts index 81a4298ea1d0c..2467e613ca2f5 100644 --- a/x-pack/test/lists_api_integration/utils.ts +++ b/x-pack/test/lists_api_integration/utils.ts @@ -16,8 +16,8 @@ import type { ExceptionListSchema, ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; +import { LIST_INDEX, LIST_ITEM_URL } from '@kbn/securitysolution-list-constants'; import { getImportListItemAsBuffer } from '../../plugins/lists/common/schemas/request/import_list_item_schema.mock'; -import { LIST_INDEX, LIST_ITEM_URL } from '../../plugins/lists/common/constants'; import { countDownES, countDownTest } from '../detection_engine_api_integration/utils'; /** diff --git a/yarn.lock b/yarn.lock index f0bea3118d887..f1f421e2a766f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2702,10 +2702,6 @@ version "0.0.0" uid "" -"@kbn/securitysolution-constants@link:bazel-bin/packages/kbn-securitysolution-constants/npm_module": - version "0.0.0" - uid "" - "@kbn/securitysolution-es-utils@link:bazel-bin/packages/kbn-securitysolution-es-utils/npm_module": version "0.0.0" uid "" @@ -2730,6 +2726,10 @@ version "0.0.0" uid "" +"@kbn/securitysolution-list-constants@link:bazel-bin/packages/kbn-securitysolution-list-constants/npm_module": + version "0.0.0" + uid "" + "@kbn/securitysolution-list-hooks@link:bazel-bin/packages/kbn-securitysolution-list-hooks/npm_module": version "0.0.0" uid "" From 7bd46ec20493e68de3a6820e2dbeb4ada5c966d6 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 25 May 2021 01:01:47 -0600 Subject: [PATCH 12/22] [test/functional/context] include missing await (#100422) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- test/functional/apps/context/_discover_navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/apps/context/_discover_navigation.js b/test/functional/apps/context/_discover_navigation.js index 1c3862e07e9d7..a09be8b35ba8f 100644 --- a/test/functional/apps/context/_discover_navigation.js +++ b/test/functional/apps/context/_discover_navigation.js @@ -130,7 +130,7 @@ export default function ({ getService, getPageObjects }) { const alert = await browser.getAlert(); await alert?.accept(); expect(await browser.getCurrentUrl()).to.contain('#/doc'); - retry.waitFor('doc view being rendered', async () => { + await retry.waitFor('doc view being rendered', async () => { return await PageObjects.discover.isShowingDocViewer(); }); }); From 818fa90fbbec3f75d9603becd25098896f45b091 Mon Sep 17 00:00:00 2001 From: Yaroslav Kuznietsov Date: Tue, 25 May 2021 12:30:20 +0300 Subject: [PATCH 13/22] [TSVB] Fix more than one empty labels in markdown breaks the values for all other labels (#100432) * Fixed multiple empty labels monitoring with []. * Fixed regexp group behavior and replaced by ''.replaceAll. * Changed ''.replaceAll with ''.split(...).join(...) * Added test for (empty) label case. * Removed not necessary comment. Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/application/components/lib/replace_vars.js | 2 +- .../application/components/lib/replace_vars.test.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.js b/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.js index 6e5e423d86807..458866f2098a0 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.js +++ b/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.js @@ -14,7 +14,7 @@ import { i18n } from '@kbn/i18n'; export function replaceVars(str, args = {}, vars = {}) { try { // we need add '[]' for emptyLabel because this value contains special characters. (https://handlebarsjs.com/guide/expressions.html#literal-segments) - const template = handlebars.compile(str.replace(emptyLabel, `[${emptyLabel}]`), { + const template = handlebars.compile(str.split(emptyLabel).join(`[${emptyLabel}]`), { strict: true, knownHelpersOnly: true, }); diff --git a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.js b/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.js index 95fa0b6255d03..b1586718149e2 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.js +++ b/src/plugins/vis_type_timeseries/public/application/components/lib/replace_vars.test.js @@ -7,6 +7,7 @@ */ import { replaceVars } from './replace_vars'; +import { emptyLabel } from '../../../../common/empty_label'; describe('replaceVars(str, args, vars)', () => { test('replaces vars with values', () => { @@ -27,4 +28,11 @@ describe('replaceVars(str, args, vars)', () => { const template = '# {{args.host}} {{total'; expect(replaceVars(template, args, vars)).toEqual('# {{args.host}} {{total'); }); + + test('replaces (empty).some_path with values', () => { + const vars = { [emptyLabel]: { d: { raw: 100 } } }; + const args = {}; + const template = `# {{ ${emptyLabel}.d.raw }} {{ ${emptyLabel}.d.raw }}`; + expect(replaceVars(template, args, vars)).toEqual('# 100 100'); + }); }); From 206a64fc4cb96d66bf1a32e683817deeeea10598 Mon Sep 17 00:00:00 2001 From: Sergi Massaneda Date: Tue, 25 May 2021 14:49:51 +0200 Subject: [PATCH 14/22] [Security Solution] Application register deepLinks instead of meta.searchDeepLinks (#100129) * refactor meta.searchDeepLinks to deepLinks and remove meta * remove comments * obsolete snapshot removed * documentation updated * [deepLinks] refactor ml nav ids and translation keys * flaky test fix attempt [sync with glo] * default deepLinks navLinkStatus * api_docs restored Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- ...kibana-plugin-core-public.app.deeplinks.md | 39 ++++ .../kibana-plugin-core-public.app.keywords.md | 13 ++ .../public/kibana-plugin-core-public.app.md | 3 +- .../kibana-plugin-core-public.app.meta.md | 43 ---- .../kibana-plugin-core-public.appdeeplink.md | 26 +++ ...ana-plugin-core-public.appmeta.keywords.md | 13 -- .../kibana-plugin-core-public.appmeta.md | 23 -- ...gin-core-public.appmeta.searchdeeplinks.md | 13 -- ...na-plugin-core-public.appsearchdeeplink.md | 26 --- ...a-plugin-core-public.appupdatablefields.md | 2 +- .../core/public/kibana-plugin-core-public.md | 6 +- ...lugin-core-public.publicappdeeplinkinfo.md | 17 ++ ...kibana-plugin-core-public.publicappinfo.md | 5 +- ...na-plugin-core-public.publicappmetainfo.md | 16 -- ...core-public.publicappsearchdeeplinkinfo.md | 16 -- .../application/application_service.test.ts | 10 +- .../application/application_service.tsx | 11 + src/core/public/application/index.ts | 6 +- src/core/public/application/types.ts | 99 ++++----- .../application/utils/get_app_info.test.ts | 126 +++++------ .../public/application/utils/get_app_info.ts | 30 ++- .../chrome/nav_links/to_nav_link.test.ts | 6 +- src/core/public/index.ts | 6 +- src/core/public/public.api.md | 59 +++--- src/plugins/dev_tools/public/plugin.ts | 6 +- src/plugins/management/public/plugin.ts | 32 ++- .../management/public/utils/management_app.ts | 9 +- .../app/Main/route_config/index.tsx | 6 +- x-pack/plugins/apm/public/plugin.ts | 84 ++++---- .../public/providers/application.test.ts | 6 +- .../public/providers/get_app_results.test.ts | 200 ++++++++---------- .../public/providers/get_app_results.ts | 21 +- .../infra/public/pages/logs/page_content.tsx | 2 +- .../infra/public/pages/metrics/index.tsx | 2 +- x-pack/plugins/infra/public/plugin.ts | 114 +++++----- .../register_search_links.ts | 16 +- .../search_deep_links.ts | 78 +++---- .../detection_alerts/alerts_details.spec.ts | 2 +- .../public/app/search/index.test.ts | 9 +- .../public/app/search/index.ts | 18 +- .../security_solution/public/app/types.ts | 6 +- .../security_solution/public/plugin.tsx | 16 +- .../translations/translations/ja-JP.json | 20 +- .../translations/translations/zh-CN.json | 20 +- x-pack/plugins/uptime/public/apps/plugin.ts | 42 ++-- 45 files changed, 598 insertions(+), 725 deletions(-) create mode 100644 docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.app.keywords.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.app.meta.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.appdeeplink.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md create mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md delete mode 100644 docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md diff --git a/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md b/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md new file mode 100644 index 0000000000000..0392cb7eaefb0 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.app.deeplinks.md @@ -0,0 +1,39 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [deepLinks](./kibana-plugin-core-public.app.deeplinks.md) + +## App.deepLinks property + +Input type for registering secondary in-app locations for an application. + +Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. + +Signature: + +```typescript +deepLinks?: AppDeepLink[]; +``` + +## Example + + +```ts +core.application.register({ + id: 'my_app', + title: 'Translated title', + keywords: ['translated keyword1', 'translated keyword2'], + deepLinks: [ + { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, + { + id: 'sub2', + title: 'Sub2', + deepLinks: [ + { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } + ] + } + ], + mount: () => { ... } +}) + +``` + diff --git a/docs/development/core/public/kibana-plugin-core-public.app.keywords.md b/docs/development/core/public/kibana-plugin-core-public.app.keywords.md new file mode 100644 index 0000000000000..585df1b48c16e --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.app.keywords.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [keywords](./kibana-plugin-core-public.app.keywords.md) + +## App.keywords property + +Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. + +Signature: + +```typescript +keywords?: string[]; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.app.md b/docs/development/core/public/kibana-plugin-core-public.app.md index 9a508f293d8e8..721d9a2f121c7 100644 --- a/docs/development/core/public/kibana-plugin-core-public.app.md +++ b/docs/development/core/public/kibana-plugin-core-public.app.md @@ -19,12 +19,13 @@ export interface App | [capabilities](./kibana-plugin-core-public.app.capabilities.md) | Partial<Capabilities> | Custom capabilities defined by the app. | | [category](./kibana-plugin-core-public.app.category.md) | AppCategory | The category definition of the product See [AppCategory](./kibana-plugin-core-public.appcategory.md) See DEFAULT\_APP\_CATEGORIES for more reference | | [chromeless](./kibana-plugin-core-public.app.chromeless.md) | boolean | Hide the UI chrome when the application is mounted. Defaults to false. Takes precedence over chrome service visibility settings. | +| [deepLinks](./kibana-plugin-core-public.app.deeplinks.md) | AppDeepLink[] | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or deepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [defaultPath](./kibana-plugin-core-public.app.defaultpath.md) | string | Allow to define the default path a user should be directed to when navigating to the app. When defined, this value will be used as a default for the path option when calling [navigateToApp](./kibana-plugin-core-public.applicationstart.navigatetoapp.md)\`, and will also be appended to the [application navLink](./kibana-plugin-core-public.chromenavlink.md) in the navigation bar. | | [euiIconType](./kibana-plugin-core-public.app.euiicontype.md) | string | A EUI iconType that will be used for the app's icon. This icon takes precendence over the icon property. | | [exactRoute](./kibana-plugin-core-public.app.exactroute.md) | boolean | If set to true, the application's route will only be checked against an exact match. Defaults to false. | | [icon](./kibana-plugin-core-public.app.icon.md) | string | A URL to an image file used as an icon. Used as a fallback if euiIconType is not provided. | | [id](./kibana-plugin-core-public.app.id.md) | string | The unique identifier of the application | -| [meta](./kibana-plugin-core-public.app.meta.md) | AppMeta | Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) | +| [keywords](./kibana-plugin-core-public.app.keywords.md) | string[] | Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. | | [mount](./kibana-plugin-core-public.app.mount.md) | AppMount<HistoryLocationState> | A mount function called when the user navigates to this app's route. | | [navLinkStatus](./kibana-plugin-core-public.app.navlinkstatus.md) | AppNavLinkStatus | The initial status of the application's navLink. Defaulting to visible if status is accessible and hidden if status is inaccessible See [AppNavLinkStatus](./kibana-plugin-core-public.appnavlinkstatus.md) | | [order](./kibana-plugin-core-public.app.order.md) | number | An ordinal used to sort nav links relative to one another for display. | diff --git a/docs/development/core/public/kibana-plugin-core-public.app.meta.md b/docs/development/core/public/kibana-plugin-core-public.app.meta.md deleted file mode 100644 index 574fa11605aec..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.app.meta.md +++ /dev/null @@ -1,43 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [App](./kibana-plugin-core-public.app.md) > [meta](./kibana-plugin-core-public.app.meta.md) - -## App.meta property - -Meta data for an application that represent additional information for the app. See [AppMeta](./kibana-plugin-core-public.appmeta.md) - -Signature: - -```typescript -meta?: AppMeta; -``` - -## Remarks - -Used to populate navigational search results (where available). Can be updated using the [App.updater$](./kibana-plugin-core-public.app.updater_.md) observable. See [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) for more details. - -## Example - - -```ts -core.application.register({ - id: 'my_app', - title: 'Translated title', - meta: { - keywords: ['translated keyword1', 'translated keyword2'], - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, - { - id: 'sub2', - title: 'Sub2', - searchDeepLinks: [ - { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } - ] - } - ], - }, - mount: () => { ... } -}) - -``` - diff --git a/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md b/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md new file mode 100644 index 0000000000000..5aa951cffdcb5 --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.appdeeplink.md @@ -0,0 +1,26 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppDeepLink](./kibana-plugin-core-public.appdeeplink.md) + +## AppDeepLink type + +Input type for registering secondary in-app locations for an application. + +Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. + +Signature: + +```typescript +export declare type AppDeepLink = { + id: string; + title: string; + keywords?: string[]; + navLinkStatus?: AppNavLinkStatus; +} & ({ + path: string; + deepLinks?: AppDeepLink[]; +} | { + path?: string; + deepLinks: AppDeepLink[]; +}); +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md deleted file mode 100644 index 13709df68e76a..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.keywords.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [keywords](./kibana-plugin-core-public.appmeta.keywords.md) - -## AppMeta.keywords property - -Keywords to represent this application - -Signature: - -```typescript -keywords?: string[]; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.md deleted file mode 100644 index a2b72f7ec799d..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.md +++ /dev/null @@ -1,23 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) - -## AppMeta interface - -Input type for meta data for an application. - -Meta fields include `keywords` and `searchDeepLinks` Keywords is an array of string with which to associate the app, must include at least one unique string as an array. `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. - -Signature: - -```typescript -export interface AppMeta -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [keywords](./kibana-plugin-core-public.appmeta.keywords.md) | string[] | Keywords to represent this application | -| [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) | AppSearchDeepLink[] | Array of links that represent secondary in-app locations for the app. | - diff --git a/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md b/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md deleted file mode 100644 index 7ec0bbaa4b418..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appmeta.searchdeeplinks.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppMeta](./kibana-plugin-core-public.appmeta.md) > [searchDeepLinks](./kibana-plugin-core-public.appmeta.searchdeeplinks.md) - -## AppMeta.searchDeepLinks property - -Array of links that represent secondary in-app locations for the app. - -Signature: - -```typescript -searchDeepLinks?: AppSearchDeepLink[]; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md b/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md deleted file mode 100644 index 29aad675fb105..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.appsearchdeeplink.md +++ /dev/null @@ -1,26 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [AppSearchDeepLink](./kibana-plugin-core-public.appsearchdeeplink.md) - -## AppSearchDeepLink type - -Input type for registering secondary in-app locations for an application. - -Deep links must include at least one of `path` or `searchDeepLinks`. A deep link that does not have a `path` represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. - -Signature: - -```typescript -export declare type AppSearchDeepLink = { - id: string; - title: string; -} & ({ - path: string; - searchDeepLinks?: AppSearchDeepLink[]; - keywords?: string[]; -} | { - path?: string; - searchDeepLinks: AppSearchDeepLink[]; - keywords?: string[]; -}); -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md index 55672d9339f61..d7b12d4b70701 100644 --- a/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md +++ b/docs/development/core/public/kibana-plugin-core-public.appupdatablefields.md @@ -9,5 +9,5 @@ Defines the list of fields that can be updated via an [AppUpdater](./kibana-plug Signature: ```typescript -export declare type AppUpdatableFields = Pick; +export declare type AppUpdatableFields = Pick; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.md b/docs/development/core/public/kibana-plugin-core-public.md index 3972f737f6618..6239279f275d1 100644 --- a/docs/development/core/public/kibana-plugin-core-public.md +++ b/docs/development/core/public/kibana-plugin-core-public.md @@ -37,7 +37,6 @@ The plugin integrates with the core system via lifecycle events: `setup` | [AppLeaveDefaultAction](./kibana-plugin-core-public.appleavedefaultaction.md) | Action to return from a [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md) to execute the default behaviour when leaving the application.See | | [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) | | | [ApplicationStart](./kibana-plugin-core-public.applicationstart.md) | | -| [AppMeta](./kibana-plugin-core-public.appmeta.md) | Input type for meta data for an application.Meta fields include keywords and searchDeepLinks Keywords is an array of string with which to associate the app, must include at least one unique string as an array. searchDeepLinks is an array of links that represent secondary in-app locations for the app. | | [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) | | | [AsyncPlugin](./kibana-plugin-core-public.asyncplugin.md) | A plugin with asynchronous lifecycle methods. | | [Capabilities](./kibana-plugin-core-public.capabilities.md) | The read-only set of capabilities available for the current UI session. Capabilities are simple key-value pairs of (string, boolean), where the string denotes the capability ID, and the boolean is a flag indicating if the capability is enabled or disabled. | @@ -144,10 +143,10 @@ The plugin integrates with the core system via lifecycle events: `setup` | Type Alias | Description | | --- | --- | +| [AppDeepLink](./kibana-plugin-core-public.appdeeplink.md) | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or deepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [AppLeaveAction](./kibana-plugin-core-public.appleaveaction.md) | Possible actions to return from a [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md)See [AppLeaveConfirmAction](./kibana-plugin-core-public.appleaveconfirmaction.md) and [AppLeaveDefaultAction](./kibana-plugin-core-public.appleavedefaultaction.md) | | [AppLeaveHandler](./kibana-plugin-core-public.appleavehandler.md) | A handler that will be executed before leaving the application, either when going to another application or when closing the browser tab or manually changing the url. Should return confirm to prompt a message to the user before leaving the page, or default to keep the default behavior (doing nothing).See [AppMountParameters](./kibana-plugin-core-public.appmountparameters.md) for detailed usage examples. | | [AppMount](./kibana-plugin-core-public.appmount.md) | A mount function called when the user navigates to this app's route. | -| [AppSearchDeepLink](./kibana-plugin-core-public.appsearchdeeplink.md) | Input type for registering secondary in-app locations for an application.Deep links must include at least one of path or searchDeepLinks. A deep link that does not have a path represents a topological level in the application's hierarchy, but does not have a destination URL that is user-accessible. | | [AppUnmount](./kibana-plugin-core-public.appunmount.md) | A function called when an application should be unmounted from the page. This function should be synchronous. | | [AppUpdatableFields](./kibana-plugin-core-public.appupdatablefields.md) | Defines the list of fields that can be updated via an [AppUpdater](./kibana-plugin-core-public.appupdater.md). | | [AppUpdater](./kibana-plugin-core-public.appupdater.md) | Updater for applications. see [ApplicationSetup](./kibana-plugin-core-public.applicationsetup.md) | @@ -161,9 +160,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [NavType](./kibana-plugin-core-public.navtype.md) | | | [PluginInitializer](./kibana-plugin-core-public.plugininitializer.md) | The plugin export at the root of a plugin's public directory should conform to this interface. | | [PluginOpaqueId](./kibana-plugin-core-public.pluginopaqueid.md) | | +| [PublicAppDeepLinkInfo](./kibana-plugin-core-public.publicappdeeplinkinfo.md) | Public information about a registered app's [deepLinks](./kibana-plugin-core-public.appdeeplink.md) | | [PublicAppInfo](./kibana-plugin-core-public.publicappinfo.md) | Public information about a registered [application](./kibana-plugin-core-public.app.md) | -| [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) | Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) | -| [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) | Public information about a registered app's [searchDeepLinks](./kibana-plugin-core-public.appsearchdeeplink.md) | | [PublicUiSettingsParams](./kibana-plugin-core-public.publicuisettingsparams.md) | A sub-set of [UiSettingsParams](./kibana-plugin-core-public.uisettingsparams.md) exposed to the client-side. | | [ResolveDeprecationResponse](./kibana-plugin-core-public.resolvedeprecationresponse.md) | | | [SavedObjectAttribute](./kibana-plugin-core-public.savedobjectattribute.md) | Type definition for a Saved Object attribute value | diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md new file mode 100644 index 0000000000000..d3a6a4de905fd --- /dev/null +++ b/docs/development/core/public/kibana-plugin-core-public.publicappdeeplinkinfo.md @@ -0,0 +1,17 @@ + + +[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppDeepLinkInfo](./kibana-plugin-core-public.publicappdeeplinkinfo.md) + +## PublicAppDeepLinkInfo type + +Public information about a registered app's [deepLinks](./kibana-plugin-core-public.appdeeplink.md) + +Signature: + +```typescript +export declare type PublicAppDeepLinkInfo = Omit & { + deepLinks: PublicAppDeepLinkInfo[]; + keywords: string[]; + navLinkStatus: AppNavLinkStatus; +}; +``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md index 9f45a06935fe4..a5563eae83563 100644 --- a/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md +++ b/docs/development/core/public/kibana-plugin-core-public.publicappinfo.md @@ -9,10 +9,11 @@ Public information about a registered [application](./kibana-plugin-core-public. Signature: ```typescript -export declare type PublicAppInfo = Omit & { +export declare type PublicAppInfo = Omit & { status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - meta: PublicAppMetaInfo; + keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; ``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md deleted file mode 100644 index 3ef0460aec467..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.publicappmetainfo.md +++ /dev/null @@ -1,16 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppMetaInfo](./kibana-plugin-core-public.publicappmetainfo.md) - -## PublicAppMetaInfo type - -Public information about a registered app's [keywords](./kibana-plugin-core-public.appmeta.md) - -Signature: - -```typescript -export declare type PublicAppMetaInfo = Omit & { - keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; -}; -``` diff --git a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md b/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md deleted file mode 100644 index e88cdb7d55edd..0000000000000 --- a/docs/development/core/public/kibana-plugin-core-public.publicappsearchdeeplinkinfo.md +++ /dev/null @@ -1,16 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-public](./kibana-plugin-core-public.md) > [PublicAppSearchDeepLinkInfo](./kibana-plugin-core-public.publicappsearchdeeplinkinfo.md) - -## PublicAppSearchDeepLinkInfo type - -Public information about a registered app's [searchDeepLinks](./kibana-plugin-core-public.appsearchdeeplink.md) - -Signature: - -```typescript -export declare type PublicAppSearchDeepLinkInfo = Omit & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; - keywords: string[]; -}; -``` diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts index 76b9c7a73d3bd..2e2f1cad49f19 100644 --- a/src/core/public/application/application_service.test.ts +++ b/src/core/public/application/application_service.test.ts @@ -75,7 +75,10 @@ describe('#setup()', () => { const pluginId = Symbol('plugin'); const updater$ = new BehaviorSubject((app) => ({})); setup.register(pluginId, createApp({ id: 'app1', updater$ })); - setup.register(pluginId, createApp({ id: 'app2' })); + setup.register( + pluginId, + createApp({ id: 'app2', deepLinks: [{ id: 'subapp1', title: 'Subapp', path: '/subapp' }] }) + ); const { applications$ } = await service.start(startDeps); let applications = await applications$.pipe(take(1)).toPromise(); @@ -92,6 +95,11 @@ describe('#setup()', () => { id: 'app2', navLinkStatus: AppNavLinkStatus.visible, status: AppStatus.accessible, + deepLinks: [ + expect.objectContaining({ + navLinkStatus: AppNavLinkStatus.hidden, + }), + ], }) ); diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx index 4a93c98205b84..bbfea61220b51 100644 --- a/src/core/public/application/application_service.tsx +++ b/src/core/public/application/application_service.tsx @@ -19,6 +19,7 @@ import { AppRouter } from './ui'; import { Capabilities, CapabilitiesService } from './capabilities'; import { App, + AppDeepLink, AppLeaveHandler, AppMount, AppNavLinkStatus, @@ -166,6 +167,7 @@ export class ApplicationService { ...appProps, status: app.status ?? AppStatus.accessible, navLinkStatus: app.navLinkStatus ?? AppNavLinkStatus.default, + deepLinks: populateDeepLinkDefaults(appProps.deepLinks), }); if (updater$) { registerStatusUpdater(app.id, updater$); @@ -392,3 +394,12 @@ const updateStatus = (app: App, statusUpdaters: AppUpdaterWrapper[]): App => { ...changes, }; }; + +const populateDeepLinkDefaults = (deepLinks?: AppDeepLink[]): AppDeepLink[] => { + if (!deepLinks) return []; + return deepLinks.map((deepLink) => ({ + ...deepLink, + navLinkStatus: deepLink.navLinkStatus ?? AppNavLinkStatus.default, + deepLinks: populateDeepLinkDefaults(deepLink.deepLinks), + })); +}; diff --git a/src/core/public/application/index.ts b/src/core/public/application/index.ts index 1e9a91717e81a..68e1991646afb 100644 --- a/src/core/public/application/index.ts +++ b/src/core/public/application/index.ts @@ -18,8 +18,7 @@ export type { AppMountParameters, AppUpdatableFields, AppUpdater, - AppMeta, - AppSearchDeepLink, + AppDeepLink, ApplicationSetup, ApplicationStart, AppLeaveHandler, @@ -29,8 +28,7 @@ export type { AppLeaveConfirmAction, NavigateToAppOptions, PublicAppInfo, - PublicAppMetaInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, // Internal types InternalApplicationSetup, InternalApplicationStart, diff --git a/src/core/public/application/types.ts b/src/core/public/application/types.ts index 24f46752f28e5..ffc41955360bd 100644 --- a/src/core/public/application/types.ts +++ b/src/core/public/application/types.ts @@ -63,7 +63,7 @@ export enum AppNavLinkStatus { */ export type AppUpdatableFields = Pick< App, - 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'meta' + 'status' | 'navLinkStatus' | 'tooltip' | 'defaultPath' | 'deepLinks' >; /** @@ -211,106 +211,92 @@ export interface App { */ exactRoute?: boolean; + /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ + keywords?: string[]; + /** - * Meta data for an application that represent additional information for the app. - * See {@link AppMeta} + * Input type for registering secondary in-app locations for an application. * - * @remarks - * Used to populate navigational search results (where available). - * Can be updated using the {@link App.updater$} observable. See {@link PublicAppSearchDeepLinkInfo} for more details. + * Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` + * represents a topological level in the application's hierarchy, but does not have a destination URL that is + * user-accessible. * * @example * ```ts * core.application.register({ * id: 'my_app', * title: 'Translated title', - * meta: { - * keywords: ['translated keyword1', 'translated keyword2'], - * searchDeepLinks: [ - * { id: 'sub1', title: 'Sub1', path: '/sub1', keywords: ['subpath1'] }, + * keywords: ['translated keyword1', 'translated keyword2'], + * deepLinks: [ + * { + * id: 'sub1', + * title: 'Sub1', + * path: '/sub1', + * keywords: ['subpath1'], + * }, * { * id: 'sub2', * title: 'Sub2', - * searchDeepLinks: [ - * { id: 'subsub', title: 'SubSub', path: '/sub2/sub', keywords: ['subpath2'] } - * ] - * } + * deepLinks: [ + * { + * id: 'subsub', + * title: 'SubSub', + * path: '/sub2/sub', + * keywords: ['subpath2'], + * }, + * ], + * }, * ], - * }, * mount: () => { ... } * }) * ``` */ - meta?: AppMeta; -} - -/** - * Input type for meta data for an application. - * - * Meta fields include `keywords` and `searchDeepLinks` - * Keywords is an array of string with which to associate the app, must include at least one unique string as an array. - * `searchDeepLinks` is an array of links that represent secondary in-app locations for the app. - * @public - */ -export interface AppMeta { - /** Keywords to represent this application */ - keywords?: string[]; - /** Array of links that represent secondary in-app locations for the app. */ - searchDeepLinks?: AppSearchDeepLink[]; + deepLinks?: AppDeepLink[]; } /** - * Public information about a registered app's {@link AppMeta | keywords } + * Public information about a registered app's {@link AppDeepLink | deepLinks} * * @public */ -export type PublicAppMetaInfo = Omit & { - keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; -}; - -/** - * Public information about a registered app's {@link AppSearchDeepLink | searchDeepLinks} - * - * @public - */ -export type PublicAppSearchDeepLinkInfo = Omit< - AppSearchDeepLink, - 'searchDeepLinks' | 'keywords' +export type PublicAppDeepLinkInfo = Omit< + AppDeepLink, + 'deepLinks' | 'keywords' | 'navLinkStatus' > & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + deepLinks: PublicAppDeepLinkInfo[]; keywords: string[]; + navLinkStatus: AppNavLinkStatus; }; /** * Input type for registering secondary in-app locations for an application. * - * Deep links must include at least one of `path` or `searchDeepLinks`. A deep link that does not have a `path` + * Deep links must include at least one of `path` or `deepLinks`. A deep link that does not have a `path` * represents a topological level in the application's hierarchy, but does not have a destination URL that is * user-accessible. * @public */ -export type AppSearchDeepLink = { +export type AppDeepLink = { /** Identifier to represent this sublink, should be unique for this application */ id: string; /** Title to label represent this deep link */ title: string; + /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ + keywords?: string[]; + /** Optional status of the chrome navigation, defaults to `hidden` */ + navLinkStatus?: AppNavLinkStatus; } & ( | { /** URL path to access this link, relative to the application's appRoute. */ path: string; /** Optional array of links that are 'underneath' this section in the hierarchy */ - searchDeepLinks?: AppSearchDeepLink[]; - /** Optional keywords to match with in deep links search for the page at the path */ - keywords?: string[]; + deepLinks?: AppDeepLink[]; } | { /** Optional path to access this section. Omit if this part of the hierarchy does not have a page URL. */ path?: string; /** Array links that are 'underneath' this section in this hierarchy. */ - searchDeepLinks: AppSearchDeepLink[]; - /** Optional keywords to match with in deep links search. Omit if this part of the hierarchy does not have a page URL. */ - keywords?: string[]; + deepLinks: AppDeepLink[]; } ); @@ -319,12 +305,13 @@ export type AppSearchDeepLink = { * * @public */ -export type PublicAppInfo = Omit & { +export type PublicAppInfo = Omit & { // remove optional on fields populated with default values status: AppStatus; navLinkStatus: AppNavLinkStatus; appRoute: string; - meta: PublicAppMetaInfo; + keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; /** diff --git a/src/core/public/application/utils/get_app_info.test.ts b/src/core/public/application/utils/get_app_info.test.ts index 28824867234ff..ef4a06707d666 100644 --- a/src/core/public/application/utils/get_app_info.test.ts +++ b/src/core/public/application/utils/get_app_info.test.ts @@ -32,24 +32,20 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [], - }, + keywords: [], + deepLinks: [], }); }); - it('populates default values for nested searchDeepLinks', () => { + it('populates default values for nested deepLinks', () => { const app = createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], - }, - ], - }, + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + deepLinks: [{ id: 'sub-sub-id', title: 'sub-sub-title', path: '/sub-sub' }], + }, + ], }); const info = getAppInfo(app); @@ -59,25 +55,23 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - keywords: [], - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: [], - searchDeepLinks: [], // default empty array added - }, - ], - }, - ], - }, + keywords: [], + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: [], + deepLinks: [], // default empty array added + }, + ], + }, + ], }); }); @@ -110,22 +104,20 @@ describe('getAppInfo', () => { it('adds default meta fields to sublinks when needed', () => { const app = createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: ['sub sub'], - }, - ], - }, - ], - }, + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + }, + ], + }, + ], }); const info = getAppInfo(app); @@ -135,25 +127,23 @@ describe('getAppInfo', () => { status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [ - { - id: 'sub-id', - title: 'sub-title', - keywords: [], // default empty array - searchDeepLinks: [ - { - id: 'sub-sub-id', - title: 'sub-sub-title', - path: '/sub-sub', - keywords: ['sub sub'], - searchDeepLinks: [], - }, - ], - }, - ], - }, + keywords: [], + deepLinks: [ + { + id: 'sub-id', + title: 'sub-title', + keywords: [], // default empty array + deepLinks: [ + { + id: 'sub-sub-id', + title: 'sub-sub-title', + path: '/sub-sub', + keywords: ['sub sub'], + deepLinks: [], + }, + ], + }, + ], }); }); }); diff --git a/src/core/public/application/utils/get_app_info.ts b/src/core/public/application/utils/get_app_info.ts index ca1e8ac807646..4c94e24f501bc 100644 --- a/src/core/public/application/utils/get_app_info.ts +++ b/src/core/public/application/utils/get_app_info.ts @@ -10,9 +10,9 @@ import { App, AppNavLinkStatus, AppStatus, - AppSearchDeepLink, + AppDeepLink, PublicAppInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, } from '../types'; export function getAppInfo(app: App): PublicAppInfo { @@ -28,29 +28,27 @@ export function getAppInfo(app: App): PublicAppInfo { status: app.status!, navLinkStatus, appRoute: app.appRoute!, - meta: { - keywords: app.meta?.keywords ?? [], - searchDeepLinks: getSearchDeepLinkInfos(app, app.meta?.searchDeepLinks), - }, + keywords: app.keywords ?? [], + deepLinks: getDeepLinkInfos(app.deepLinks), }; } -function getSearchDeepLinkInfos( - app: App, - searchDeepLinks?: AppSearchDeepLink[] -): PublicAppSearchDeepLinkInfo[] { - if (!searchDeepLinks) { - return []; - } +function getDeepLinkInfos(deepLinks?: AppDeepLink[]): PublicAppDeepLinkInfo[] { + if (!deepLinks) return []; - return searchDeepLinks.map( - (rawDeepLink): PublicAppSearchDeepLinkInfo => { + return deepLinks.map( + (rawDeepLink): PublicAppDeepLinkInfo => { + const navLinkStatus = + rawDeepLink.navLinkStatus === AppNavLinkStatus.default + ? AppNavLinkStatus.hidden + : rawDeepLink.navLinkStatus!; return { id: rawDeepLink.id, title: rawDeepLink.title, path: rawDeepLink.path, keywords: rawDeepLink.keywords ?? [], - searchDeepLinks: getSearchDeepLinkInfos(app, rawDeepLink.searchDeepLinks), + navLinkStatus, + deepLinks: getDeepLinkInfos(rawDeepLink.deepLinks), }; } ); diff --git a/src/core/public/chrome/nav_links/to_nav_link.test.ts b/src/core/public/chrome/nav_links/to_nav_link.test.ts index 41c4ff178d737..db783d0028f07 100644 --- a/src/core/public/chrome/nav_links/to_nav_link.test.ts +++ b/src/core/public/chrome/nav_links/to_nav_link.test.ts @@ -17,10 +17,8 @@ const app = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.default, appRoute: `/app/some-id`, - meta: { - keywords: [], - searchDeepLinks: [], - }, + keywords: [], + deepLinks: [], ...props, }); diff --git a/src/core/public/index.ts b/src/core/public/index.ts index 129ae1c16f99b..24b48683cdd93 100644 --- a/src/core/public/index.ts +++ b/src/core/public/index.ts @@ -89,13 +89,11 @@ export type { AppLeaveAction, AppLeaveDefaultAction, AppLeaveConfirmAction, - AppMeta, AppUpdatableFields, AppUpdater, - AppSearchDeepLink, + AppDeepLink, PublicAppInfo, - PublicAppMetaInfo, - PublicAppSearchDeepLinkInfo, + PublicAppDeepLinkInfo, NavigateToAppOptions, } from './application'; diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 31e7a1e2321df..9f0c5135e702f 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -58,12 +58,13 @@ export interface App { capabilities?: Partial; category?: AppCategory; chromeless?: boolean; + deepLinks?: AppDeepLink[]; defaultPath?: string; euiIconType?: string; exactRoute?: boolean; icon?: string; id: string; - meta?: AppMeta; + keywords?: string[]; mount: AppMount; navLinkStatus?: AppNavLinkStatus; order?: number; @@ -85,6 +86,20 @@ export interface AppCategory { order?: number; } +// @public +export type AppDeepLink = { + id: string; + title: string; + keywords?: string[]; + navLinkStatus?: AppNavLinkStatus; +} & ({ + path: string; + deepLinks?: AppDeepLink[]; +} | { + path?: string; + deepLinks: AppDeepLink[]; +}); + // @public export type AppLeaveAction = AppLeaveDefaultAction | AppLeaveConfirmAction; @@ -142,12 +157,6 @@ export interface ApplicationStart { navigateToUrl(url: string): Promise; } -// @public -export interface AppMeta { - keywords?: string[]; - searchDeepLinks?: AppSearchDeepLink[]; -} - // @public export type AppMount = (params: AppMountParameters) => AppUnmount | Promise; @@ -170,20 +179,6 @@ export enum AppNavLinkStatus { visible = 1 } -// @public -export type AppSearchDeepLink = { - id: string; - title: string; -} & ({ - path: string; - searchDeepLinks?: AppSearchDeepLink[]; - keywords?: string[]; -} | { - path?: string; - searchDeepLinks: AppSearchDeepLink[]; - keywords?: string[]; -}); - // @public export enum AppStatus { accessible = 0, @@ -194,7 +189,7 @@ export enum AppStatus { export type AppUnmount = () => void; // @public -export type AppUpdatableFields = Pick; +export type AppUpdatableFields = Pick; // @public export type AppUpdater = (app: App) => Partial | undefined; @@ -1071,23 +1066,19 @@ export interface PluginInitializerContext export type PluginOpaqueId = symbol; // @public -export type PublicAppInfo = Omit & { - status: AppStatus; - navLinkStatus: AppNavLinkStatus; - appRoute: string; - meta: PublicAppMetaInfo; -}; - -// @public -export type PublicAppMetaInfo = Omit & { +export type PublicAppDeepLinkInfo = Omit & { + deepLinks: PublicAppDeepLinkInfo[]; keywords: string[]; - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; + navLinkStatus: AppNavLinkStatus; }; // @public -export type PublicAppSearchDeepLinkInfo = Omit & { - searchDeepLinks: PublicAppSearchDeepLinkInfo[]; +export type PublicAppInfo = Omit & { + status: AppStatus; + navLinkStatus: AppNavLinkStatus; + appRoute: string; keywords: string[]; + deepLinks: PublicAppDeepLinkInfo[]; }; // @public diff --git a/src/plugins/dev_tools/public/plugin.ts b/src/plugins/dev_tools/public/plugin.ts index e9f5d206de918..5ccf614533164 100644 --- a/src/plugins/dev_tools/public/plugin.ts +++ b/src/plugins/dev_tools/public/plugin.ts @@ -7,7 +7,7 @@ */ import { BehaviorSubject } from 'rxjs'; -import { Plugin, CoreSetup, AppMountParameters, AppSearchDeepLink } from 'src/core/public'; +import { Plugin, CoreSetup, AppMountParameters, AppDeepLink } from 'src/core/public'; import { AppUpdater } from 'kibana/public'; import { i18n } from '@kbn/i18n'; import { sortBy } from 'lodash'; @@ -86,7 +86,7 @@ export class DevToolsPlugin implements Plugin { this.appStateUpdater.next(() => ({ navLinkStatus: AppNavLinkStatus.hidden })); } else { this.appStateUpdater.next(() => { - const deepLinks: AppSearchDeepLink[] = [...this.devTools.values()] + const deepLinks: AppDeepLink[] = [...this.devTools.values()] .filter( // Some tools do not use a string title, so we filter those out (tool) => !tool.enableRouting && !tool.isDisabled() && typeof tool.title === 'string' @@ -96,7 +96,7 @@ export class DevToolsPlugin implements Plugin { title: tool.title as string, path: `#/${tool.id}`, })); - return { meta: { searchDeepLinks: deepLinks } }; + return { deepLinks }; }); } } diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts index 0429ea8c9bd7b..1f96ec87171c5 100644 --- a/src/plugins/management/public/plugin.ts +++ b/src/plugins/management/public/plugin.ts @@ -20,7 +20,7 @@ import { AppUpdater, AppStatus, AppNavLinkStatus, - AppSearchDeepLink, + AppDeepLink, } from '../../../core/public'; import { MANAGEMENT_APP_ID } from '../common/contants'; @@ -38,22 +38,20 @@ export class ManagementPlugin implements Plugin(() => { - const deepLinks: AppSearchDeepLink[] = Object.values( - this.managementSections.definedSections - ).map((section: ManagementSection) => ({ - id: section.id, - title: section.title, - searchDeepLinks: section.getAppsEnabled().map((mgmtApp) => ({ - id: mgmtApp.id, - title: mgmtApp.title, - path: mgmtApp.basePath, - meta: { ...mgmtApp.meta }, - })), - })); - - return { - meta: { searchDeepLinks: deepLinks }, - }; + const deepLinks: AppDeepLink[] = Object.values(this.managementSections.definedSections).map( + (section: ManagementSection) => ({ + id: section.id, + title: section.title, + deepLinks: section.getAppsEnabled().map((mgmtApp) => ({ + id: mgmtApp.id, + title: mgmtApp.title, + path: mgmtApp.basePath, + keywords: mgmtApp.keywords, + })), + }) + ); + + return { deepLinks }; }); private hasAnyEnabledApps = true; diff --git a/src/plugins/management/public/utils/management_app.ts b/src/plugins/management/public/utils/management_app.ts index c9385463def5b..3578b2ab0b7f2 100644 --- a/src/plugins/management/public/utils/management_app.ts +++ b/src/plugins/management/public/utils/management_app.ts @@ -6,28 +6,25 @@ * Side Public License, v 1. */ -import { AppMeta } from 'kibana/public'; import { CreateManagementItemArgs, Mount } from '../types'; import { ManagementItem } from './management_item'; export interface RegisterManagementAppArgs extends CreateManagementItemArgs { mount: Mount; basePath: string; - meta?: AppMeta; + keywords?: string[]; } export class ManagementApp extends ManagementItem { public readonly mount: Mount; public readonly basePath: string; - public readonly meta: AppMeta; + public readonly keywords: string[]; constructor(args: RegisterManagementAppArgs) { super(args); this.mount = args.mount; this.basePath = args.basePath; - this.meta = { - keywords: args.meta?.keywords || [], - }; + this.keywords = args.keywords || []; } } diff --git a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx index 9410fd00411e3..89b8db5f386dc 100644 --- a/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -173,7 +173,7 @@ export const routes: APMRouteDefinition[] = [ render: renderAsRedirectTo('/services'), breadcrumb: 'APM', }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/services', @@ -182,7 +182,7 @@ export const routes: APMRouteDefinition[] = [ defaultMessage: 'Services', }), }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/traces', @@ -328,7 +328,7 @@ export const routes: APMRouteDefinition[] = [ component: TraceLink, breadcrumb: null, }, - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/apm/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/apm/public/plugin.ts { exact: true, path: '/service-map', diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts index b76849ccf3011..10af1837dab42 100644 --- a/x-pack/plugins/apm/public/plugin.ts +++ b/x-pack/plugins/apm/public/plugin.ts @@ -140,32 +140,30 @@ export class ApmPlugin implements Plugin { appRoute: '/app/apm', icon: 'plugins/apm/public/icon.svg', category: DEFAULT_APP_CATEGORIES.observability, - meta: { - // !! Need to be kept in sync with the routes in x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx - searchDeepLinks: [ - { - id: 'services', - title: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { - defaultMessage: 'Services', - }), - path: '/services', - }, - { - id: 'traces', - title: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { - defaultMessage: 'Traces', - }), - path: '/traces', - }, - { - id: 'service-map', - title: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { - defaultMessage: 'Service Map', - }), - path: '/service-map', - }, - ], - }, + // !! Need to be kept in sync with the routes in x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx + deepLinks: [ + { + id: 'services', + title: i18n.translate('xpack.apm.breadcrumb.servicesTitle', { + defaultMessage: 'Services', + }), + path: '/services', + }, + { + id: 'traces', + title: i18n.translate('xpack.apm.breadcrumb.tracesTitle', { + defaultMessage: 'Traces', + }), + path: '/traces', + }, + { + id: 'service-map', + title: i18n.translate('xpack.apm.breadcrumb.serviceMapTitle', { + defaultMessage: 'Service Map', + }), + path: '/service-map', + }, + ], async mount(appMountParameters: AppMountParameters) { // Load application bundle and Get start services @@ -196,24 +194,22 @@ export class ApmPlugin implements Plugin { navLinkStatus: config.ui.enabled ? AppNavLinkStatus.default : AppNavLinkStatus.hidden, - meta: { - keywords: [ - 'RUM', - 'Real User Monitoring', - 'DEM', - 'Digital Experience Monitoring', - 'EUM', - 'End User Monitoring', - 'UX', - 'Javascript', - 'APM', - 'Mobile', - 'digital', - 'performance', - 'web performance', - 'web perf', - ], - }, + keywords: [ + 'RUM', + 'Real User Monitoring', + 'DEM', + 'Digital Experience Monitoring', + 'EUM', + 'End User Monitoring', + 'UX', + 'Javascript', + 'APM', + 'Mobile', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], async mount(appMountParameters: AppMountParameters) { // Load application bundle and Get start service const [{ renderApp }, [coreStart, corePlugins]] = await Promise.all([ diff --git a/x-pack/plugins/global_search_providers/public/providers/application.test.ts b/x-pack/plugins/global_search_providers/public/providers/application.test.ts index 9b084d7bb9a6a..2d555f38d16d1 100644 --- a/x-pack/plugins/global_search_providers/public/providers/application.test.ts +++ b/x-pack/plugins/global_search_providers/public/providers/application.test.ts @@ -29,10 +29,8 @@ const createApp = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, chromeless: false, - meta: { - keywords: props.meta?.keywords || [], - searchDeepLinks: [], - }, + keywords: props.keywords || [], + deepLinks: [], ...props, }); diff --git a/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts b/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts index 8b875dbb7ed9b..251dd84395aa0 100644 --- a/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts +++ b/x-pack/plugins/global_search_providers/public/providers/get_app_results.test.ts @@ -26,7 +26,8 @@ const createApp = (props: Partial = {}): PublicAppInfo => ({ status: AppStatus.accessible, navLinkStatus: AppNavLinkStatus.visible, chromeless: false, - meta: { keywords: [], searchDeepLinks: [] }, + keywords: [], + deepLinks: [], ...props, }); @@ -34,7 +35,7 @@ const createAppLink = (props: Partial = {}): AppLink => ({ id: props.id ?? 'app1', path: props.appRoute ?? '/app/app1', subLinkTitles: [], - keywords: props.meta?.keywords ?? [], // start off with the top level app keywords + keywords: props.keywords ?? [], // start off with the top level app keywords app: createApp(props), }); @@ -51,30 +52,37 @@ describe('getAppResults', () => { expect(results[0]).toEqual(expect.objectContaining({ id: 'dashboard', score: 100 })); }); - it('creates multiple links for apps with searchDeepLinks', () => { + it('creates multiple links for apps with deepLinks', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', searchDeepLinks: [], keywords: [] }, - { - id: 'sub2', - title: 'Sub2', - path: '/sub2', - searchDeepLinks: [ - { - id: 'sub2sub1', - title: 'Sub2Sub1', - path: '/sub2/sub1', - searchDeepLinks: [], - keywords: [], - }, - ], - keywords: [], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + { + id: 'sub2', + title: 'Sub2', + path: '/sub2', + deepLinks: [ + { + id: 'sub2sub1', + title: 'Sub2Sub1', + path: '/sub2/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -89,21 +97,20 @@ describe('getAppResults', () => { ]); }); - it('only includes searchDeepLinks when search term is non-empty', () => { + it('only includes deepLinks when search term is non-empty', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { - id: 'sub1', - title: 'Sub1', - path: '/sub1', - searchDeepLinks: [], - keywords: [], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -112,11 +119,7 @@ describe('getAppResults', () => { }); it('retrieves the matching results from keywords', () => { - const apps = [ - createApp({ - meta: { searchDeepLinks: [], keywords: ['One'] }, - }), - ]; + const apps = [createApp({ deepLinks: [], keywords: ['One'] })]; const results = getAppResults('One', apps); expect(results.map(({ title }) => title)).toEqual(['App 1']); }); @@ -124,27 +127,34 @@ describe('getAppResults', () => { it('retrieves the matching results from deeplink keywords', () => { const apps = [ createApp({ - meta: { - searchDeepLinks: [ - { id: 'sub1', title: 'Sub1', path: '/sub1', searchDeepLinks: [], keywords: [] }, - { - id: 'sub2', - title: 'Sub2', - path: '/sub2', - searchDeepLinks: [ - { - id: 'sub2sub1', - title: 'Sub2Sub1', - path: '/sub2/sub1', - searchDeepLinks: [], - keywords: ['TwoOne'], - }, - ], - keywords: ['two'], - }, - ], - keywords: [], - }, + deepLinks: [ + { + id: 'sub1', + title: 'Sub1', + path: '/sub1', + deepLinks: [], + keywords: [], + navLinkStatus: AppNavLinkStatus.hidden, + }, + { + id: 'sub2', + title: 'Sub2', + path: '/sub2', + deepLinks: [ + { + id: 'sub2sub1', + title: 'Sub2Sub1', + path: '/sub2/sub1', + deepLinks: [], + keywords: ['TwoOne'], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: ['two'], + navLinkStatus: AppNavLinkStatus.hidden, + }, + ], + keywords: [], }), ]; @@ -187,26 +197,17 @@ describe('scoreApp', () => { describe('when the term is included in the keywords but not in the title', () => { it(`returns 100 * ${keywordScoreWeighting} if one of the app meta keywords is an exact match`, () => { expect( - scoreApp( - 'bar', - createAppLink({ title: 'foo', meta: { keywords: ['bar'], searchDeepLinks: [] } }) - ) + scoreApp('bar', createAppLink({ title: 'foo', keywords: ['bar'], deepLinks: [] })) ).toBe(100 * keywordScoreWeighting); expect( - scoreApp( - 'bar', - createAppLink({ title: 'foo', meta: { keywords: ['BAR'], searchDeepLinks: [] } }) - ) + scoreApp('bar', createAppLink({ title: 'foo', keywords: ['BAR'], deepLinks: [] })) ).toBe(100 * keywordScoreWeighting); }); it(`returns 90 * ${keywordScoreWeighting} if any of the keywords start with the term`, () => { expect( scoreApp( 'viz', - createAppLink({ - title: 'Foo', - meta: { keywords: ['Vizualize', 'Viz view'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['Vizualize', 'Viz view'], deepLinks: [] }) ) ).toBe(90 * keywordScoreWeighting); }); @@ -214,19 +215,13 @@ describe('scoreApp', () => { expect( scoreApp( 'board', - createAppLink({ - title: 'Foo', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75 * keywordScoreWeighting); expect( scoreApp( 'shboa', - createAppLink({ - title: 'Foo', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Foo', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75 * keywordScoreWeighting); }); @@ -235,26 +230,17 @@ describe('scoreApp', () => { describe('when the term is included in the keywords and the title', () => { it('returns 100 if one of the app meta keywords and the title is an exact match', () => { expect( - scoreApp( - 'home', - createAppLink({ title: 'Home', meta: { keywords: ['home'], searchDeepLinks: [] } }) - ) + scoreApp('home', createAppLink({ title: 'Home', keywords: ['home'], deepLinks: [] })) ).toBe(100); expect( - scoreApp( - 'Home', - createAppLink({ title: 'Home', meta: { keywords: ['HOME'], searchDeepLinks: [] } }) - ) + scoreApp('Home', createAppLink({ title: 'Home', keywords: ['HOME'], deepLinks: [] })) ).toBe(100); }); it('returns 90 if either one of the keywords or the title start with the term', () => { expect( scoreApp( 'vis', - createAppLink({ - title: 'Visualize', - meta: { keywords: ['Visualise'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Visualize', keywords: ['Visualise'], deepLinks: [] }) ) ).toBe(90); }); @@ -262,19 +248,13 @@ describe('scoreApp', () => { expect( scoreApp( 'board', - createAppLink({ - title: 'Dashboard', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'Dashboard', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75); expect( scoreApp( 'shboa', - createAppLink({ - title: 'dashboard', - meta: { keywords: ['dashboard app'], searchDeepLinks: [] }, - }) + createAppLink({ title: 'dashboard', keywords: ['dashboard app'], deepLinks: [] }) ) ).toBe(75); }); @@ -285,19 +265,13 @@ describe('scoreApp', () => { expect( scoreApp( '0123456789', - createAppLink({ - title: '012345', - meta: { keywords: ['0345', '9987'], searchDeepLinks: [] }, - }) + createAppLink({ title: '012345', keywords: ['0345', '9987'], deepLinks: [] }) ) ).toBe(60); expect( scoreApp( '--1234567-', - createAppLink({ - title: '123456789', - meta: { keywords: ['--345--'], searchDeepLinks: [] }, - }) + createAppLink({ title: '123456789', keywords: ['--345--'], deepLinks: [] }) ) ).toBe(60); }); @@ -305,13 +279,13 @@ describe('scoreApp', () => { expect( scoreApp( '0123456789', - createAppLink({ title: '12345', meta: { keywords: ['12', '34'], searchDeepLinks: [] } }) + createAppLink({ title: '12345', keywords: ['12', '34'], deepLinks: [] }) ) ).toBe(0); expect( scoreApp( '1-2-3-4-5', - createAppLink({ title: '123456789', meta: { keywords: ['12-789'], searchDeepLinks: [] } }) + createAppLink({ title: '123456789', keywords: ['12-789'], deepLinks: [] }) ) ).toBe(0); }); diff --git a/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts b/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts index f5f0a2d34e91c..3ae1a082cdebf 100644 --- a/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts +++ b/x-pack/plugins/global_search_providers/public/providers/get_app_results.ts @@ -6,10 +6,10 @@ */ import levenshtein from 'js-levenshtein'; -import { PublicAppInfo, PublicAppSearchDeepLinkInfo } from 'src/core/public'; +import { PublicAppInfo, PublicAppDeepLinkInfo } from 'src/core/public'; import { GlobalSearchProviderResult } from '../../../global_search/public'; -/** Type used internally to represent an application unrolled into its separate searchDeepLinks */ +/** Type used internally to represent an application unrolled into its separate deepLinks */ export interface AppLink { id: string; app: PublicAppInfo; @@ -27,7 +27,7 @@ export const getAppResults = ( ): GlobalSearchProviderResult[] => { return ( apps - // Unroll all searchDeepLinks, only if there is a search term + // Unroll all deepLinks, only if there is a search term .flatMap((app) => term.length > 0 ? flattenDeepLinks(app) @@ -37,7 +37,7 @@ export const getAppResults = ( app, path: app.appRoute, subLinkTitles: [], - keywords: app.meta?.keywords ?? [], + keywords: app.keywords ?? [], }, ] ) @@ -56,7 +56,7 @@ export const scoreApp = (term: string, appLink: AppLink): number => { const appScoreByTerms = scoreAppByTerms(term, title); const keywords = [ - ...appLink.app.meta.keywords.map((keyword) => keyword.toLowerCase()), + ...appLink.app.keywords.map((keyword) => keyword.toLowerCase()), ...appLink.keywords.map((keyword) => keyword.toLowerCase()), ]; const appScoreByKeywords = scoreAppByKeywords(term, keywords); @@ -115,10 +115,7 @@ export const appToResult = (appLink: AppLink, score: number): GlobalSearchProvid }; }; -const flattenDeepLinks = ( - app: PublicAppInfo, - deepLink?: PublicAppSearchDeepLinkInfo -): AppLink[] => { +const flattenDeepLinks = (app: PublicAppInfo, deepLink?: PublicAppDeepLinkInfo): AppLink[] => { if (!deepLink) { return [ { @@ -126,9 +123,9 @@ const flattenDeepLinks = ( app, path: app.appRoute, subLinkTitles: [], - keywords: app.meta?.keywords ?? [], + keywords: app?.keywords ?? [], }, - ...app.meta.searchDeepLinks.flatMap((appDeepLink) => flattenDeepLinks(app, appDeepLink)), + ...app.deepLinks.flatMap((appDeepLink) => flattenDeepLinks(app, appDeepLink)), ]; } return [ @@ -143,7 +140,7 @@ const flattenDeepLinks = ( }, ] : []), - ...deepLink.searchDeepLinks + ...deepLink.deepLinks .flatMap((deepDeepLink) => flattenDeepLinks(app, deepDeepLink)) .map((deepAppLink) => ({ ...deepAppLink, diff --git a/x-pack/plugins/infra/public/pages/logs/page_content.tsx b/x-pack/plugins/infra/public/pages/logs/page_content.tsx index d43fe198c5077..9ae127a8eca66 100644 --- a/x-pack/plugins/infra/public/pages/logs/page_content.tsx +++ b/x-pack/plugins/infra/public/pages/logs/page_content.tsx @@ -40,7 +40,7 @@ export const LogsPageContent: React.FunctionComponent = () => { initialize(); }); - // !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/infra/public/plugin.ts + // !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts const streamTab = { app: 'logs', title: streamTabTitle, diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index b43d7640f6390..819c764bfb7ba 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -120,7 +120,7 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { > - {/** !! Need to be kept in sync with the searchDeepLinks in x-pack/plugins/infra/public/plugin.ts */} + {/** !! Need to be kept in sync with the deepLinks in x-pack/plugins/infra/public/plugin.ts */} { // mount callback should not use setup dependencies, get start dependencies instead @@ -115,32 +113,30 @@ export class Plugin implements InfraClientPluginClass { order: 8200, appRoute: '/app/metrics', category: DEFAULT_APP_CATEGORIES.observability, - meta: { - // !! Need to be kept in sync with the routes in x-pack/plugins/infra/public/pages/metrics/index.tsx - searchDeepLinks: [ - { - id: 'inventory', - title: i18n.translate('xpack.infra.homePage.inventoryTabTitle', { - defaultMessage: 'Inventory', - }), - path: '/inventory', - }, - { - id: 'metrics-explorer', - title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { - defaultMessage: 'Metrics Explorer', - }), - path: '/explorer', - }, - { - id: 'settings', - title: i18n.translate('xpack.infra.homePage.settingsTabTitle', { - defaultMessage: 'Settings', - }), - path: '/settings', - }, - ], - }, + // !! Need to be kept in sync with the routes in x-pack/plugins/infra/public/pages/metrics/index.tsx + deepLinks: [ + { + id: 'inventory', + title: i18n.translate('xpack.infra.homePage.inventoryTabTitle', { + defaultMessage: 'Inventory', + }), + path: '/inventory', + }, + { + id: 'metrics-explorer', + title: i18n.translate('xpack.infra.homePage.metricsExplorerTabTitle', { + defaultMessage: 'Metrics Explorer', + }), + path: '/explorer', + }, + { + id: 'settings', + title: i18n.translate('xpack.infra.homePage.settingsTabTitle', { + defaultMessage: 'Settings', + }), + path: '/settings', + }, + ], mount: async (params: AppMountParameters) => { // mount callback should not use setup dependencies, get start dependencies instead const [coreStart, pluginsStart] = await core.getStartServices(); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts index 6c219340da817..dd3ca0bb8fa30 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -9,20 +9,18 @@ import { i18n } from '@kbn/i18n'; import { BehaviorSubject } from 'rxjs'; import { AppUpdater } from 'src/core/public'; -import { getSearchDeepLinks } from './search_deep_links'; +import { getDeepLinks } from './search_deep_links'; export function registerSearchLinks( appUpdater: BehaviorSubject, isFullLicense: boolean ) { appUpdater.next(() => ({ - meta: { - keywords: [ - i18n.translate('xpack.ml.keyword.ml', { - defaultMessage: 'ML', - }), - ], - searchDeepLinks: getSearchDeepLinks(isFullLicense), - }, + keywords: [ + i18n.translate('xpack.ml.keyword.ml', { + defaultMessage: 'ML', + }), + ], + deepLinks: getDeepLinks(isFullLicense), })); } diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index d248df9088989..d682a93fa274c 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -7,35 +7,35 @@ import { i18n } from '@kbn/i18n'; -import type { AppSearchDeepLink } from 'src/core/public'; +import type { AppDeepLink } from 'src/core/public'; import { ML_PAGES } from '../../../common/constants/ml_url_generator'; -const OVERVIEW_LINK_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlOverviewSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.overview', { +const OVERVIEW_LINK_DEEP_LINK: AppDeepLink = { + id: 'mlOverviewDeepLink', + title: i18n.translate('xpack.ml.deepLink.overview', { defaultMessage: 'Overview', }), path: `/${ML_PAGES.OVERVIEW}`, }; -const ANOMALY_DETECTION_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlAnomalyDetectionSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.anomalyDetection', { +const ANOMALY_DETECTION_DEEP_LINK: AppDeepLink = { + id: 'mlAnomalyDetectionDeepLink', + title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { defaultMessage: 'Anomaly Detection', }), path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, }; -const DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlDataFrameAnalyticsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.dataFrameAnalytics', { +const DATA_FRAME_ANALYTICS_DEEP_LINK: AppDeepLink = { + id: 'mlDataFrameAnalyticsDeepLink', + title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { defaultMessage: 'Data Frame Analytics', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, - searchDeepLinks: [ + deepLinks: [ { - id: 'mlTrainedModelsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.trainedModels', { + id: 'mlTrainedModelsDeepLink', + title: i18n.translate('xpack.ml.deepLink.trainedModels', { defaultMessage: 'Trained Models', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MODELS_MANAGE}`, @@ -43,47 +43,47 @@ const DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK: AppSearchDeepLink = { ], }; -const DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlDataVisualizerSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.dataVisualizer', { +const DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { + id: 'mlDataVisualizerDeepLink', + title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { defaultMessage: 'Data Visualizer', }), path: `/${ML_PAGES.DATA_VISUALIZER}`, }; -const FILE_UPLOAD_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlFileUploadSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.fileUpload', { +const FILE_UPLOAD_DEEP_LINK: AppDeepLink = { + id: 'mlFileUploadDeepLink', + title: i18n.translate('xpack.ml.deepLink.fileUpload', { defaultMessage: 'File Upload', }), path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, }; -const INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlIndexDataVisualizerSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.indexDataVisualizer', { +const INDEX_DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { + id: 'mlIndexDataVisualizerDeepLink', + title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { defaultMessage: 'Index Data Visualizer', }), path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, }; -const SETTINGS_SEARCH_DEEP_LINK: AppSearchDeepLink = { - id: 'mlSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.settings', { +const SETTINGS_DEEP_LINK: AppDeepLink = { + id: 'mlSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.settings', { defaultMessage: 'Settings', }), path: `/${ML_PAGES.SETTINGS}`, - searchDeepLinks: [ + deepLinks: [ { - id: 'mlCalendarSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.calendarSettings', { + id: 'mlCalendarSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.calendarSettings', { defaultMessage: 'Calendars', }), path: `/${ML_PAGES.CALENDARS_MANAGE}`, }, { - id: 'mlFilterListsSettingsSearchDeepLink', - title: i18n.translate('xpack.ml.searchDeepLink.filterListsSettings', { + id: 'mlFilterListsSettingsDeepLink', + title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { defaultMessage: 'Filter Lists', }), path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. @@ -91,19 +91,19 @@ const SETTINGS_SEARCH_DEEP_LINK: AppSearchDeepLink = { ], }; -export function getSearchDeepLinks(isFullLicense: boolean) { - const deepLinks: AppSearchDeepLink[] = [ - DATA_VISUALIZER_SEARCH_DEEP_LINK, - FILE_UPLOAD_SEARCH_DEEP_LINK, - INDEX_DATA_VISUALIZER_SEARCH_DEEP_LINK, +export function getDeepLinks(isFullLicense: boolean) { + const deepLinks: AppDeepLink[] = [ + DATA_VISUALIZER_DEEP_LINK, + FILE_UPLOAD_DEEP_LINK, + INDEX_DATA_VISUALIZER_DEEP_LINK, ]; if (isFullLicense === true) { deepLinks.push( - OVERVIEW_LINK_SEARCH_DEEP_LINK, - ANOMALY_DETECTION_SEARCH_DEEP_LINK, - DATA_FRAME_ANALYTICS_SEARCH_DEEP_LINK, - SETTINGS_SEARCH_DEEP_LINK + OVERVIEW_LINK_DEEP_LINK, + ANOMALY_DETECTION_DEEP_LINK, + DATA_FRAME_ANALYTICS_DEEP_LINK, + SETTINGS_DEEP_LINK ); } diff --git a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts index 5af5a8adf95b7..aeee7077ec9c0 100644 --- a/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/detection_alerts/alerts_details.spec.ts @@ -23,7 +23,7 @@ import { unmappedRule } from '../../objects/rule'; import { DETECTIONS_URL } from '../../urls/navigation'; describe('Alert details with unmapped fields', () => { - before(() => { + beforeEach(() => { cleanKibana(); esArchiverLoad('unmapped_fields'); loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); diff --git a/x-pack/plugins/security_solution/public/app/search/index.test.ts b/x-pack/plugins/security_solution/public/app/search/index.test.ts index d6c36e89558d0..328395f9b85c9 100644 --- a/x-pack/plugins/security_solution/public/app/search/index.test.ts +++ b/x-pack/plugins/security_solution/public/app/search/index.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { getSearchDeepLinksAndKeywords } from '.'; +import { getDeepLinksAndKeywords } from '.'; import { SecurityPageName } from '../../../common/constants'; describe('public search functions', () => { @@ -13,10 +13,9 @@ describe('public search functions', () => { const platinumLicense = 'platinum'; for (const pageName of Object.values(SecurityPageName)) { expect.assertions(Object.values(SecurityPageName).length * 2); - const basicLinkCount = - getSearchDeepLinksAndKeywords(pageName, basicLicense).searchDeepLinks?.length || 0; - const platinumLinks = getSearchDeepLinksAndKeywords(pageName, platinumLicense); - expect(platinumLinks.searchDeepLinks?.length).toBeGreaterThanOrEqual(basicLinkCount); + const basicLinkCount = getDeepLinksAndKeywords(pageName, basicLicense).deepLinks?.length || 0; + const platinumLinks = getDeepLinksAndKeywords(pageName, platinumLicense); + expect(platinumLinks.deepLinks?.length).toBeGreaterThanOrEqual(basicLinkCount); expect(platinumLinks.keywords?.length).not.toBe(null); } }); diff --git a/x-pack/plugins/security_solution/public/app/search/index.ts b/x-pack/plugins/security_solution/public/app/search/index.ts index 110356269e891..93d931fc4d137 100644 --- a/x-pack/plugins/security_solution/public/app/search/index.ts +++ b/x-pack/plugins/security_solution/public/app/search/index.ts @@ -11,7 +11,7 @@ import { Subject } from 'rxjs'; import { AppUpdater } from 'src/core/public'; import { LicenseType } from '../../../../licensing/common/types'; import { SecuritySubPluginNames, SecurityDeepLinks } from '../types'; -import { AppMeta } from '../../../../../../src/core/public'; +import { App } from '../../../../../../src/core/public'; const securityDeepLinks: SecurityDeepLinks = { detections: { @@ -198,10 +198,10 @@ const subpluginKeywords: { [key in SecuritySubPluginNames]: string[] } = { * @param subPluginName SubPluginName of the app to retrieve meta information for. * @param licenseType optional string for license level, if not provided basic is assumed. */ -export function getSearchDeepLinksAndKeywords( +export function getDeepLinksAndKeywords( subPluginName: SecuritySubPluginNames, licenseType?: LicenseType -): AppMeta { +): Pick { const baseRoutes = [...securityDeepLinks[subPluginName].base]; if ( licenseType === 'gold' || @@ -214,29 +214,27 @@ export function getSearchDeepLinksAndKeywords( if (premiumRoutes !== undefined) { return { keywords: subpluginKeywords[subPluginName], - searchDeepLinks: [...baseRoutes, ...premiumRoutes], + deepLinks: [...baseRoutes, ...premiumRoutes], }; } } return { keywords: subpluginKeywords[subPluginName], - searchDeepLinks: baseRoutes, + deepLinks: baseRoutes, }; } /** * A function that updates a subplugin's meta property as appropriate when license level changes. - * @param subPluginName SubPluginName of the app to register searchDeepLinks for + * @param subPluginName SubPluginName of the app to register deepLinks for * @param appUpdater an instance of appUpdater$ observable to update search links when needed. * @param licenseType A string representing the current license level. */ -export function registerSearchLinks( +export function registerDeepLinks( subPluginName: SecuritySubPluginNames, appUpdater?: Subject, licenseType?: LicenseType ) { if (appUpdater !== undefined) { - appUpdater.next(() => ({ - meta: getSearchDeepLinksAndKeywords(subPluginName, licenseType), - })); + appUpdater.next(() => ({ ...getDeepLinksAndKeywords(subPluginName, licenseType) })); } } diff --git a/x-pack/plugins/security_solution/public/app/types.ts b/x-pack/plugins/security_solution/public/app/types.ts index a617c6f14b9c4..77d5b99e1c3a3 100644 --- a/x-pack/plugins/security_solution/public/app/types.ts +++ b/x-pack/plugins/security_solution/public/app/types.ts @@ -17,7 +17,7 @@ import { CombinedState, } from 'redux'; -import { AppMountParameters, AppSearchDeepLink } from '../../../../../src/core/public'; +import { AppMountParameters, AppDeepLink } from '../../../../../src/core/public'; import { StartServices } from '../types'; /** @@ -58,8 +58,8 @@ export type SecuritySubPluginKeyStore = export type SecuritySubPluginNames = keyof typeof SecurityPageName; interface SecurityDeepLink { - base: AppSearchDeepLink[]; - premium?: AppSearchDeepLink[]; + base: AppDeepLink[]; + premium?: AppDeepLink[]; } export type SecurityDeepLinks = { [key in SecuritySubPluginNames]: SecurityDeepLink }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index efbe857d168d8..c1f501d3f7094 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -47,7 +47,7 @@ import { } from '../common/constants'; import { SecurityPageName } from './app/types'; -import { registerSearchLinks, getSearchDeepLinksAndKeywords } from './app/search'; +import { registerDeepLinks, getDeepLinksAndKeywords } from './app/search'; import { manageOldSiemRoutes } from './helpers'; import { OVERVIEW, @@ -258,7 +258,7 @@ export class Plugin implements IPlugin { const [coreStart, startPlugins] = await core.getStartServices(); const { timelines: subPlugin } = await this.subPlugins(); @@ -300,7 +300,7 @@ export class Plugin implements IPlugin { const [coreStart, startPlugins] = await core.getStartServices(); const { management: managementSubPlugin } = await this.subPlugins(); @@ -366,19 +366,19 @@ export class Plugin implements IPlugin { if (currentLicense.type !== undefined) { - registerSearchLinks(SecurityPageName.network, this.networkUpdater$, currentLicense.type); - registerSearchLinks( + registerDeepLinks(SecurityPageName.network, this.networkUpdater$, currentLicense.type); + registerDeepLinks( SecurityPageName.detections, this.detectionsUpdater$, currentLicense.type ); - registerSearchLinks(SecurityPageName.hosts, this.hostsUpdater$, currentLicense.type); - registerSearchLinks(SecurityPageName.case, this.caseUpdater$, currentLicense.type); + registerDeepLinks(SecurityPageName.hosts, this.hostsUpdater$, currentLicense.type); + registerDeepLinks(SecurityPageName.case, this.caseUpdater$, currentLicense.type); } }); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 134f58236cfee..af6cdd1d672a1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -15978,16 +15978,16 @@ "xpack.ml.ruleEditor.selectRuleAction.orText": "OR ", "xpack.ml.ruleEditor.typicalAppliesTypeText": "通常", "xpack.ml.sampleDataLinkLabel": "ML ジョブ", - "xpack.ml.searchDeepLink.anomalyDetection": "異常検知", - "xpack.ml.searchDeepLink.calendarSettings": "カレンダー", - "xpack.ml.searchDeepLink.dataFrameAnalytics": "データフレーム分析", - "xpack.ml.searchDeepLink.dataVisualizer": "データビジュアライザー", - "xpack.ml.searchDeepLink.fileUpload": "ファイルアップロード", - "xpack.ml.searchDeepLink.filterListsSettings": "フィルターリスト", - "xpack.ml.searchDeepLink.indexDataVisualizer": "インデックスデータビジュアライザー", - "xpack.ml.searchDeepLink.overview": "概要", - "xpack.ml.searchDeepLink.settings": "設定", - "xpack.ml.searchDeepLink.trainedModels": "学習済みモデル", + "xpack.ml.deepLink.anomalyDetection": "異常検知", + "xpack.ml.deepLink.calendarSettings": "カレンダー", + "xpack.ml.deepLink.dataFrameAnalytics": "データフレーム分析", + "xpack.ml.deepLink.dataVisualizer": "データビジュアライザー", + "xpack.ml.deepLink.fileUpload": "ファイルアップロード", + "xpack.ml.deepLink.filterListsSettings": "フィルターリスト", + "xpack.ml.deepLink.indexDataVisualizer": "インデックスデータビジュアライザー", + "xpack.ml.deepLink.overview": "概要", + "xpack.ml.deepLink.settings": "設定", + "xpack.ml.deepLink.trainedModels": "学習済みモデル", "xpack.ml.settings.anomalyDetection.anomalyDetectionTitle": "異常検知", "xpack.ml.settings.anomalyDetection.calendarsText": "システム停止日や祝日など、異常値を生成したくないイベントについては、カレンダーに予定されているイベントのリストを登録できます。", "xpack.ml.settings.anomalyDetection.calendarsTitle": "カレンダー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 67677f86ddbf7..c8376b72daef1 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16203,16 +16203,16 @@ "xpack.ml.ruleEditor.selectRuleAction.orText": "或 ", "xpack.ml.ruleEditor.typicalAppliesTypeText": "典型", "xpack.ml.sampleDataLinkLabel": "ML 作业", - "xpack.ml.searchDeepLink.anomalyDetection": "异常检测", - "xpack.ml.searchDeepLink.calendarSettings": "日历", - "xpack.ml.searchDeepLink.dataFrameAnalytics": "数据帧分析", - "xpack.ml.searchDeepLink.dataVisualizer": "数据可视化工具", - "xpack.ml.searchDeepLink.fileUpload": "文件上传", - "xpack.ml.searchDeepLink.filterListsSettings": "筛选列表", - "xpack.ml.searchDeepLink.indexDataVisualizer": "索引数据可视化工具", - "xpack.ml.searchDeepLink.overview": "概览", - "xpack.ml.searchDeepLink.settings": "设置", - "xpack.ml.searchDeepLink.trainedModels": "已训练模型", + "xpack.ml.deepLink.anomalyDetection": "异常检测", + "xpack.ml.deepLink.calendarSettings": "日历", + "xpack.ml.deepLink.dataFrameAnalytics": "数据帧分析", + "xpack.ml.deepLink.dataVisualizer": "数据可视化工具", + "xpack.ml.deepLink.fileUpload": "文件上传", + "xpack.ml.deepLink.filterListsSettings": "筛选列表", + "xpack.ml.deepLink.indexDataVisualizer": "索引数据可视化工具", + "xpack.ml.deepLink.overview": "概览", + "xpack.ml.deepLink.settings": "设置", + "xpack.ml.deepLink.trainedModels": "已训练模型", "xpack.ml.settings.anomalyDetection.anomalyDetectionTitle": "异常检测", "xpack.ml.settings.anomalyDetection.calendarsSummaryCount": "您有 {calendarsCountBadge} 个{calendarsCount, plural, other {日历}}", "xpack.ml.settings.anomalyDetection.calendarsText": "日志包含不应生成异常的已计划事件列表,例如已计划系统中断或公共假期。", diff --git a/x-pack/plugins/uptime/public/apps/plugin.ts b/x-pack/plugins/uptime/public/apps/plugin.ts index 0832274f0785a..80a131676951e 100644 --- a/x-pack/plugins/uptime/public/apps/plugin.ts +++ b/x-pack/plugins/uptime/public/apps/plugin.ts @@ -104,28 +104,26 @@ export class UptimePlugin order: 8400, title: PLUGIN.TITLE, category: DEFAULT_APP_CATEGORIES.observability, - meta: { - keywords: [ - 'Synthetics', - 'pings', - 'checks', - 'availability', - 'response duration', - 'response time', - 'outside in', - 'reachability', - 'reachable', - 'digital', - 'performance', - 'web performance', - 'web perf', - ], - searchDeepLinks: [ - { id: 'Down monitors', title: 'Down monitors', path: '/?statusFilter=down' }, - { id: 'Certificates', title: 'TLS Certificates', path: '/certificates' }, - { id: 'Settings', title: 'Settings', path: '/settings' }, - ], - }, + keywords: [ + 'Synthetics', + 'pings', + 'checks', + 'availability', + 'response duration', + 'response time', + 'outside in', + 'reachability', + 'reachable', + 'digital', + 'performance', + 'web performance', + 'web perf', + ], + deepLinks: [ + { id: 'Down monitors', title: 'Down monitors', path: '/?statusFilter=down' }, + { id: 'Certificates', title: 'TLS Certificates', path: '/certificates' }, + { id: 'Settings', title: 'Settings', path: '/settings' }, + ], mount: async (params: AppMountParameters) => { const [coreStart, corePlugins] = await core.getStartServices(); From 60b5c842cd0405e24901b4944f51e555358679f6 Mon Sep 17 00:00:00 2001 From: Sandra Gonzales Date: Tue, 25 May 2021 08:51:24 -0400 Subject: [PATCH 15/22] [Metrics UI] use EuiTooltip to control tooltip component and simplify ConditionalTooltip (#99224) * use EuiTooltip to control tooltip component * fix style * update unit tests * add functional waffle map tooltip tests * remove reload() from useEffect * fix type * update unit test --- .../conditional_tooltip.test.tsx.snap | 226 +++++++++++++----- .../waffle/conditional_tooltip.test.tsx | 106 ++------ .../components/waffle/conditional_tooltip.tsx | 168 +++++-------- .../inventory_view/components/waffle/node.tsx | 15 +- .../test/functional/apps/infra/home_page.ts | 3 +- .../page_objects/infra_home_page.ts | 29 +++ 6 files changed, 277 insertions(+), 270 deletions(-) diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap index a5d97813e4b14..91bafb3b15e4d 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/__snapshots__/conditional_tooltip.test.tsx.snap @@ -1,8 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ConditionalToolTip should just work 1`] = ` +exports[`ConditionalToolTip renders correctly 1`] = `
- - CPU usage - - - 10% - + +
+ CPU usage +
+
+ +
+ 10% +
+
+
- - Memory usage - - - 80% - + +
+ Memory usage +
+
+ +
+ 80% +
+
+
- - Outbound traffic - - - 8Mbit/s - + +
+ Outbound traffic +
+
+ +
+ 8Mbit/s +
+
+
- - Inbound traffic - - - 8Mbit/s - + +
+ Inbound traffic +
+
+ +
+ 8Mbit/s +
+
+
- - My Custom Label - - - 34.1% - + +
+ My Custom Label +
+
+ +
+ 34.1% +
+
+
- - Avg of host.network.out.packets - - - 4,392.2 - + +
+ Avg of host.network.out.packets +
+
+ +
+ 4,392.2 +
+
+
`; diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx index 6dde53efae761..ac4fac394dacc 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.test.tsx @@ -7,15 +7,10 @@ import React from 'react'; import { mount } from 'enzyme'; -// import { act } from 'react-dom/test-utils'; +import toJson from 'enzyme-to-json'; import { EuiThemeProvider } from '../../../../../../../../../src/plugins/kibana_react/common'; -import { EuiToolTip } from '@elastic/eui'; import { ConditionalToolTip } from './conditional_tooltip'; -import { - InfraWaffleMapNode, - InfraWaffleMapOptions, - InfraFormatterType, -} from '../../../../../lib/lib'; +import { InfraWaffleMapNode } from '../../../../../lib/lib'; jest.mock('../../../../../containers/metrics_source', () => ({ useSourceContext: () => ({ sourceId: 'default' }), @@ -38,61 +33,12 @@ const NODE: InfraWaffleMapNode = { metrics: [{ name: 'cpu' }], }; -const OPTIONS: InfraWaffleMapOptions = { - formatter: InfraFormatterType.percent, - formatTemplate: '{value}', - metric: { type: 'cpu' }, - groupBy: [], - legend: { - type: 'steppedGradient', - rules: [], - }, - sort: { by: 'value', direction: 'desc' }, -}; - export const nextTick = () => new Promise((res) => process.nextTick(res)); -const ChildComponent = () =>
child
; describe('ConditionalToolTip', () => { - afterEach(() => { - mockedUseSnapshot.mockReset(); - mockedUseWaffleOptionsContext.mockReset(); - }); - - function createWrapper(currentTime: number = Date.now(), hidden: boolean = false) { - return mount( - - - - ); - } - - it('should return children when hidden', () => { - mockedUseSnapshot.mockReturnValue({ - nodes: [], - error: null, - loading: true, - interval: '', - reload: jest.fn(() => Promise.resolve()), - }); - mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, true); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - }); + const currentTime = Date.now(); - it('should just work', () => { - jest.useFakeTimers(); - const reloadMock = jest.fn(() => Promise.resolve()); + it('renders correctly', () => { mockedUseSnapshot.mockReturnValue({ nodes: [ { @@ -121,13 +67,9 @@ describe('ConditionalToolTip', () => { error: null, loading: false, interval: '60s', - reload: reloadMock, + reload: jest.fn(() => Promise.resolve()), }); mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, false); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - expect(wrapper.find(EuiToolTip).exists()).toBeTruthy(); const expectedQuery = JSON.stringify({ bool: { filter: { @@ -154,6 +96,14 @@ describe('ConditionalToolTip', () => { type: 'custom', }, ]; + const wrapper = mount( + + + + ); + const tooltip = wrapper.find('[data-test-subj~="conditionalTooltipContent-host-01"]'); + expect(toJson(tooltip)).toMatchSnapshot(); + expect(mockedUseSnapshot).toBeCalledWith( expectedQuery, expectedMetrics, @@ -162,36 +112,8 @@ describe('ConditionalToolTip', () => { 'default', currentTime, '', - '', - false + '' ); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOver'); - wrapper.find(EuiToolTip).simulate('mouseOver'); - jest.advanceTimersByTime(500); - expect(reloadMock).toHaveBeenCalled(); - expect(wrapper.find(EuiToolTip).props().content).toMatchSnapshot(); - }); - - it('should not load data if mouse out before 200 ms', () => { - jest.useFakeTimers(); - const reloadMock = jest.fn(() => Promise.resolve()); - mockedUseSnapshot.mockReturnValue({ - nodes: [], - error: null, - loading: true, - interval: '', - reload: reloadMock, - }); - mockedUseWaffleOptionsContext.mockReturnValue(mockedUseWaffleOptionsContexReturnValue); - const currentTime = Date.now(); - const wrapper = createWrapper(currentTime, false); - expect(wrapper.find(ChildComponent).exists()).toBeTruthy(); - expect(wrapper.find(EuiToolTip).exists()).toBeTruthy(); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOver'); - jest.advanceTimersByTime(100); - wrapper.find('[data-test-subj~="conditionalTooltipMouseHandler"]').simulate('mouseOut'); - jest.advanceTimersByTime(200); - expect(reloadMock).not.toHaveBeenCalled(); }); }); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx index 6e334f4fbca75..a47512906abd1 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/conditional_tooltip.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { useCallback, useState, useEffect } from 'react'; -import { EuiToolTip, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { first } from 'lodash'; import { getCustomMetricLabel } from '../../../../../../common/formatters/get_custom_metric_label'; import { SnapshotCustomMetricInput } from '../../../../../../common/http_api'; @@ -18,7 +18,7 @@ import { SnapshotMetricType, SnapshotMetricTypeRT, } from '../../../../../../common/inventory_models/types'; -import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; +import { InfraWaffleMapNode } from '../../../../../lib/lib'; import { useSnapshot } from '../../hooks/use_snaphot'; import { createInventoryMetricFormatter } from '../../lib/create_inventory_metric_formatter'; import { SNAPSHOT_METRIC_TRANSLATIONS } from '../../../../../../common/inventory_models/intl_strings'; @@ -27,113 +27,69 @@ import { createFormatterForMetric } from '../../../metrics_explorer/components/h export interface Props { currentTime: number; - hidden: boolean; node: InfraWaffleMapNode; - options: InfraWaffleMapOptions; - formatter: (val: number) => string; - children: React.ReactElement; nodeType: InventoryItemType; theme: EuiTheme | undefined; } - -export const ConditionalToolTip = withTheme( - ({ theme, hidden, node, children, nodeType, currentTime }: Props) => { - const { sourceId } = useSourceContext(); - const [timer, setTimer] = useState | null>(null); - const model = findInventoryModel(nodeType); - const { customMetrics } = useWaffleOptionsContext(); - const requestMetrics = model.tooltipMetrics - .map((type) => ({ type })) - .concat(customMetrics) as Array< - | { - type: SnapshotMetricType; - } - | SnapshotCustomMetricInput - >; - const query = JSON.stringify({ - bool: { - filter: { - match_phrase: { [model.fields.id]: node.id }, - }, +export const ConditionalToolTip = withTheme(({ theme, node, nodeType, currentTime }: Props) => { + const { sourceId } = useSourceContext(); + const model = findInventoryModel(nodeType); + const { customMetrics } = useWaffleOptionsContext(); + const requestMetrics = model.tooltipMetrics + .map((type) => ({ type })) + .concat(customMetrics) as Array< + | { + type: SnapshotMetricType; + } + | SnapshotCustomMetricInput + >; + const query = JSON.stringify({ + bool: { + filter: { + match_phrase: { [model.fields.id]: node.id }, }, - }); - const { nodes, reload } = useSnapshot( - query, - requestMetrics, - [], - nodeType, - sourceId, - currentTime, - '', - '', - false // Doesn't send request until reload() is called - ); - - const handleDataLoad = useCallback(() => { - const id = setTimeout(reload, 200); - setTimer(id); - }, [reload]); - - const cancelDataLoad = useCallback(() => { - return (timer && clearTimeout(timer)) || void 0; - }, [timer]); + }, + }); + const { nodes } = useSnapshot(query, requestMetrics, [], nodeType, sourceId, currentTime, '', ''); - useEffect(() => { - return cancelDataLoad; - }, [timer, cancelDataLoad]); - - if (hidden) { - return children; - } - const dataNode = first(nodes); - const metrics = (dataNode && dataNode.metrics) || []; - const content = ( -
-
- {node.name} -
- {metrics.map((metric) => { - const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom'; - const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName; - // if custom metric, find field and label from waffleOptionsContext result - // because useSnapshot does not return it - const customMetric = - name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null; - const formatter = customMetric - ? createFormatterForMetric(customMetric) - : createInventoryMetricFormatter({ type: metricName }); - return ( - - - {customMetric ? getCustomMetricLabel(customMetric) : name} - - - {(metric.value && formatter(metric.value)) || '-'} - - - ); - })} + const dataNode = first(nodes); + const metrics = (dataNode && dataNode.metrics) || []; + return ( +
+
+ {node.name}
- ); - - return ( - -
- {children} -
-
- ); - } -); + {metrics.map((metric) => { + const metricName = SnapshotMetricTypeRT.is(metric.name) ? metric.name : 'custom'; + const name = SNAPSHOT_METRIC_TRANSLATIONS[metricName] || metricName; + // if custom metric, find field and label from waffleOptionsContext result + // because useSnapshot does not return it + const customMetric = + name === 'custom' ? customMetrics.find((item) => item.id === metric.name) : null; + const formatter = customMetric + ? createFormatterForMetric(customMetric) + : createInventoryMetricFormatter({ type: metricName }); + return ( + + + {customMetric ? getCustomMetricLabel(customMetric) : name} + + + {(metric.value && formatter(metric.value)) || '-'} + + + ); + })} +
+ ); +}); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx index e972f9ca4f345..031b826265e16 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node.tsx @@ -11,7 +11,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { first } from 'lodash'; -import { EuiPopover } from '@elastic/eui'; +import { EuiPopover, EuiToolTip } from '@elastic/eui'; import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common'; import { InfraWaffleMapBounds, @@ -64,13 +64,10 @@ export class Node extends React.PureComponent { const nodeBorder = this.state.isOverlayOpen ? { border: 'solid 4px #000' } : undefined; const button = ( - + ); return ( diff --git a/x-pack/test/functional/apps/infra/home_page.ts b/x-pack/test/functional/apps/infra/home_page.ts index 1cc7c87f3a1a8..7578abbad33e7 100644 --- a/x-pack/test/functional/apps/infra/home_page.ts +++ b/x-pack/test/functional/apps/infra/home_page.ts @@ -38,9 +38,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => await esArchiver.unload('infra/metrics_and_logs')); - it('renders the waffle map for dates with data', async () => { + it('renders the waffle map and tooltips for dates with data', async () => { await pageObjects.infraHome.goToTime(DATE_WITH_DATA); await pageObjects.infraHome.getWaffleMap(); + await pageObjects.infraHome.getWaffleMapTooltips(); }); it('renders an empty data prompt for dates with no data', async () => { diff --git a/x-pack/test/functional/page_objects/infra_home_page.ts b/x-pack/test/functional/page_objects/infra_home_page.ts index 04dfbe5da0002..2f4575d45cc20 100644 --- a/x-pack/test/functional/page_objects/infra_home_page.ts +++ b/x-pack/test/functional/page_objects/infra_home_page.ts @@ -5,6 +5,7 @@ * 2.0. */ +import expect from '@kbn/expect/expect.js'; import testSubjSelector from '@kbn/test-subj-selector'; import { FtrProviderContext } from '../ftr_provider_context'; @@ -34,6 +35,34 @@ export function InfraHomePageProvider({ getService }: FtrProviderContext) { return await testSubjects.find('waffleMap'); }, + async getWaffleMapTooltips() { + const node = await testSubjects.findAll('nodeContainer'); + await node[0].moveMouseTo(); + const tooltip = await testSubjects.find('conditionalTooltipContent-demo-stack-redis-01'); + const metrics = await tooltip.findAllByTestSubject('conditionalTooltipContent-metric'); + const values = await tooltip.findAllByTestSubject('conditionalTooltipContent-value'); + expect(await metrics[0].getVisibleText()).to.be('CPU usage'); + expect(await values[0].getVisibleText()).to.be('1%'); + expect(await metrics[1].getVisibleText()).to.be('Memory usage'); + expect(await values[1].getVisibleText()).to.be('15.9%'); + expect(await metrics[2].getVisibleText()).to.be('Outbound traffic'); + expect(await values[2].getVisibleText()).to.be('71.9kbit/s'); + expect(await metrics[3].getVisibleText()).to.be('Inbound traffic'); + expect(await values[3].getVisibleText()).to.be('25.6kbit/s'); + await node[1].moveMouseTo(); + const tooltip2 = await testSubjects.find('conditionalTooltipContent-demo-stack-nginx-01'); + const metrics2 = await tooltip2.findAllByTestSubject('conditionalTooltipContent-metric'); + const values2 = await tooltip2.findAllByTestSubject('conditionalTooltipContent-value'); + expect(await metrics2[0].getVisibleText()).to.be('CPU usage'); + expect(await values2[0].getVisibleText()).to.be('1.1%'); + expect(await metrics2[1].getVisibleText()).to.be('Memory usage'); + expect(await values2[1].getVisibleText()).to.be('18%'); + expect(await metrics2[2].getVisibleText()).to.be('Outbound traffic'); + expect(await values2[2].getVisibleText()).to.be('256.3kbit/s'); + expect(await metrics2[3].getVisibleText()).to.be('Inbound traffic'); + expect(await values2[3].getVisibleText()).to.be('255.1kbit/s'); + }, + async openInvenotrySwitcher() { await testSubjects.click('openInventorySwitcher'); return await testSubjects.find('goToHost'); From ca324c63be2d9f9bda21d372c125ac07d924dd25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Tue, 25 May 2021 15:19:42 +0200 Subject: [PATCH 16/22] Removes event filters feature flag and exposes this feature by default (#100389) * Removes event filters feature flag and expose this feature by default * Fixes manifest unit test * Fixes functional test adding event filter list case Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../exception_list_client.mock.ts | 6 +- .../common/experimental_features.ts | 1 - .../public/common/mock/global_state.ts | 1 - .../components/administration_list_page.tsx | 22 ++-- .../event_filter_delete_modal.test.tsx | 1 - .../view/event_filters_list_page.test.tsx | 1 - .../public/management/pages/index.tsx | 7 +- .../timeline/body/actions/index.tsx | 7 +- .../server/endpoint/lib/artifacts/mocks.ts | 30 +++++ .../manifest_manager/manifest_manager.mock.ts | 17 +-- .../manifest_manager/manifest_manager.test.ts | 45 +++++++- .../manifest_manager/manifest_manager.ts | 5 +- .../factory/hosts/details/index.test.tsx | 1 - .../apps/endpoint/policy_details.ts | 108 ++++++++++++++++++ 14 files changed, 204 insertions(+), 48 deletions(-) diff --git a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts index 973f5822cae2b..1566241e7351e 100644 --- a/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts +++ b/x-pack/plugins/lists/server/services/exception_lists/exception_list_client.mock.ts @@ -32,9 +32,11 @@ export class ExceptionListClientMock extends ExceptionListClient { public createEndpointList = jest.fn().mockResolvedValue(getExceptionListSchemaMock()); } -export const getExceptionListClientMock = (): ExceptionListClient => { +export const getExceptionListClientMock = ( + savedObject?: ReturnType +): ExceptionListClient => { const mock = new ExceptionListClientMock({ - savedObjectsClient: savedObjectsClientMock.create(), + savedObjectsClient: savedObject ? savedObject : savedObjectsClientMock.create(), user: 'elastic', }); return mock; diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 8d1cc4ca2c1f0..6195dd61a7984 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -14,7 +14,6 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues; const allowedExperimentalValues = Object.freeze({ trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, - eventFilteringEnabled: false, hostIsolationEnabled: false, }); diff --git a/x-pack/plugins/security_solution/public/common/mock/global_state.ts b/x-pack/plugins/security_solution/public/common/mock/global_state.ts index b1b3147f4f494..af278b09e719c 100644 --- a/x-pack/plugins/security_solution/public/common/mock/global_state.ts +++ b/x-pack/plugins/security_solution/public/common/mock/global_state.ts @@ -40,7 +40,6 @@ export const mockGlobalState: State = { { id: 'error-id-2', title: 'title-2', message: ['error-message-2'] }, ], enableExperimental: { - eventFilteringEnabled: false, trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, hostIsolationEnabled: false, diff --git a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx index 02fbb4f4b0296..72a6de2a2de8d 100644 --- a/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx +++ b/x-pack/plugins/security_solution/public/management/components/administration_list_page.tsx @@ -25,7 +25,6 @@ import { getEventFiltersListPath, getTrustedAppsListPath, } from '../common/routing'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; /** Ensure that all flyouts z-index in Administation area show the flyout header */ const EuiPanelStyled = styled(EuiPanel)` @@ -44,7 +43,6 @@ interface AdministrationListPageProps { export const AdministrationListPage: FC = memo( ({ beta, title, subtitle, actions, children, headerBackComponent, ...otherProps }) => { - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const badgeOptions = !beta ? undefined : { beta: true, text: BETA_BADGE_LABEL }; return ( @@ -77,18 +75,14 @@ export const AdministrationListPage: FC diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx index cec3e34d9c98f..c594aaa5c7e19 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/components/event_filter_delete_modal.test.tsx @@ -64,7 +64,6 @@ describe('When event filters delete modal is shown', () => { }; waitForAction = mockedContext.middlewareSpy.waitForAction; - mockedContext.setExperimentalFlag({ eventFilteringEnabled: true }); }); it('should display name of event filter in body message', async () => { diff --git a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx index 2fbabad746cad..465f92dfda767 100644 --- a/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/event_filters/view/event_filters_list_page.test.tsx @@ -41,7 +41,6 @@ describe('When on the Event Filters List Page', () => { waitForAction = mockedContext.middlewareSpy.waitForAction; act(() => { - mockedContext.setExperimentalFlag({ eventFilteringEnabled: true }); history.push('/event_filters'); }); }); diff --git a/x-pack/plugins/security_solution/public/management/pages/index.tsx b/x-pack/plugins/security_solution/public/management/pages/index.tsx index 4be75117daeda..8273f1a6e55c2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/index.tsx @@ -25,7 +25,6 @@ import { SecurityPageName } from '../../../common/constants'; import { SpyRoute } from '../../common/utils/route/spy_routes'; import { useIngestEnabledCheck } from '../../common/hooks/endpoint/ingest_enabled'; import { EventFiltersContainer } from './event_filters'; -import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; const NoPermissions = memo(() => { return ( @@ -58,7 +57,6 @@ NoPermissions.displayName = 'NoPermissions'; export const ManagementContainer = memo(() => { const history = useHistory(); - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); const { allEnabled: isIngestEnabled } = useIngestEnabledCheck(); if (!isIngestEnabled) { @@ -70,10 +68,7 @@ export const ManagementContainer = memo(() => { - - {isEventFilteringEnabled && ( - - )} + = ({ const emptyNotes: string[] = []; const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); - const isEventFilteringEnabled = useIsExperimentalFeatureEnabled('eventFilteringEnabled'); - const handleSelectEvent = useCallback( (event: React.ChangeEvent) => onRowSelected({ @@ -116,8 +113,8 @@ const ActionsComponent: React.FC = ({ const eventType = getEventType(ecsData); const isEventContextMenuEnabled = useMemo( - () => isEventFilteringEnabled && !!ecsData.event?.kind && ecsData.event?.kind[0] === 'event', - [ecsData.event?.kind, isEventFilteringEnabled] + () => !!ecsData.event?.kind && ecsData.event?.kind[0] === 'event', + [ecsData.event?.kind] ); return ( diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts index 85857301d5f39..cda42bdf3f585 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/mocks.ts @@ -92,6 +92,36 @@ export const createPackagePolicyWithInitialManifestMock = (): PackagePolicy => { artifact_manifest: { value: { artifacts: { + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, 'endpoint-exceptionlist-macos-v1': { compression_algorithm: 'zlib', encryption_algorithm: 'none', diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts index f471ace617a6d..e0bbfc351a20f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.mock.ts @@ -69,13 +69,16 @@ export interface ManifestManagerMockOptions { export const buildManifestManagerMockOptions = ( opts: Partial -): ManifestManagerMockOptions => ({ - cache: new LRU({ max: 10, maxAge: 1000 * 60 * 60 }), - exceptionListClient: listMock.getExceptionListClient(), - packagePolicyService: createPackagePolicyServiceMock(), - savedObjectsClient: savedObjectsClientMock.create(), - ...opts, -}); +): ManifestManagerMockOptions => { + const savedObjectMock = savedObjectsClientMock.create(); + return { + cache: new LRU({ max: 10, maxAge: 1000 * 60 * 60 }), + exceptionListClient: listMock.getExceptionListClient(savedObjectMock), + packagePolicyService: createPackagePolicyServiceMock(), + savedObjectsClient: savedObjectMock, + ...opts, + }; +}; export const buildManifestManagerContextMock = ( opts: Partial diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts index e1de39482428d..7719dbf30c72b 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.test.ts @@ -65,6 +65,9 @@ describe('ManifestManager', () => { const ARTIFACT_NAME_TRUSTED_APPS_MACOS = 'endpoint-trustlist-macos-v1'; const ARTIFACT_NAME_TRUSTED_APPS_WINDOWS = 'endpoint-trustlist-windows-v1'; const ARTIFACT_NAME_TRUSTED_APPS_LINUX = 'endpoint-trustlist-linux-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_MACOS = 'endpoint-eventfilterlist-macos-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_WINDOWS = 'endpoint-eventfilterlist-windows-v1'; + const ARTIFACT_NAME_EVENT_FILTERS_LINUX = 'endpoint-eventfilterlist-linux-v1'; let ARTIFACTS: InternalArtifactCompleteSchema[] = []; let ARTIFACTS_BY_ID: { [K: string]: InternalArtifactCompleteSchema } = {}; @@ -219,6 +222,9 @@ describe('ManifestManager', () => { ARTIFACT_NAME_TRUSTED_APPS_MACOS, ARTIFACT_NAME_TRUSTED_APPS_WINDOWS, ARTIFACT_NAME_TRUSTED_APPS_LINUX, + ARTIFACT_NAME_EVENT_FILTERS_MACOS, + ARTIFACT_NAME_EVENT_FILTERS_WINDOWS, + ARTIFACT_NAME_EVENT_FILTERS_LINUX, ]; const getArtifactIds = (artifacts: InternalArtifactSchema[]) => [ @@ -249,6 +255,11 @@ describe('ManifestManager', () => { context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({}); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); const manifest = await manifestManager.buildNewManifest(); expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); @@ -257,7 +268,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -280,6 +291,11 @@ describe('ManifestManager', () => { [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, [ENDPOINT_TRUSTED_APPS_LIST_ID]: { linux: [trustedAppListItem] }, }); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); const manifest = await manifestManager.buildNewManifest(); @@ -290,7 +306,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -304,6 +320,9 @@ describe('ManifestManager', () => { expect(await uncompressArtifact(artifacts[5])).toStrictEqual({ entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), }); + expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); for (const artifact of artifacts) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); @@ -323,7 +342,11 @@ describe('ManifestManager', () => { [ENDPOINT_LIST_ID]: { macos: [exceptionListItem] }, }); context.packagePolicyService.listIds = mockPolicyListIdsResponse([TEST_POLICY_ID_1]); - + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); const oldManifest = await manifestManager.buildNewManifest(); context.exceptionListClient.findExceptionListItem = mockFindExceptionListItemResponses({ @@ -339,7 +362,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(6); + expect(artifacts.length).toBe(9); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -351,6 +374,9 @@ describe('ManifestManager', () => { expect(await uncompressArtifact(artifacts[5])).toStrictEqual({ entries: translateToEndpointExceptions([trustedAppListItem], 'v1'), }); + expect(await uncompressArtifact(artifacts[6])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); for (const artifact of artifacts) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); @@ -384,6 +410,12 @@ describe('ManifestManager', () => { TEST_POLICY_ID_2, ]); + context.savedObjectsClient.create = jest + .fn() + .mockImplementation((type: string, object: InternalManifestSchema) => ({ + attributes: object, + })); + const manifest = await manifestManager.buildNewManifest(); expect(manifest?.getSchemaVersion()).toStrictEqual('v1'); @@ -392,7 +424,7 @@ describe('ManifestManager', () => { const artifacts = manifest.getAllArtifacts(); - expect(artifacts.length).toBe(7); + expect(artifacts.length).toBe(10); expect(getArtifactIds(artifacts)).toStrictEqual(SUPPORTED_ARTIFACT_NAMES); expect(artifacts.every(isCompressed)).toBe(true); @@ -412,6 +444,9 @@ describe('ManifestManager', () => { 'v1' ), }); + expect(await uncompressArtifact(artifacts[7])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[8])).toStrictEqual({ entries: [] }); + expect(await uncompressArtifact(artifacts[9])).toStrictEqual({ entries: [] }); for (const artifact of artifacts.slice(0, 5)) { expect(manifest.isDefaultArtifact(artifact)).toBe(true); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts index fe4aba165d2bd..6c25b6152938f 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/artifacts/manifest_manager/manifest_manager.ts @@ -361,10 +361,7 @@ export class ManifestManager { const results = await Promise.all([ this.buildExceptionListArtifacts(), this.buildTrustedAppsArtifacts(), - // If Endpoint Event Filtering feature is ON, then add in the exceptions for them - ...(this.experimentalFeatures.eventFilteringEnabled - ? [this.buildEventFiltersArtifacts()] - : []), + this.buildEventFiltersArtifacts(), ]); const manifest = new Manifest({ diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx index 4474b9f288570..e43db6b86f8b9 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/index.test.tsx @@ -32,7 +32,6 @@ const mockDeps = { experimentalFeatures: { trustedAppsByPolicyEnabled: false, metricsEntitiesEnabled: false, - eventFilteringEnabled: false, hostIsolationEnabled: false, }, service: {} as EndpointAppContextService, diff --git a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts index d8bc9f6444f64..44348d1ad0d9c 100644 --- a/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts +++ b/x-pack/test/security_solution_endpoint/apps/endpoint/policy_details.ts @@ -248,6 +248,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top @@ -416,6 +452,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top @@ -582,6 +654,42 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { relative_url: '/api/fleet/artifacts/endpoint-trustlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', }, + 'endpoint-eventfilterlist-linux-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-linux-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-macos-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-macos-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, + 'endpoint-eventfilterlist-windows-v1': { + compression_algorithm: 'zlib', + decoded_sha256: + 'd801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + decoded_size: 14, + encoded_sha256: + 'f8e6afa1d5662f5b37f83337af774b5785b5b7f1daee08b7b00c2d6813874cda', + encoded_size: 22, + encryption_algorithm: 'none', + relative_url: + '/api/fleet/artifacts/endpoint-eventfilterlist-windows-v1/d801aa1fb7ddcc330a5e3173372ea6af4a3d08ec58074478e85aa5603e926658', + }, }, // The manifest version could have changed when the Policy was updated because the // policy details page ensures that a save action applies the udpated policy on top From 73b6048ba1076f53b826214ac9736bf7e2f8d5b4 Mon Sep 17 00:00:00 2001 From: Thomas Neirynck Date: Tue, 25 May 2021 09:51:57 -0400 Subject: [PATCH 17/22] [Maps][Vega] Isolate mapbox-gl library into bazel package (#99931) --- package.json | 1 + packages/BUILD.bazel | 1 + packages/kbn-mapbox-gl/BUILD.bazel | 84 +++++++++++++++++++ packages/kbn-mapbox-gl/README.md | 3 + packages/kbn-mapbox-gl/package.json | 8 ++ packages/kbn-mapbox-gl/src/index.ts | 20 +++++ packages/kbn-mapbox-gl/src/typings.ts | 10 +++ packages/kbn-mapbox-gl/tsconfig.json | 16 ++++ .../vega_map_view/vega_map_view.scss | 2 - .../vega_view/vega_map_view/view.test.ts | 49 +++++------ .../public/vega_view/vega_map_view/view.ts | 13 +-- .../map_container/map_container.tsx | 1 - .../connected_components/mb_map/mb_map.tsx | 15 ++-- yarn.lock | 4 + 14 files changed, 180 insertions(+), 47 deletions(-) create mode 100644 packages/kbn-mapbox-gl/BUILD.bazel create mode 100644 packages/kbn-mapbox-gl/README.md create mode 100644 packages/kbn-mapbox-gl/package.json create mode 100644 packages/kbn-mapbox-gl/src/index.ts create mode 100644 packages/kbn-mapbox-gl/src/typings.ts create mode 100644 packages/kbn-mapbox-gl/tsconfig.json diff --git a/package.json b/package.json index 5737bce303e09..73f3e5585faf7 100644 --- a/package.json +++ b/package.json @@ -130,6 +130,7 @@ "@kbn/config": "link:bazel-bin/packages/kbn-config/npm_module", "@kbn/config-schema": "link:bazel-bin/packages/kbn-config-schema/npm_module", "@kbn/crypto": "link:bazel-bin/packages/kbn-crypto/npm_module", + "@kbn/mapbox-gl": "link:bazel-bin/packages/kbn-mapbox-gl/npm_module", "@kbn/i18n": "link:bazel-bin/packages/kbn-i18n/npm_module", "@kbn/interpreter": "link:packages/kbn-interpreter", "@kbn/io-ts-utils": "link:packages/kbn-io-ts-utils", diff --git a/packages/BUILD.bazel b/packages/BUILD.bazel index ec8252cb6144d..43528e0ae4162 100644 --- a/packages/BUILD.bazel +++ b/packages/BUILD.bazel @@ -24,6 +24,7 @@ filegroup( "//packages/kbn-i18n:build", "//packages/kbn-legacy-logging:build", "//packages/kbn-logging:build", + "//packages/kbn-mapbox-gl:build", "//packages/kbn-plugin-generator:build", "//packages/kbn-securitysolution-list-constants:build", "//packages/kbn-securitysolution-io-ts-types:build", diff --git a/packages/kbn-mapbox-gl/BUILD.bazel b/packages/kbn-mapbox-gl/BUILD.bazel new file mode 100644 index 0000000000000..7d7186068832e --- /dev/null +++ b/packages/kbn-mapbox-gl/BUILD.bazel @@ -0,0 +1,84 @@ + +load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project") +load("@build_bazel_rules_nodejs//:index.bzl", "js_library", "pkg_npm") + +PKG_BASE_NAME = "kbn-mapbox-gl" +PKG_REQUIRE_NAME = "@kbn/mapbox-gl" + +SOURCE_FILES = glob( + [ + "src/**/*.ts", + ], + exclude = [ + "**/*.test.*", + ], +) + +SRCS = SOURCE_FILES + +filegroup( + name = "srcs", + srcs = SRCS, +) + +NPM_MODULE_EXTRA_FILES = [ + "package.json", + "README.md" +] + +SRC_DEPS = [ + "@npm//@mapbox/mapbox-gl-rtl-text", + "@npm//file-loader", + "@npm//mapbox-gl", +] + +TYPES_DEPS = [ + "@npm//@types/mapbox-gl", +] + +DEPS = SRC_DEPS + TYPES_DEPS + +ts_config( + name = "tsconfig", + src = "tsconfig.json", + deps = [ + "//:tsconfig.base.json", + ], +) + +ts_project( + name = "tsc", + args = ['--pretty'], + srcs = SRCS, + deps = DEPS, + declaration = True, + declaration_map = True, + incremental = True, + out_dir = "target", + source_map = True, + root_dir = "src", + tsconfig = ":tsconfig", +) + +js_library( + name = PKG_BASE_NAME, + srcs = NPM_MODULE_EXTRA_FILES, + deps = DEPS + [":tsc"], + package_name = PKG_REQUIRE_NAME, + visibility = ["//visibility:public"], +) + +pkg_npm( + name = "npm_module", + deps = [ + ":%s" % PKG_BASE_NAME, + ] +) + +filegroup( + name = "build", + srcs = [ + ":npm_module", + ], + visibility = ["//visibility:public"], +) diff --git a/packages/kbn-mapbox-gl/README.md b/packages/kbn-mapbox-gl/README.md new file mode 100644 index 0000000000000..c1fdea491feaa --- /dev/null +++ b/packages/kbn-mapbox-gl/README.md @@ -0,0 +1,3 @@ +# @kbn/mapbox-gl + +Default instantiation for mapbox-gl. \ No newline at end of file diff --git a/packages/kbn-mapbox-gl/package.json b/packages/kbn-mapbox-gl/package.json new file mode 100644 index 0000000000000..9de88dac54a5a --- /dev/null +++ b/packages/kbn-mapbox-gl/package.json @@ -0,0 +1,8 @@ +{ + "name": "@kbn/mapbox-gl", + "version": "1.0.0", + "private": true, + "license": "SSPL-1.0 OR Elastic License 2.0", + "main": "./target/index.js", + "types": "./target/index.d.ts" +} diff --git a/packages/kbn-mapbox-gl/src/index.ts b/packages/kbn-mapbox-gl/src/index.ts new file mode 100644 index 0000000000000..117b874a28ffb --- /dev/null +++ b/packages/kbn-mapbox-gl/src/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 './typings'; +import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; +// @ts-expect-error +import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; +// @ts-expect-error +import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; +import 'mapbox-gl/dist/mapbox-gl.css'; + +mapboxgl.workerUrl = mbWorkerUrl; +mapboxgl.setRTLTextPlugin(mbRtlPlugin); + +export { mapboxgl }; diff --git a/packages/kbn-mapbox-gl/src/typings.ts b/packages/kbn-mapbox-gl/src/typings.ts new file mode 100644 index 0000000000000..0cc6908aca428 --- /dev/null +++ b/packages/kbn-mapbox-gl/src/typings.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// Mapbox-gl doesn't declare this type. +declare module 'mapbox-gl/dist/mapbox-gl-csp'; diff --git a/packages/kbn-mapbox-gl/tsconfig.json b/packages/kbn-mapbox-gl/tsconfig.json new file mode 100644 index 0000000000000..cf1cca0f5a0fd --- /dev/null +++ b/packages/kbn-mapbox-gl/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "incremental": true, + "outDir": "./target", + "declaration": true, + "declarationMap": true, + "rootDir": "src", + "sourceMap": true, + "sourceRoot": "../../../../packages/kbn-mapbox-gl/src", + "types": [] + }, + "include": [ + "src/**/*", + ] +} diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss index 33e63e7ef317c..3e3ef71faf0d7 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/vega_map_view.scss @@ -1,5 +1,3 @@ -@import '~mapbox-gl/dist/mapbox-gl.css'; - .vgaVis { .mapboxgl-canvas-container { cursor: auto; diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts index 4fd19aa45e69e..ee3bf305e9427 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.test.ts @@ -29,30 +29,31 @@ import { } from '../../services'; import { initVegaLayer, initTmsRasterLayer } from './layers'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; - -jest.mock('mapbox-gl/dist/mapbox-gl-csp', () => ({ - setRTLTextPlugin: jest.fn(), - Map: jest.fn().mockImplementation(() => ({ - getLayer: () => '', - removeLayer: jest.fn(), - once: (eventName: string, handler: Function) => handler(), - remove: () => jest.fn(), - getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), - getCenter: () => ({ lat: 20, lng: 20 }), - getZoom: () => 3, - addControl: jest.fn(), - addLayer: jest.fn(), - dragRotate: { - disable: jest.fn(), - }, - touchZoomRotate: { - disableRotation: jest.fn(), - }, - })), - MapboxOptions: jest.fn(), - NavigationControl: jest.fn(), +import { mapboxgl } from '@kbn/mapbox-gl'; + +jest.mock('@kbn/mapbox-gl', () => ({ + mapboxgl: { + setRTLTextPlugin: jest.fn(), + Map: jest.fn().mockImplementation(() => ({ + getLayer: () => '', + removeLayer: jest.fn(), + once: (eventName: string, handler: Function) => handler(), + remove: () => jest.fn(), + getCanvas: () => ({ clientWidth: 512, clientHeight: 512 }), + getCenter: () => ({ lat: 20, lng: 20 }), + getZoom: () => 3, + addControl: jest.fn(), + addLayer: jest.fn(), + dragRotate: { + disable: jest.fn(), + }, + touchZoomRotate: { + disableRotation: jest.fn(), + }, + })), + MapboxOptions: jest.fn(), + NavigationControl: jest.fn(), + }, })); jest.mock('./layers', () => ({ diff --git a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts index e899057819a19..835ac36ceee47 100644 --- a/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts +++ b/src/plugins/vis_type_vega/public/vega_view/vega_map_view/view.ts @@ -10,8 +10,9 @@ import { i18n } from '@kbn/i18n'; import type { Map, Style, MapboxOptions } from 'mapbox-gl'; import { View, parse } from 'vega'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; + +import { mapboxgl } from '@kbn/mapbox-gl'; + import { initTmsRasterLayer, initVegaLayer } from './layers'; import { VegaBaseView } from '../vega_base_view'; import { getMapServiceSettings } from '../../services'; @@ -27,14 +28,6 @@ import { import { validateZoomSettings, injectMapPropsIntoSpec } from './utils'; import './vega_map_view.scss'; -// @ts-expect-error -import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; -// @ts-expect-error -import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; - -mapboxgl.workerUrl = mbWorkerUrl; -mapboxgl.setRTLTextPlugin(mbRtlPlugin); - async function updateVegaView(mapBoxInstance: Map, vegaView: View) { const mapCanvas = mapBoxInstance.getCanvas(); const { lat, lng } = mapBoxInstance.getCenter(); diff --git a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx index e0cfe978bf45c..851fd583b4251 100644 --- a/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx +++ b/x-pack/plugins/maps/public/connected_components/map_container/map_container.tsx @@ -30,7 +30,6 @@ import { registerLayerWizards } from '../../classes/layers/load_layer_wizards'; import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; import { MapRefreshConfig } from '../../../common/descriptor_types'; -import 'mapbox-gl/dist/mapbox-gl.css'; const RENDER_COMPLETE_EVENT = 'renderComplete'; diff --git a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx index ac3e72545033f..355e49564620d 100644 --- a/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx +++ b/x-pack/plugins/maps/public/connected_components/mb_map/mb_map.tsx @@ -7,9 +7,8 @@ import _ from 'lodash'; import React, { Component } from 'react'; -import { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; -// @ts-expect-error -import mapboxgl from 'mapbox-gl/dist/mapbox-gl-csp'; +import type { Map as MapboxMap, MapboxOptions, MapMouseEvent } from 'mapbox-gl'; + // @ts-expect-error import { spritesheet } from '@elastic/maki'; import sprites1 from '@elastic/maki/dist/sprite@1.png'; @@ -17,6 +16,9 @@ import sprites2 from '@elastic/maki/dist/sprite@2.png'; import { Adapters } from 'src/plugins/inspector/public'; import { Filter } from 'src/plugins/data/public'; import { ActionExecutionContext, Action } from 'src/plugins/ui_actions/public'; + +import { mapboxgl } from '@kbn/mapbox-gl'; + import { DrawFilterControl } from './draw_control'; import { ScaleControl } from './scale_control'; import { TooltipControl } from './tooltip_control'; @@ -45,13 +47,6 @@ import { GeoFieldWithIndex } from '../../components/geo_field_with_index'; import { RenderToolTipContent } from '../../classes/tooltips/tooltip_property'; import { MapExtentState } from '../../actions'; import { TileStatusTracker } from './tile_status_tracker'; -// @ts-expect-error -import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'; -// @ts-expect-error -import mbWorkerUrl from '!!file-loader!mapbox-gl/dist/mapbox-gl-csp-worker'; - -mapboxgl.workerUrl = mbWorkerUrl; -mapboxgl.setRTLTextPlugin(mbRtlPlugin); export interface Props { isMapReady: boolean; diff --git a/yarn.lock b/yarn.lock index f1f421e2a766f..9967cedea9fde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2678,6 +2678,10 @@ version "0.0.0" uid "" +"@kbn/mapbox-gl@link:bazel-bin/packages/kbn-mapbox-gl/npm_module": + version "0.0.0" + uid "" + "@kbn/monaco@link:packages/kbn-monaco": version "0.0.0" uid "" From e2d47f72694014ff6063fc0c7858bed6ed07fb9c Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 25 May 2021 07:45:07 -0700 Subject: [PATCH 18/22] [DOCS] Remove redundant maps attribute (#100426) --- docs/maps/index.asciidoc | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/maps/index.asciidoc b/docs/maps/index.asciidoc index e4150fc280096..45d24bfb5a7e4 100644 --- a/docs/maps/index.asciidoc +++ b/docs/maps/index.asciidoc @@ -1,6 +1,5 @@ :ems-docker-repo: docker.elastic.co/elastic-maps-service/elastic-maps-server-ubi8 :ems-docker-image: {ems-docker-repo}:{version} -:hosted-ems: Elastic Maps Server [role="xpack"] [[maps]] From 662fe7475738d90120342503e5a56016c2a5ee95 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 25 May 2021 17:02:48 +0200 Subject: [PATCH 19/22] [Reporting] ILM policy for managing reporting indices (#100130) * wip; added logic for creating ILM policy at start up * added log when ilm policy is not created * added test for start function * updated ilm policy to not delete data * actually update jest snapshots and remove unused import * updated the ilm policy, removed the min_age for the hot phase * update jest snapshot * removed TODO comment * debug log -> info log Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../server/lib/store/report_ilm_policy.ts | 18 +++++ .../reporting/server/lib/store/store.test.ts | 39 +++++++++++ .../reporting/server/lib/store/store.ts | 66 +++++++++++++++---- x-pack/plugins/reporting/server/plugin.ts | 3 + 4 files changed, 114 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts diff --git a/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts b/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts new file mode 100644 index 0000000000000..f4cd69a0331d7 --- /dev/null +++ b/x-pack/plugins/reporting/server/lib/store/report_ilm_policy.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PutLifecycleRequest } from '@elastic/elasticsearch/api/types'; + +export const reportingIlmPolicy: PutLifecycleRequest['body'] = { + policy: { + phases: { + hot: { + actions: {}, + }, + }, + }, +}; diff --git a/x-pack/plugins/reporting/server/lib/store/store.test.ts b/x-pack/plugins/reporting/server/lib/store/store.test.ts index 7f96433fcc6ce..fa35240dfc8fb 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.test.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.test.ts @@ -7,6 +7,7 @@ import type { DeeplyMockedKeys } from '@kbn/utility-types/jest'; import { ElasticsearchClient } from 'src/core/server'; +import { elasticsearchServiceMock } from 'src/core/server/mocks'; import { ReportingCore } from '../../'; import { createMockConfigSchema, @@ -16,6 +17,8 @@ import { import { Report, ReportDocument } from './report'; import { ReportingStore } from './store'; +const { createApiResponse } = elasticsearchServiceMock; + describe('ReportingStore', () => { const mockLogger = createMockLevelLogger(); let mockCore: ReportingCore; @@ -403,4 +406,40 @@ describe('ReportingStore', () => { ] `); }); + + describe('start', () => { + it('creates an ILM policy for managing reporting indices if there is not already one', async () => { + mockEsClient.ilm.getLifecycle.mockRejectedValueOnce(createApiResponse({ statusCode: 404 })); + mockEsClient.ilm.putLifecycle.mockResolvedValueOnce(createApiResponse()); + + const store = new ReportingStore(mockCore, mockLogger); + await store.start(); + + expect(mockEsClient.ilm.getLifecycle).toHaveBeenCalledWith({ policy: 'kibana-reporting' }); + expect(mockEsClient.ilm.putLifecycle.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "policy": Object { + "phases": Object { + "hot": Object { + "actions": Object {}, + }, + }, + }, + }, + "policy": "kibana-reporting", + } + `); + }); + + it('does not create an ILM policy for managing reporting indices if one already exists', async () => { + mockEsClient.ilm.getLifecycle.mockResolvedValueOnce(createApiResponse()); + + const store = new ReportingStore(mockCore, mockLogger); + await store.start(); + + expect(mockEsClient.ilm.getLifecycle).toHaveBeenCalledWith({ policy: 'kibana-reporting' }); + expect(mockEsClient.ilm.putLifecycle).not.toHaveBeenCalled(); + }); + }); }); diff --git a/x-pack/plugins/reporting/server/lib/store/store.ts b/x-pack/plugins/reporting/server/lib/store/store.ts index fc7bd9c23d769..9fb203fd5627a 100644 --- a/x-pack/plugins/reporting/server/lib/store/store.ts +++ b/x-pack/plugins/reporting/server/lib/store/store.ts @@ -14,6 +14,7 @@ import { ReportTaskParams } from '../tasks'; import { indexTimestamp } from './index_timestamp'; import { mapping } from './mapping'; import { Report, ReportDocument, ReportSource } from './report'; +import { reportingIlmPolicy } from './report_ilm_policy'; /* * When searching for long-pending reports, we get a subset of fields @@ -71,19 +72,22 @@ export class ReportingStore { return exists; } - const indexSettings = { - number_of_shards: 1, - auto_expand_replicas: '0-1', - }; - const body = { - settings: indexSettings, - mappings: { - properties: mapping, - }, - }; - try { - await client.indices.create({ index: indexName, body }); + await client.indices.create({ + index: indexName, + body: { + settings: { + number_of_shards: 1, + auto_expand_replicas: '0-1', + lifecycle: { + name: this.ilmPolicyName, + }, + }, + mappings: { + properties: mapping, + }, + }, + }); return true; } catch (error) { @@ -130,6 +134,44 @@ export class ReportingStore { return client.indices.refresh({ index }); } + private readonly ilmPolicyName = 'kibana-reporting'; + + private async doesIlmPolicyExist(): Promise { + const client = await this.getClient(); + try { + await client.ilm.getLifecycle({ policy: this.ilmPolicyName }); + return true; + } catch (e) { + if (e.statusCode === 404) { + return false; + } + throw e; + } + } + + /** + * Function to be called during plugin start phase. This ensures the environment is correctly + * configured for storage of reports. + */ + public async start() { + const client = await this.getClient(); + try { + if (await this.doesIlmPolicyExist()) { + this.logger.debug(`Found ILM policy ${this.ilmPolicyName}; skipping creation.`); + return; + } + this.logger.info(`Creating ILM policy for managing reporting indices: ${this.ilmPolicyName}`); + await client.ilm.putLifecycle({ + policy: this.ilmPolicyName, + body: reportingIlmPolicy, + }); + } catch (e) { + this.logger.error('Error in start phase'); + this.logger.error(e.body.error); + throw e; + } + } + public async addReport(report: Report): Promise { let index = report._index; if (!index) { diff --git a/x-pack/plugins/reporting/server/plugin.ts b/x-pack/plugins/reporting/server/plugin.ts index fc52e10dd0cf9..efe1d9450bef3 100644 --- a/x-pack/plugins/reporting/server/plugin.ts +++ b/x-pack/plugins/reporting/server/plugin.ts @@ -107,6 +107,9 @@ export class ReportingPlugin logger: this.logger, }); + // Note: this must be called after ReportingCore.pluginStart + await store.start(); + this.logger.debug('Start complete'); })().catch((e) => { this.logger.error(`Error in Reporting start, reporting may not function properly`); From a818b2ad9d188eae1d510157605e916fddfd4bfd Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Tue, 25 May 2021 17:03:44 +0200 Subject: [PATCH 20/22] [Reporting] ILM policy for managing reporting indices (#100130) * wip; added logic for creating ILM policy at start up * added log when ilm policy is not created * added test for start function * updated ilm policy to not delete data * actually update jest snapshots and remove unused import * updated the ilm policy, removed the min_age for the hot phase * update jest snapshot * removed TODO comment * debug log -> info log Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> From d8c259478947d647f2781296f2ef6c3ff1441d54 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Tue, 25 May 2021 18:56:29 +0300 Subject: [PATCH 21/22] [XY] [Lens] Adds opacity slider (#100453) * [XY] Add opacity slider and dots size slider * [Lens] Adds fill opacity slider * Make the new sliders to appear fullwidth * Change property name and fix unit tests * Add a comment * useDebouncedValue hook Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/__snapshots__/to_ast.test.ts.snap | 2 +- .../vis_type_xy/public/config/get_config.ts | 2 + .../__snapshots__/index.test.tsx.snap | 2 + .../__snapshots__/line_options.test.tsx.snap | 9 --- .../__snapshots__/point_options.test.tsx.snap | 46 ++++++++++++++ .../metrics_axes/chart_options.test.tsx | 14 +++++ .../options/metrics_axes/chart_options.tsx | 4 ++ .../options/metrics_axes/line_options.tsx | 11 ---- .../components/options/metrics_axes/mocks.ts | 1 + .../metrics_axes/point_options.test.tsx | 44 +++++++++++++ .../options/metrics_axes/point_options.tsx | 63 +++++++++++++++++++ .../components/options/metrics_axes/utils.ts | 1 + .../point_series/elastic_charts_options.tsx | 37 +++++++++-- .../point_series/point_series.mocks.ts | 2 + .../expression_functions/series_param.ts | 8 +++ .../public/expression_functions/xy_vis_fn.ts | 7 +++ .../public/sample_vis.test.mocks.ts | 3 + src/plugins/vis_type_xy/public/to_ast.ts | 2 + .../vis_type_xy/public/types/config.ts | 1 + src/plugins/vis_type_xy/public/types/param.ts | 3 + .../public/utils/render_all_series.test.tsx | 1 + .../public/utils/render_all_series.tsx | 14 ++++- .../vis_type_xy/public/vis_types/area.ts | 1 + .../vis_type_xy/public/vis_types/histogram.ts | 1 + .../public/vis_types/horizontal_bar.ts | 1 + .../vis_type_xy/public/vis_types/line.ts | 1 + .../__snapshots__/to_expression.test.ts.snap | 3 + .../public/xy_visualization/expression.tsx | 7 +++ .../public/xy_visualization/to_expression.ts | 1 + .../lens/public/xy_visualization/types.ts | 2 + .../fill_opacity_option.test.tsx | 35 +++++++++++ .../fill_opacity_option.tsx | 59 +++++++++++++++++ .../missing_values_option.tsx | 10 ++- .../visual_options_popover.test.tsx | 51 +++++++++++++++ .../visual_options_popover.tsx | 16 +++++ .../public/xy_visualization/xy_suggestions.ts | 1 + 36 files changed, 437 insertions(+), 29 deletions(-) create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx create mode 100644 src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx create mode 100644 x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx create mode 100644 x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap index 3ca2834a54fca..8b720568c4d2c 100644 --- a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap @@ -8,7 +8,7 @@ Object { "area", ], "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"circlesRadius\\":5,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_type_xy/public/config/get_config.ts b/src/plugins/vis_type_xy/public/config/get_config.ts index 8ebac1b71940a..ce01572060a40 100644 --- a/src/plugins/vis_type_xy/public/config/get_config.ts +++ b/src/plugins/vis_type_xy/public/config/get_config.ts @@ -39,6 +39,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { fittingFunction, detailedTooltip, isVislibVis, + fillOpacity, } = params; const aspects = getAspects(table.columns, params.dimensions); const xAxis = getAxis( @@ -63,6 +64,7 @@ export function getConfig(table: Datatable, params: VisParams): VisConfig { // NOTE: downscale ratio to match current vislib implementation markSizeRatio: radiusRatio * 0.6, fittingFunction, + fillOpacity, detailedTooltip, orderBucketsBySum, isTimeChart, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap index 40e53d88f99cf..05e2532073eaf 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/index.test.tsx.snap @@ -7,6 +7,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", @@ -79,6 +80,7 @@ exports[`MetricsAxisOptions component should init with the default set of props seriesParams={ Array [ Object { + "circlesRadius": 3, "data": Object { "id": "1", "label": "Count", diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap index 7b45423f5f861..8764db1dea06a 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/line_options.test.tsx.snap @@ -54,14 +54,5 @@ exports[`LineOptions component should init with the default set of props 1`] = ` /> - - `; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap new file mode 100644 index 0000000000000..fcd6f8d00a138 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/__snapshots__/point_options.test.tsx.snap @@ -0,0 +1,46 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PointOptions component should init with the default set of props 1`] = ` + + + + + + + + +`; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx index def24d51f49f3..1d5c8be2b9246 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.test.tsx @@ -12,6 +12,7 @@ import { shallow, mount } from 'enzyme'; import { ChartOptions, ChartOptionsParams } from './chart_options'; import { SeriesParam, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { valueAxis, seriesParam } from './mocks'; import { ChartType } from '../../../../../common'; @@ -41,6 +42,12 @@ describe('ChartOptions component', () => { expect(comp).toMatchSnapshot(); }); + it('should hide the PointOptions when type is bar', () => { + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeFalsy(); + }); + it('should show LineOptions when type is line', () => { chart.type = ChartType.Line; const comp = shallow(); @@ -48,6 +55,13 @@ describe('ChartOptions component', () => { expect(comp.find(LineOptions).exists()).toBeTruthy(); }); + it('should show PointOptions when type is area', () => { + chart.type = ChartType.Area; + const comp = shallow(); + + expect(comp.find(PointOptions).exists()).toBeTruthy(); + }); + it('should show line mode when type is area', () => { chart.type = ChartType.Area; const comp = shallow(); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx index 23452a87aae60..34ee33781f269 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/chart_options.tsx @@ -15,6 +15,7 @@ import { SelectOption } from '../../../../../../vis_default_editor/public'; import { SeriesParam, ValueAxis, ChartMode, AxisMode } from '../../../../types'; import { LineOptions } from './line_options'; +import { PointOptions } from './point_options'; import { SetParamByIndex, ChangeValueAxis } from '.'; import { ChartType } from '../../../../../common'; import { getConfigCollections } from '../../../collections'; @@ -143,6 +144,9 @@ function ChartOptions({ )} {chart.type === ChartType.Line && } + {(chart.type === ChartType.Area || chart.type === ChartType.Line) && ( + + )} ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx index 140f190c77181..75dfe8627d73e 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/line_options.tsx @@ -78,17 +78,6 @@ function LineOptions({ chart, setChart }: LineOptionsParams) { /> - - - - ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts index 7451f6dea9039..eed224cf2a514 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/mocks.ts @@ -75,6 +75,7 @@ const seriesParam: SeriesParam = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: defaultValueAxisId, }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx new file mode 100644 index 0000000000000..68ac1832d28a8 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.test.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; +import { shallow, mount } from 'enzyme'; +import { findTestSubject } from '@elastic/eui/lib/test'; + +import { SeriesParam } from '../../../../types'; +import { PointOptions, PointOptionsParams } from './point_options'; +import { seriesParam } from './mocks'; + +describe('PointOptions component', () => { + let setChart: jest.Mock; + let defaultProps: PointOptionsParams; + let chart: SeriesParam; + + beforeEach(() => { + setChart = jest.fn(); + chart = { ...seriesParam }; + + defaultProps = { + chart, + setChart, + }; + }); + + it('should init with the default set of props', () => { + const comp = shallow(); + + expect(comp).toMatchSnapshot(); + }); + + it('should disable the dots size range if the show dots switch is off', () => { + chart.showCircles = false; + const comp = mount(); + const range = findTestSubject(comp, 'circlesRadius'); + expect(range.at(1).props().disabled).toBeTruthy(); + }); +}); diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx new file mode 100644 index 0000000000000..d35a5a2374ca3 --- /dev/null +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/point_options.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import React from 'react'; + +import { i18n } from '@kbn/i18n'; +import { EuiRange, EuiFormRow, EuiSpacer } from '@elastic/eui'; + +import { SwitchOption } from '../../../../../../vis_default_editor/public'; + +import { SeriesParam } from '../../../../types'; +import { SetChart } from './chart_options'; + +export interface PointOptionsParams { + chart: SeriesParam; + setChart: SetChart; +} + +function PointOptions({ chart, setChart }: PointOptionsParams) { + return ( + <> + + + + + { + setChart('circlesRadius', Number(e.currentTarget.value)); + }} + /> + + + ); +} + +export { PointOptions }; diff --git a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts index d0d0c08060acf..a8d53e45bc988 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/metrics_axes/utils.ts @@ -26,6 +26,7 @@ export const makeSerie = ( type: ChartType.Line, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, lineWidth: 2, valueAxis: defaultValueAxis, diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx index 5398980e268d4..271c5445a9580 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/elastic_charts_options.tsx @@ -10,7 +10,7 @@ import React, { useState, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { METRIC_TYPE } from '@kbn/analytics'; - +import { EuiFormRow, EuiRange } from '@elastic/eui'; import { SelectOption, SwitchOption, @@ -31,10 +31,14 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps const [palettesRegistry, setPalettesRegistry] = useState(null); const { stateParams, setValue, aggs } = props; - const hasLineChart = stateParams.seriesParams.some( + const isLineChart = stateParams.seriesParams.some( + ({ type, data: { id: paramId } }) => + type === ChartType.Line && aggs.aggs.find(({ id }) => id === paramId)?.enabled + ); + + const isAreaChart = stateParams.seriesParams.some( ({ type, data: { id: paramId } }) => - (type === ChartType.Line || type === ChartType.Area) && - aggs.aggs.find(({ id }) => id === paramId)?.enabled + type === ChartType.Area && aggs.aggs.find(({ id }) => id === paramId)?.enabled ); useEffect(() => { @@ -66,7 +70,7 @@ export function ElasticChartsOptions(props: ValidationVisOptionsProps }} /> - {hasLineChart && ( + {(isLineChart || isAreaChart) && ( }} /> )} + {isAreaChart && ( + + { + setValue('fillOpacity', Number(e.currentTarget.value)); + }} + /> + + )} ); } diff --git a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts index eb8d4d1c440d7..f23d9e4ada336 100644 --- a/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts +++ b/src/plugins/vis_type_xy/public/editor/components/options/point_series/point_series.mocks.ts @@ -410,6 +410,7 @@ export const getVis = (bucketType: string) => { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -838,6 +839,7 @@ export const getStateParams = (type: string, thresholdPanelOn: boolean) => { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 3, interpolate: 'cardinal', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts index 402187cea6586..3fd62e33e257f 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts @@ -29,6 +29,7 @@ export type ExpressionValueSeriesParam = ExpressionValueBoxed< mode: SeriesParam['mode']; show: boolean; showCircles: boolean; + circlesRadius: number; seriesParamType: SeriesParam['type']; valueAxis: string; } @@ -98,6 +99,12 @@ export const seriesParam = (): ExpressionFunctionDefinition< defaultMessage: 'Show circles', }), }, + circlesRadius: { + types: ['number'], + help: i18n.translate('visTypeXy.function.seriesParam.circlesRadius.help', { + defaultMessage: 'Defines the circles size (radius)', + }), + }, type: { types: ['string'], help: i18n.translate('visTypeXy.function.seriesParam.type.help', { @@ -121,6 +128,7 @@ export const seriesParam = (): ExpressionFunctionDefinition< mode: args.mode, show: args.show, showCircles: args.showCircles, + circlesRadius: args.circlesRadius, seriesParamType: args.type, valueAxis: args.valueAxis, }; diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts index b8b8c0e8b8cca..29403a12fdce6 100644 --- a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts +++ b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts @@ -161,6 +161,12 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ defaultMessage: 'Defines the chart palette name', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('visTypeXy.function.args.fillOpacity.help', { + defaultMessage: 'Defines the area chart fill opacity', + }), + }, xDimension: { types: ['xy_dimension', 'null'], help: i18n.translate('visTypeXy.function.args.xDimension.help', { @@ -242,6 +248,7 @@ export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ type: 'palette', name: args.palette, }, + fillOpacity: args.fillOpacity, fittingFunction: args.fittingFunction, dimensions: { x: args.xDimension, diff --git a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts index e15f9c4207702..39370d941b52a 100644 --- a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts @@ -1397,6 +1397,7 @@ export const sampleAreaVis = { drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, @@ -1417,6 +1418,7 @@ export const sampleAreaVis = { palette: { name: 'default', }, + fillOpacity: 0.5, }, }, editorConfig: { @@ -1562,6 +1564,7 @@ export const sampleAreaVis = { }, drawLinesBetweenPoints: true, showCircles: true, + circlesRadius: 5, interpolate: 'linear', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts index c0a0ee566a445..f473cd77c2d2b 100644 --- a/src/plugins/vis_type_xy/public/to_ast.ts +++ b/src/plugins/vis_type_xy/public/to_ast.ts @@ -98,6 +98,7 @@ const prepareSeriesParam = (data: SeriesParam) => { mode: data.mode, show: data.show, showCircles: data.showCircles, + circlesRadius: data.circlesRadius, type: data.type, valueAxis: data.valueAxis, }); @@ -207,6 +208,7 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params fittingFunction: vis.params.fittingFunction, times: vis.params.times.map(prepareTimeMarker), palette: vis.params.palette.name, + fillOpacity: vis.params.fillOpacity, xDimension: dimensions.x ? prepareXYDimension(dimensions.x) : null, yDimension: dimensions.y.map(prepareXYDimension), zDimension: dimensions.z?.map(prepareXYDimension), diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_type_xy/public/types/config.ts index f025a36a82410..e52b47366bc85 100644 --- a/src/plugins/vis_type_xy/public/types/config.ts +++ b/src/plugins/vis_type_xy/public/types/config.ts @@ -116,6 +116,7 @@ export interface VisConfig { showValueLabel: boolean; enableHistogramMode: boolean; fittingFunction?: Exclude; + fillOpacity?: number; detailedTooltip?: boolean; isVislibVis?: boolean; } diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts index f90899620126a..7a2ff7e240264 100644 --- a/src/plugins/vis_type_xy/public/types/param.ts +++ b/src/plugins/vis_type_xy/public/types/param.ts @@ -78,6 +78,7 @@ export interface SeriesParam { mode: ChartMode; show: boolean; showCircles: boolean; + circlesRadius: number; type: ChartType; valueAxis: string; } @@ -155,6 +156,7 @@ export interface VisParams { */ detailedTooltip?: boolean; palette: PaletteOutput; + fillOpacity?: number; fittingFunction?: Exclude; } @@ -186,6 +188,7 @@ export interface XYVisConfig { */ detailedTooltip?: boolean; fittingFunction?: Exclude; + fillOpacity?: number; xDimension: ExpressionValueXYDimension | null; yDimension: ExpressionValueXYDimension[]; zDimension?: ExpressionValueXYDimension[]; diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx index 628d3620090ca..23dabef662d55 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.test.tsx @@ -31,6 +31,7 @@ const defaultSeriesParams = [ mode: 'stacked', show: true, showCircles: true, + circlesRadius: 3, type: 'area', valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx index 3bce5ddc2e85e..e915e6d4966c5 100644 --- a/src/plugins/vis_type_xy/public/utils/render_all_series.tsx +++ b/src/plugins/vis_type_xy/public/utils/render_all_series.tsx @@ -51,7 +51,15 @@ const getCurveType = (type?: 'linear' | 'cardinal' | 'step-after'): CurveType => * @param getSeriesColor */ export const renderAllSeries = ( - { aspects, yAxes, xAxis, showValueLabel, enableHistogramMode, fittingFunction }: VisConfig, + { + aspects, + yAxes, + xAxis, + showValueLabel, + enableHistogramMode, + fittingFunction, + fillOpacity, + }: VisConfig, seriesParams: SeriesParam[], data: DatatableRow[], getSeriesName: (series: XYChartSeriesIdentifier) => SeriesName, @@ -67,6 +75,7 @@ export const renderAllSeries = ( data: { id: paramId }, lineWidth: strokeWidth, showCircles, + circlesRadius, drawLinesBetweenPoints, mode, interpolate, @@ -158,7 +167,7 @@ export const renderAllSeries = ( stackMode={stackMode} areaSeriesStyle={{ area: { - ...(type === ChartType.Line && { opacity: 0 }), + ...(type === ChartType.Line ? { opacity: 0 } : { opacity: fillOpacity }), }, line: { strokeWidth, @@ -167,6 +176,7 @@ export const renderAllSeries = ( point: { visible: showCircles, fill: markSizeAccessor ? ColorVariant.Series : undefined, + radius: circlesRadius, }, }} /> diff --git a/src/plugins/vis_type_xy/public/vis_types/area.ts b/src/plugins/vis_type_xy/public/vis_types/area.ts index f22f8df1752d6..912b3d8d48e95 100644 --- a/src/plugins/vis_type_xy/public/vis_types/area.ts +++ b/src/plugins/vis_type_xy/public/vis_types/area.ts @@ -98,6 +98,7 @@ export const getAreaVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, interpolate: InterpolationMode.Linear, valueAxis: 'ValueAxis-1', }, diff --git a/src/plugins/vis_type_xy/public/vis_types/histogram.ts b/src/plugins/vis_type_xy/public/vis_types/histogram.ts index 732833ffecc80..9af4cfd7b43a3 100644 --- a/src/plugins/vis_type_xy/public/vis_types/histogram.ts +++ b/src/plugins/vis_type_xy/public/vis_types/histogram.ts @@ -102,6 +102,7 @@ export const getHistogramVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], radiusRatio: 0, diff --git a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts index 791d93bb646b2..874e69b246a4d 100644 --- a/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts +++ b/src/plugins/vis_type_xy/public/vis_types/horizontal_bar.ts @@ -103,6 +103,7 @@ export const getHorizontalBarVisTypeDefinition = ( drawLinesBetweenPoints: true, lineWidth: 2, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/src/plugins/vis_type_xy/public/vis_types/line.ts b/src/plugins/vis_type_xy/public/vis_types/line.ts index 6316fe4458229..2e8944f44daab 100644 --- a/src/plugins/vis_type_xy/public/vis_types/line.ts +++ b/src/plugins/vis_type_xy/public/vis_types/line.ts @@ -100,6 +100,7 @@ export const getLineVisTypeDefinition = ( lineWidth: 2, interpolate: InterpolationMode.Linear, showCircles: true, + circlesRadius: 3, }, ], addTooltip: true, diff --git a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap index 339fb5a7ab68f..08b3393fafe48 100644 --- a/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap +++ b/x-pack/plugins/lens/public/xy_visualization/__snapshots__/to_expression.test.ts.snap @@ -33,6 +33,9 @@ Object { "description": Array [ "", ], + "fillOpacity": Array [ + 0.3, + ], "fittingFunction": Array [ "Carry", ], diff --git a/x-pack/plugins/lens/public/xy_visualization/expression.tsx b/x-pack/plugins/lens/public/xy_visualization/expression.tsx index 006727b05b905..e3b4565913ad8 100644 --- a/x-pack/plugins/lens/public/xy_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/expression.tsx @@ -196,6 +196,12 @@ export const xyChart: ExpressionFunctionDefinition< defaultMessage: 'Define how curve type is rendered for a line chart', }), }, + fillOpacity: { + types: ['number'], + help: i18n.translate('xpack.lens.xyChart.fillOpacity.help', { + defaultMessage: 'Define the area chart fill opacity', + }), + }, hideEndzones: { types: ['boolean'], default: false, @@ -812,6 +818,7 @@ export function XYChart({ visible: !xAccessor, radius: 5, }, + ...(args.fillOpacity && { area: { opacity: args.fillOpacity } }), }, lineSeriesStyle: { point: { diff --git a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts index dea6b1a7be0c5..269f10159892f 100644 --- a/x-pack/plugins/lens/public/xy_visualization/to_expression.ts +++ b/x-pack/plugins/lens/public/xy_visualization/to_expression.ts @@ -149,6 +149,7 @@ export const buildExpression = ( ], fittingFunction: [state.fittingFunction || 'None'], curveType: [state.curveType || 'LINEAR'], + fillOpacity: [state.fillOpacity || 0.3], yLeftExtent: [ { type: 'expression', diff --git a/x-pack/plugins/lens/public/xy_visualization/types.ts b/x-pack/plugins/lens/public/xy_visualization/types.ts index ea28b492477c1..531b034b53242 100644 --- a/x-pack/plugins/lens/public/xy_visualization/types.ts +++ b/x-pack/plugins/lens/public/xy_visualization/types.ts @@ -464,6 +464,7 @@ export interface XYArgs { tickLabelsVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_tickLabelsConfig' }; gridlinesVisibilitySettings?: AxesSettingsConfig & { type: 'lens_xy_gridlinesConfig' }; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } @@ -485,6 +486,7 @@ export interface XYState { tickLabelsVisibilitySettings?: AxesSettingsConfig; gridlinesVisibilitySettings?: AxesSettingsConfig; curveType?: XYCurveType; + fillOpacity?: number; hideEndzones?: boolean; } diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx new file mode 100644 index 0000000000000..3ba29e4f72c83 --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.test.tsx @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { mountWithIntl as mount, shallowWithIntl as shallow } from '@kbn/test/jest'; +import { EuiRange } from '@elastic/eui'; +import { FillOpacityOption } from './fill_opacity_option'; + +describe('Line curve option', () => { + it('should show currently selected opacity value', () => { + const component = shallow(); + + expect(component.find(EuiRange).prop('value')).toEqual(0.3); + }); + + it('should show fill opacity option when enabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(true); + }); + + it('should hide curve option when disabled', () => { + const component = mount( + + ); + + expect(component.exists('[data-test-subj="lnsFillOpacity"]')).toEqual(false); + }); +}); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx new file mode 100644 index 0000000000000..eb8d35c54a99b --- /dev/null +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/fill_opacity_option.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFormRow, EuiRange } from '@elastic/eui'; +import { useDebouncedValue } from '../../shared_components'; + +export interface FillOpacityOptionProps { + /** + * Currently selected value + */ + value: number; + /** + * Callback on display option change + */ + onChange: (value: number) => void; + /** + * Flag for rendering or not the component + */ + isFillOpacityEnabled?: boolean; +} + +export const FillOpacityOption: React.FC = ({ + onChange, + value, + isFillOpacityEnabled = true, +}) => { + const { inputValue, handleInputChange } = useDebouncedValue({ value, onChange }); + return isFillOpacityEnabled ? ( + <> + + { + handleInputChange(Number(e.currentTarget.value)); + }} + /> + + + ) : null; +}; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx index fb6ecec4d2801..a683d4fbf514c 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/missing_values_option.tsx @@ -7,7 +7,14 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonGroup, EuiFormRow, EuiIconTip, EuiSuperSelect, EuiText } from '@elastic/eui'; +import { + EuiButtonGroup, + EuiFormRow, + EuiIconTip, + EuiSuperSelect, + EuiText, + EuiSpacer, +} from '@elastic/eui'; import { FittingFunction, fittingFunctionDefinitions } from '../fitting_functions'; import { ValueLabelConfig } from '../types'; @@ -133,6 +140,7 @@ export const MissingValuesOptions: React.FC = ({ /> )} + ); }; diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx index e7ec395312bff..b46ad1940491e 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.test.tsx @@ -14,6 +14,7 @@ import { State } from '../types'; import { VisualOptionsPopover } from './visual_options_popover'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; +import { FillOpacityOption } from './fill_opacity_option'; describe('Visual options popover', () => { let frame: FramePublicAPI; @@ -74,6 +75,22 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should not disable the fill opacity for percentage area charts', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(true); + }); + it('should not disable the visual options for percentage area charts', () => { const state = testState(); const component = shallow( @@ -128,6 +145,40 @@ describe('Visual options popover', () => { expect(component.find(MissingValuesOptions).prop('isFittingEnabled')).toEqual(false); }); + it('should hide the fill opacity option for bar series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + + it('should hide the fill opacity option for line series', () => { + const state = testState(); + const component = shallow( + + ); + + expect(component.find(FillOpacityOption).prop('isFillOpacityEnabled')).toEqual(false); + }); + it('should show the popover and display field enabled for bar and horizontal_bar series', () => { const state = testState(); diff --git a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx index b8b89f146bdc0..b07feb85892e5 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visual_options_popover/visual_options_popover.tsx @@ -10,6 +10,7 @@ import { i18n } from '@kbn/i18n'; import { ToolbarPopover } from '../../shared_components'; import { MissingValuesOptions } from './missing_values_option'; import { LineCurveOption } from './line_curve_option'; +import { FillOpacityOption } from './fill_opacity_option'; import { XYState } from '../types'; import { hasHistogramSeries } from '../state_helpers'; import { ValidLayer } from '../types'; @@ -61,6 +62,10 @@ export const VisualOptionsPopover: React.FC = ({ ['bar', 'bar_horizontal'].includes(seriesType) ); + const hasAreaSeries = state?.layers.some(({ seriesType }) => + ['area_stacked', 'area', 'area_percentage_stacked'].includes(seriesType) + ); + const isHistogramSeries = Boolean( hasHistogramSeries(state?.layers as ValidLayer[], datasourceLayers) ); @@ -110,6 +115,17 @@ export const VisualOptionsPopover: React.FC = ({ setState({ ...state, fittingFunction: newVal }); }} /> + + { + setState({ + ...state, + fillOpacity: newValue, + }); + }} + /> ); diff --git a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts index 4554c34b97c55..aff33778258fe 100644 --- a/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts +++ b/x-pack/plugins/lens/public/xy_visualization/xy_suggestions.ts @@ -524,6 +524,7 @@ function buildSuggestion({ valueLabels: currentState?.valueLabels || 'hide', fittingFunction: currentState?.fittingFunction || 'None', curveType: currentState?.curveType, + fillOpacity: currentState?.fillOpacity, xTitle: currentState?.xTitle, yTitle: currentState?.yTitle, yRightTitle: currentState?.yRightTitle, From 111e15a0549df284fa3254057797a7359ffca9a8 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 25 May 2021 10:25:09 -0600 Subject: [PATCH 22/22] [ftr] implement FtrService classes and migrate common services (#99546) Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../development-functional-tests.asciidoc | 9 +- .../lib/providers/provider_collection.ts | 12 +- .../functional_test_runner/public_types.ts | 12 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- test/common/services/deployment.ts | 60 +++++----- test/common/services/index.ts | 16 +-- .../services/kibana_server/kibana_server.ts | 2 +- test/common/services/randomness.ts | 93 ++++++++------- test/common/services/retry/index.ts | 2 +- test/common/services/retry/retry.ts | 104 ++++++++--------- test/common/services/saved_object_info.ts | 74 ++++++------ test/common/services/security/security.ts | 32 ++--- test/common/services/security/test_user.ts | 110 ++++++++++-------- test/functional/apps/visualize/index.ts | 2 +- .../functional/apps/visualize/legacy/index.ts | 2 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- test/functional/page_objects/time_picker.ts | 2 +- .../page_objects/visual_builder_page.ts | 2 +- x-pack/test/functional/apps/lens/index.ts | 2 +- ...r_context.d.ts => ftr_provider_context.ts} | 3 +- 20 files changed, 292 insertions(+), 253 deletions(-) rename test/common/{ftr_provider_context.d.ts => ftr_provider_context.ts} (76%) rename test/functional/{ftr_provider_context.d.ts => ftr_provider_context.ts} (78%) rename x-pack/test/functional/{ftr_provider_context.d.ts => ftr_provider_context.ts} (74%) diff --git a/docs/developer/contributing/development-functional-tests.asciidoc b/docs/developer/contributing/development-functional-tests.asciidoc index 110704a8e569a..f0041b85c14eb 100644 --- a/docs/developer/contributing/development-functional-tests.asciidoc +++ b/docs/developer/contributing/development-functional-tests.asciidoc @@ -139,11 +139,14 @@ export default function (/* { providerAPI } */) { } ----------- -**Services**::: -Services are named singleton values produced by a Service Provider. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services. +**Service**::: +A Service is a named singleton created using a subclass of `FtrService`. Tests and other services can retrieve service instances by asking for them by name. All functionality except the mocha API is exposed via services. When you write your own functional tests check for existing services that help with the interactions you're looking to execute, and add new services for interactions which aren't already encoded in a service. + +**Service Providers**::: +For legacy purposes, and for when creating a subclass of `FtrService` is inconvenient, you can also create services using a "Service Provider". These are functions which which create service instances and return them. These instances are cached and provided to tests. Currently these providers may also return a Promise for the service instance, allowing the service to do some setup work before tests run. We expect to fully deprecate and remove support for async service providers in the near future and instead require that services use the `lifecycle` service to run setup before tests. Providers which return instances of classes other than `FtrService` will likely remain supported for as long as possible. **Page objects**::: -Page objects are a special type of service that encapsulate behaviors common to a particular page or plugin. When you write your own plugin, you’ll likely want to add a page object (or several) that describes the common interactions your tests need to execute. +Page objects are functionally equivalent to services, except they are loaded with a slightly different mechanism and generally defined separate from services. When you write your own functional tests you might want to write some of your services as Page objects, but it is not required. **Test Files**::: The `FunctionalTestRunner`'s primary purpose is to execute test files. These files export a Test Provider that is called with a Provider API but is not expected to return a value. Instead Test Providers define a suite using https://mochajs.org/#bdd[mocha's BDD interface]. diff --git a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts index 1aa5df1105f46..2d05d5bba5ff6 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/providers/provider_collection.ts @@ -12,6 +12,7 @@ import { loadTracer } from '../load_tracer'; import { createAsyncInstance, isAsyncInstance } from './async_instance'; import { Providers } from './read_provider_spec'; import { createVerboseInstance } from './verbose_instance'; +import { GenericFtrService } from '../../public_types'; export class ProviderCollection { private readonly instances = new Map(); @@ -58,12 +59,19 @@ export class ProviderCollection { } public invokeProviderFn(provider: (args: any) => any) { - return provider({ + const ctx = { getService: this.getService, hasService: this.hasService, getPageObject: this.getPageObject, getPageObjects: this.getPageObjects, - }); + }; + + if (provider.prototype instanceof GenericFtrService) { + const Constructor = (provider as any) as new (ctx: any) => any; + return new Constructor(ctx); + } + + return provider(ctx); } private findProvider(type: string, name: string) { diff --git a/packages/kbn-test/src/functional_test_runner/public_types.ts b/packages/kbn-test/src/functional_test_runner/public_types.ts index 915cb34f6ffe5..4a30744c09b51 100644 --- a/packages/kbn-test/src/functional_test_runner/public_types.ts +++ b/packages/kbn-test/src/functional_test_runner/public_types.ts @@ -13,7 +13,7 @@ import { Test, Suite } from './fake_mocha_types'; export { Lifecycle, Config, FailureMetadata }; -interface AsyncInstance { +export interface AsyncInstance { /** * Services that are initialized async are not ready before the tests execute, so you might need * to call `init()` and await the promise it returns before interacting with the service @@ -39,7 +39,11 @@ export type ProvidedType any> = MaybeAsyncInstance * promise types into the async instances that other providers will receive. */ type ProvidedTypeMap = { - [K in keyof T]: T[K] extends (...args: any[]) => any ? ProvidedType : unknown; + [K in keyof T]: T[K] extends new (...args: any[]) => infer X + ? X + : T[K] extends (...args: any[]) => any + ? ProvidedType + : unknown; }; export interface GenericFtrProviderContext< @@ -84,6 +88,10 @@ export interface GenericFtrProviderContext< loadTestFile(path: string): void; } +export class GenericFtrService> { + constructor(protected readonly ctx: ProviderContext) {} +} + export interface FtrConfigProviderContext { log: ToolingLog; readConfigFile(path: string): Promise; diff --git a/test/common/ftr_provider_context.d.ts b/test/common/ftr_provider_context.ts similarity index 76% rename from test/common/ftr_provider_context.d.ts rename to test/common/ftr_provider_context.ts index 91d35a2dbc32a..6d21aedfe1d5e 100644 --- a/test/common/ftr_provider_context.d.ts +++ b/test/common/ftr_provider_context.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} diff --git a/test/common/services/deployment.ts b/test/common/services/deployment.ts index 65466ca966ad2..b250d39ce65d6 100644 --- a/test/common/services/deployment.ts +++ b/test/common/services/deployment.ts @@ -10,39 +10,37 @@ import { get } from 'lodash'; import fetch from 'node-fetch'; import { getUrl } from '@kbn/test'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; -export function DeploymentProvider({ getService }: FtrProviderContext) { - const config = getService('config'); +export class DeploymentService extends FtrService { + private readonly config = this.ctx.getService('config'); - return { - /** - * Returns Kibana host URL - */ - getHostPort() { - return getUrl.baseUrl(config.get('servers.kibana')); - }, + /** + * Returns Kibana host URL + */ + getHostPort() { + return getUrl.baseUrl(this.config.get('servers.kibana')); + } - /** - * Returns ES host URL - */ - getEsHostPort() { - return getUrl.baseUrl(config.get('servers.elasticsearch')); - }, + /** + * Returns ES host URL + */ + getEsHostPort() { + return getUrl.baseUrl(this.config.get('servers.elasticsearch')); + } - async isCloud(): Promise { - const baseUrl = this.getHostPort(); - const username = config.get('servers.kibana.username'); - const password = config.get('servers.kibana.password'); - const response = await fetch(baseUrl + '/api/stats?extended', { - method: 'get', - headers: { - 'Content-Type': 'application/json', - Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), - }, - }); - const data = await response.json(); - return get(data, 'usage.cloud.is_cloud_enabled', false); - }, - }; + async isCloud(): Promise { + const baseUrl = this.getHostPort(); + const username = this.config.get('servers.kibana.username'); + const password = this.config.get('servers.kibana.password'); + const response = await fetch(baseUrl + '/api/stats?extended', { + method: 'get', + headers: { + 'Content-Type': 'application/json', + Authorization: 'Basic ' + Buffer.from(username + ':' + password).toString('base64'), + }, + }); + const data = await response.json(); + return get(data, 'usage.cloud.is_cloud_enabled', false); + } } diff --git a/test/common/services/index.ts b/test/common/services/index.ts index cc4859b7016bf..02aafc59fa80f 100644 --- a/test/common/services/index.ts +++ b/test/common/services/index.ts @@ -6,26 +6,26 @@ * Side Public License, v 1. */ -import { DeploymentProvider } from './deployment'; +import { DeploymentService } from './deployment'; import { LegacyEsProvider } from './legacy_es'; import { ElasticsearchProvider } from './elasticsearch'; import { EsArchiverProvider } from './es_archiver'; import { KibanaServerProvider } from './kibana_server'; -import { RetryProvider } from './retry'; -import { RandomnessProvider } from './randomness'; +import { RetryService } from './retry'; +import { RandomnessService } from './randomness'; import { SecurityServiceProvider } from './security'; import { EsDeleteAllIndicesProvider } from './es_delete_all_indices'; -import { SavedObjectInfoProvider } from './saved_object_info'; +import { SavedObjectInfoService } from './saved_object_info'; export const services = { - deployment: DeploymentProvider, + deployment: DeploymentService, legacyEs: LegacyEsProvider, es: ElasticsearchProvider, esArchiver: EsArchiverProvider, kibanaServer: KibanaServerProvider, - retry: RetryProvider, - randomness: RandomnessProvider, + retry: RetryService, + randomness: RandomnessService, security: SecurityServiceProvider, esDeleteAllIndices: EsDeleteAllIndicesProvider, - savedObjectInfo: SavedObjectInfoProvider, + savedObjectInfo: SavedObjectInfoService, }; diff --git a/test/common/services/kibana_server/kibana_server.ts b/test/common/services/kibana_server/kibana_server.ts index f366a864db980..63803bd511bd1 100644 --- a/test/common/services/kibana_server/kibana_server.ts +++ b/test/common/services/kibana_server/kibana_server.ts @@ -11,7 +11,7 @@ import { KbnClient } from '@kbn/test'; import { FtrProviderContext } from '../../ftr_provider_context'; -export function KibanaServerProvider({ getService }: FtrProviderContext) { +export function KibanaServerProvider({ getService }: FtrProviderContext): KbnClient { const log = getService('log'); const config = getService('config'); const lifecycle = getService('lifecycle'); diff --git a/test/common/services/randomness.ts b/test/common/services/randomness.ts index 88b0411f98033..82f06fb681066 100644 --- a/test/common/services/randomness.ts +++ b/test/common/services/randomness.ts @@ -7,8 +7,20 @@ */ import Chance from 'chance'; +import { ToolingLog } from '@kbn/dev-utils'; -import { FtrProviderContext } from '../ftr_provider_context'; +import { FtrService } from '../ftr_provider_context'; + +let __CACHED_SEED__: number | undefined; +function getSeed(log: ToolingLog) { + if (__CACHED_SEED__ !== undefined) { + return __CACHED_SEED__; + } + + __CACHED_SEED__ = Date.now(); + log.debug('randomness seed: %j', __CACHED_SEED__); + return __CACHED_SEED__; +} interface CharOptions { pool?: string; @@ -27,52 +39,45 @@ interface NumberOptions { max?: number; } -export function RandomnessProvider({ getService }: FtrProviderContext) { - const log = getService('log'); - - const seed = Date.now(); - log.debug('randomness seed: %j', seed); - - const chance = new Chance(seed); +export class RandomnessService extends FtrService { + private readonly chance = new Chance(getSeed(this.ctx.getService('log'))); - return new (class RandomnessService { - /** - * Generate a random natural number - * - * range: 0 to 9007199254740991 - * - */ - naturalNumber(options?: NumberOptions) { - return chance.natural(options); - } + /** + * Generate a random natural number + * + * range: 0 to 9007199254740991 + * + */ + naturalNumber(options?: NumberOptions) { + return this.chance.natural(options); + } - /** - * Generate a random integer - */ - integer(options?: NumberOptions) { - return chance.integer(options); - } + /** + * Generate a random integer + */ + integer(options?: NumberOptions) { + return this.chance.integer(options); + } - /** - * Generate a random number, defaults to at least 4 and no more than 8 syllables - */ - word(options: { syllables?: number } = {}) { - const { syllables = this.naturalNumber({ min: 4, max: 8 }) } = options; + /** + * Generate a random number, defaults to at least 4 and no more than 8 syllables + */ + word(options: { syllables?: number } = {}) { + const { syllables = this.naturalNumber({ min: 4, max: 8 }) } = options; - return chance.word({ - syllables, - }); - } + return this.chance.word({ + syllables, + }); + } - /** - * Generate a random string, defaults to at least 8 and no more than 15 alpha-numeric characters - */ - string(options: StringOptions = {}) { - return chance.string({ - length: this.naturalNumber({ min: 8, max: 15 }), - ...(options.pool === 'undefined' ? { alpha: true, numeric: true, symbols: false } : {}), - ...options, - }); - } - })(); + /** + * Generate a random string, defaults to at least 8 and no more than 15 alpha-numeric characters + */ + string(options: StringOptions = {}) { + return this.chance.string({ + length: this.naturalNumber({ min: 8, max: 15 }), + ...(options.pool === 'undefined' ? { alpha: true, numeric: true, symbols: false } : {}), + ...options, + }); + } } diff --git a/test/common/services/retry/index.ts b/test/common/services/retry/index.ts index 4914b3cff2261..08ce3f9bd4661 100644 --- a/test/common/services/retry/index.ts +++ b/test/common/services/retry/index.ts @@ -6,4 +6,4 @@ * Side Public License, v 1. */ -export { RetryProvider } from './retry'; +export { RetryService } from './retry'; diff --git a/test/common/services/retry/retry.ts b/test/common/services/retry/retry.ts index 8ea2a52b6adf6..5c823e256ddc8 100644 --- a/test/common/services/retry/retry.ts +++ b/test/common/services/retry/retry.ts @@ -6,64 +6,62 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService } from '../../ftr_provider_context'; import { retryForSuccess } from './retry_for_success'; import { retryForTruthy } from './retry_for_truthy'; -export function RetryProvider({ getService }: FtrProviderContext) { - const config = getService('config'); - const log = getService('log'); +export class RetryService extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly log = this.ctx.getService('log'); - return new (class Retry { - public async tryForTime( - timeout: number, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - return await retryForSuccess(log, { - timeout, - methodName: 'retry.tryForTime', - block, - onFailureBlock, - }); - } + public async tryForTime( + timeout: number, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + return await retryForSuccess(this.log, { + timeout, + methodName: 'retry.tryForTime', + block, + onFailureBlock, + }); + } - public async try(block: () => Promise, onFailureBlock?: () => Promise) { - return await retryForSuccess(log, { - timeout: config.get('timeouts.try'), - methodName: 'retry.try', - block, - onFailureBlock, - }); - } + public async try(block: () => Promise, onFailureBlock?: () => Promise) { + return await retryForSuccess(this.log, { + timeout: this.config.get('timeouts.try'), + methodName: 'retry.try', + block, + onFailureBlock, + }); + } - public async waitForWithTimeout( - description: string, - timeout: number, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - await retryForTruthy(log, { - timeout, - methodName: 'retry.waitForWithTimeout', - description, - block, - onFailureBlock, - }); - } + public async waitForWithTimeout( + description: string, + timeout: number, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + await retryForTruthy(this.log, { + timeout, + methodName: 'retry.waitForWithTimeout', + description, + block, + onFailureBlock, + }); + } - public async waitFor( - description: string, - block: () => Promise, - onFailureBlock?: () => Promise - ) { - await retryForTruthy(log, { - timeout: config.get('timeouts.waitFor'), - methodName: 'retry.waitFor', - description, - block, - onFailureBlock, - }); - } - })(); + public async waitFor( + description: string, + block: () => Promise, + onFailureBlock?: () => Promise + ) { + await retryForTruthy(this.log, { + timeout: this.config.get('timeouts.waitFor'), + methodName: 'retry.waitFor', + description, + block, + onFailureBlock, + }); + } } diff --git a/test/common/services/saved_object_info.ts b/test/common/services/saved_object_info.ts index 02ab38d4ecb1d..1558b364f5391 100644 --- a/test/common/services/saved_object_info.ts +++ b/test/common/services/saved_object_info.ts @@ -6,48 +6,44 @@ * Side Public License, v 1. */ -import { Client } from '@elastic/elasticsearch'; -import url from 'url'; -import { Either, fromNullable, chain, getOrElse } from 'fp-ts/Either'; -import { flow } from 'fp-ts/function'; -import { FtrProviderContext } from '../ftr_provider_context'; - -const pluck = (key: string) => (obj: any): Either => - fromNullable(new Error(`Missing ${key}`))(obj[key]); - -const types = (node: string) => async (index: string = '.kibana') => { - let res: unknown; - try { - const { body } = await new Client({ node }).search({ - index, - body: { - aggs: { - savedobjs: { - terms: { - field: 'type', +import { inspect } from 'util'; + +import { TermsAggregate } from '@elastic/elasticsearch/api/types'; + +import { FtrService } from '../ftr_provider_context'; + +export class SavedObjectInfoService extends FtrService { + private readonly es = this.ctx.getService('es'); + + public async getTypes(index = '.kibana') { + try { + const { body } = await this.es.search({ + index, + size: 0, + body: { + aggs: { + savedobjs: { + terms: { + field: 'type', + }, }, }, }, - }, - }); - - res = flow( - pluck('aggregations'), - chain(pluck('savedobjs')), - chain(pluck('buckets')), - getOrElse((err) => `${err.message}`) - )(body); - } catch (err) { - throw new Error(`Error while searching for saved object types: ${err}`); - } + }); - return res; -}; + const agg = body.aggregations?.savedobjs as + | TermsAggregate<{ key: string; doc_count: number }> + | undefined; -export const SavedObjectInfoProvider: any = ({ getService }: FtrProviderContext) => { - const config = getService('config'); + if (!agg?.buckets) { + throw new Error( + `expected es to return buckets of saved object types: ${inspect(body, { depth: 100 })}` + ); + } - return { - types: types(url.format(config.get('servers.elasticsearch'))), - }; -}; + return agg.buckets; + } catch (error) { + throw new Error(`Error while searching for saved object types: ${error}`); + } + } +} diff --git a/test/common/services/security/security.ts b/test/common/services/security/security.ts index 52fb6bdd70330..b8fea0a0c59b2 100644 --- a/test/common/services/security/security.ts +++ b/test/common/services/security/security.ts @@ -10,23 +10,27 @@ import { Role } from './role'; import { User } from './user'; import { RoleMappings } from './role_mappings'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { createTestUserService, TestUserSupertestProvider } from './test_user'; +import { createTestUserService, TestUserSupertestProvider, TestUser } from './test_user'; -export async function SecurityServiceProvider(context: FtrProviderContext) { - const { getService } = context; - const log = getService('log'); - const kibanaServer = getService('kibanaServer'); +export class SecurityService { + constructor( + public readonly roleMappings: RoleMappings, + public readonly testUser: TestUser, + public readonly role: Role, + public readonly user: User, + public readonly testUserSupertest: ReturnType + ) {} +} + +export async function SecurityServiceProvider(ctx: FtrProviderContext) { + const log = ctx.getService('log'); + const kibanaServer = ctx.getService('kibanaServer'); const role = new Role(log, kibanaServer); const user = new User(log, kibanaServer); - const testUser = await createTestUserService(role, user, context); - const testUserSupertest = TestUserSupertestProvider(context); + const testUser = await createTestUserService(ctx, role, user); + const testUserSupertest = TestUserSupertestProvider(ctx); + const roleMappings = new RoleMappings(log, kibanaServer); - return new (class SecurityService { - roleMappings = new RoleMappings(log, kibanaServer); - testUser = testUser; - role = role; - user = user; - testUserSupertest = testUserSupertest; - })(); + return new SecurityService(roleMappings, testUser, role, user, testUserSupertest); } diff --git a/test/common/services/security/test_user.ts b/test/common/services/security/test_user.ts index d5e1f02e1bc8c..8b0a1c34e790c 100644 --- a/test/common/services/security/test_user.ts +++ b/test/common/services/security/test_user.ts @@ -11,41 +11,84 @@ import supertestAsPromised from 'supertest-as-promised'; import { Role } from './role'; import { User } from './user'; -import { FtrProviderContext } from '../../ftr_provider_context'; +import { FtrService, FtrProviderContext } from '../../ftr_provider_context'; import { Browser } from '../../../functional/services/common'; import { TestSubjects } from '../../../functional/services/common'; const TEST_USER_NAME = 'test_user'; const TEST_USER_PASSWORD = 'changeme'; -export async function createTestUserService( - role: Role, - user: User, - { getService, hasService }: FtrProviderContext -) { - const log = getService('log'); - const config = getService('config'); - // @ts-ignore browser service is not normally available in common. - const browser: Browser | void = hasService('browser') && getService('browser'); - const testSubjects: TestSubjects | undefined = +export class TestUser extends FtrService { + private readonly config = this.ctx.getService('config'); + private readonly log = this.ctx.getService('log'); + + private readonly browser: Browser | void = + // browser service is not normally available in common. + this.ctx.hasService('browser') ? (this.ctx.getService('browser' as any) as Browser) : undefined; + + private readonly testSubjects: TestSubjects | undefined = // testSubject service is not normally available in common. - hasService('testSubjects') ? (getService('testSubjects' as any) as TestSubjects) : undefined; - const kibanaServer = getService('kibanaServer'); + this.ctx.hasService('testSubjects') + ? (this.ctx.getService('testSubjects' as any) as TestSubjects) + : undefined; + + constructor( + ctx: FtrProviderContext, + private readonly enabled: boolean, + private readonly user: User + ) { + super(ctx); + } + + async restoreDefaults(shouldRefreshBrowser: boolean = true) { + if (this.enabled) { + await this.setRoles(this.config.get('security.defaultRoles'), shouldRefreshBrowser); + } + } + + async setRoles(roles: string[], shouldRefreshBrowser: boolean = true) { + if (this.enabled) { + this.log.debug(`set roles = ${roles}`); + await this.user.create(TEST_USER_NAME, { + password: TEST_USER_PASSWORD, + roles, + full_name: 'test user', + }); + + if (this.browser && this.testSubjects && shouldRefreshBrowser) { + if (await this.testSubjects.exists('kibanaChrome', { allowHidden: true })) { + await this.browser.refresh(); + // accept alert if it pops up + const alert = await this.browser.getAlert(); + await alert?.accept(); + await this.testSubjects.find('kibanaChrome', this.config.get('timeouts.find') * 10); + } + } + } + } +} + +export async function createTestUserService(ctx: FtrProviderContext, role: Role, user: User) { + const log = ctx.getService('log'); + const config = ctx.getService('config'); + const kibanaServer = ctx.getService('kibanaServer'); const enabledPlugins = config.get('security.disableTestUser') ? [] : await kibanaServer.plugins.getEnabledIds(); - const isEnabled = () => { - return enabledPlugins.includes('security') && !config.get('security.disableTestUser'); - }; - if (isEnabled()) { + + const enabled = enabledPlugins.includes('security') && !config.get('security.disableTestUser'); + + if (enabled) { log.debug('===============creating roles and users==============='); + + // create the defined roles (need to map array to create roles) for (const [name, definition] of Object.entries(config.get('security.roles'))) { - // create the defined roles (need to map array to create roles) await role.create(name, definition); } + + // delete the test_user if present (will it error if the user doesn't exist?) try { - // delete the test_user if present (will it error if the user doesn't exist?) await user.delete(TEST_USER_NAME); } catch (exception) { log.debug('no test user to delete'); @@ -60,34 +103,7 @@ export async function createTestUserService( }); } - return new (class TestUser { - async restoreDefaults(shouldRefreshBrowser: boolean = true) { - if (isEnabled()) { - await this.setRoles(config.get('security.defaultRoles'), shouldRefreshBrowser); - } - } - - async setRoles(roles: string[], shouldRefreshBrowser: boolean = true) { - if (isEnabled()) { - log.debug(`set roles = ${roles}`); - await user.create(TEST_USER_NAME, { - password: TEST_USER_PASSWORD, - roles, - full_name: 'test user', - }); - - if (browser && testSubjects && shouldRefreshBrowser) { - if (await testSubjects.exists('kibanaChrome', { allowHidden: true })) { - await browser.refresh(); - // accept alert if it pops up - const alert = await browser.getAlert(); - await alert?.accept(); - await testSubjects.find('kibanaChrome', config.get('timeouts.find') * 10); - } - } - } - } - })(); + return new TestUser(ctx, enabled, user); } export function TestUserSupertestProvider({ getService }: FtrProviderContext) { diff --git a/test/functional/apps/visualize/index.ts b/test/functional/apps/visualize/index.ts index eb224b3c9b879..b87184bab3c0d 100644 --- a/test/functional/apps/visualize/index.ts +++ b/test/functional/apps/visualize/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); diff --git a/test/functional/apps/visualize/legacy/index.ts b/test/functional/apps/visualize/legacy/index.ts index 187e8f3f3a663..914559e5cea92 100644 --- a/test/functional/apps/visualize/legacy/index.ts +++ b/test/functional/apps/visualize/legacy/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../../ftr_provider_context'; import { UI_SETTINGS } from '../../../../../src/plugins/data/common'; export default function ({ getPageObjects, getService, loadTestFile }: FtrProviderContext) { diff --git a/test/functional/ftr_provider_context.d.ts b/test/functional/ftr_provider_context.ts similarity index 78% rename from test/functional/ftr_provider_context.d.ts rename to test/functional/ftr_provider_context.ts index 4c827393e1ef3..a1a29f50b7761 100644 --- a/test/functional/ftr_provider_context.d.ts +++ b/test/functional/ftr_provider_context.ts @@ -6,9 +6,10 @@ * Side Public License, v 1. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { pageObjects } from './page_objects'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {} diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index cfe250831e06c..d3b6edaffdbd3 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -7,7 +7,7 @@ */ import moment from 'moment'; -import { FtrProviderContext } from '../ftr_provider_context.d'; +import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export type CommonlyUsed = diff --git a/test/functional/page_objects/visual_builder_page.ts b/test/functional/page_objects/visual_builder_page.ts index 3ed5d74808fce..997a1127005ee 100644 --- a/test/functional/page_objects/visual_builder_page.ts +++ b/test/functional/page_objects/visual_builder_page.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { FtrProviderContext } from '../ftr_provider_context.d'; +import { FtrProviderContext } from '../ftr_provider_context'; import { WebElementWrapper } from '../services/lib/web_element_wrapper'; export function VisualBuilderPageProvider({ getService, getPageObjects }: FtrProviderContext) { diff --git a/x-pack/test/functional/apps/lens/index.ts b/x-pack/test/functional/apps/lens/index.ts index ab7cee13ffebd..d0466b8814fec 100644 --- a/x-pack/test/functional/apps/lens/index.ts +++ b/x-pack/test/functional/apps/lens/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { FtrProviderContext } from '../../ftr_provider_context.d'; +import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const browser = getService('browser'); diff --git a/x-pack/test/functional/ftr_provider_context.d.ts b/x-pack/test/functional/ftr_provider_context.ts similarity index 74% rename from x-pack/test/functional/ftr_provider_context.d.ts rename to x-pack/test/functional/ftr_provider_context.ts index 24f5087ef7fe2..e757164fa1de9 100644 --- a/x-pack/test/functional/ftr_provider_context.d.ts +++ b/x-pack/test/functional/ftr_provider_context.ts @@ -5,9 +5,10 @@ * 2.0. */ -import { GenericFtrProviderContext } from '@kbn/test'; +import { GenericFtrProviderContext, GenericFtrService } from '@kbn/test'; import { pageObjects } from './page_objects'; import { services } from './services'; export type FtrProviderContext = GenericFtrProviderContext; +export class FtrService extends GenericFtrService {}