From 58562c95656d37ad458d204f1e1810c63b7b2456 Mon Sep 17 00:00:00 2001 From: Pablo Machado Date: Wed, 24 Apr 2024 14:59:48 +0200 Subject: [PATCH 01/67] [SecuritySolutions] Fix entity analytics UI issues on dark mode (#181431) ## Summary We were using the wrong colour variables in a couple of places. These changes only impact the dark mode UI. Fixed pages: ![Screenshot 2024-04-23 at 14 55 20](https://github.com/elastic/kibana/assets/1490444/4b330c43-559d-4542-ab6b-46e98b69ce19) ![Screenshot 2024-04-23 at 14 36 12](https://github.com/elastic/kibana/assets/1490444/0b47b893-e9f2-4a54-b7c6-d055f2bb91a6) . --- .../components/file_picker_step.tsx | 2 +- .../shared/components/entity_table/columns.tsx | 6 +++--- .../components/side_panel/new_user_detail/columns.tsx | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/file_picker_step.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/file_picker_step.tsx index efe70c77f4c8f..942b3a18c2c21 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/file_picker_step.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality_file_uploader/components/file_picker_step.tsx @@ -137,7 +137,7 @@ export const AssetCriticalityFilePickerStep: React.FC( {label ?? field} diff --git a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx index da4e82976d515..fc3aeb6aedd9f 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/side_panel/new_user_detail/columns.tsx @@ -7,7 +7,7 @@ import { css } from '@emotion/react'; import React from 'react'; -import { euiLightVars } from '@kbn/ui-theme'; +import { euiThemeVars } from '@kbn/ui-theme'; import type { EuiBasicTableColumn } from '@elastic/eui'; import { SourcererScopeName } from '../../../../common/store/sourcerer/model'; import { DefaultFieldRenderer } from '../../field_renderers/field_renderers'; @@ -21,8 +21,8 @@ const fieldColumn: EuiBasicTableColumn = { render: (label: string, { field }) => ( {label ?? field} From 707ec552d9a303dae2ebb4603e8fd4ca157ff6d4 Mon Sep 17 00:00:00 2001 From: Abdul Wahab Zahid Date: Wed, 24 Apr 2024 15:27:08 +0200 Subject: [PATCH 02/67] [Dataset quality] Pass breakdown field over to logs explorer from degraded docs chart (#181509) ## Summary The PR adds the `breakdownField` param in `LogsExplorerNavigationParams` so that when "Explorer data in Logs Explorer" is clicked on Degraded Docs chart on Dataset Quality flyout while the chart has a breakdown field selected, the field is passed over to Logs Explorer. https://github.com/elastic/kibana/assets/2748376/b380ac85-e40e-451b-983f-41c68f87ed7b --- .../observability/locators/logs_explorer.ts | 4 ++ .../common/locators/locators.test.ts | 48 +++++++++++++++++++ .../locators/utils/construct_locator_path.ts | 12 ++++- 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/deeplinks/observability/locators/logs_explorer.ts b/packages/deeplinks/observability/locators/logs_explorer.ts index 1442e7afe02cd..39a28f91e7c11 100644 --- a/packages/deeplinks/observability/locators/logs_explorer.ts +++ b/packages/deeplinks/observability/locators/logs_explorer.ts @@ -68,6 +68,10 @@ export interface LogsExplorerNavigationParams extends SerializableRecord { * Optionally apply curated filter controls */ filterControls?: FilterControls; + /** + * Optionally set chart's breakdown field + */ + breakdownField?: string; } export interface LogsExplorerLocatorParams extends LogsExplorerNavigationParams { diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/locators.test.ts b/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/locators.test.ts index cdc50af3f5471..6761953c62325 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/locators.test.ts +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/locators.test.ts @@ -99,6 +99,21 @@ describe('Observability Logs Explorer Locators', () => { }); }); + it('should allow specifying breakdown field', async () => { + const params: AllDatasetsLocatorParams = { + breakdownField: 'service.name', + }; + + const { allDatasetsLocator } = await setup(); + const location = await allDatasetsLocator.getLocation(params); + + expect(location).toMatchObject({ + app: OBSERVABILITY_LOGS_EXPLORER_APP_ID, + path: '/?pageState=(breakdownField:service.name,dataSourceSelection:(selectionType:all),v:2)', + state: {}, + }); + }); + it('should allow specifying columns', async () => { const params: AllDatasetsLocatorParams = { columns: [{ field: '_source', type: 'document-field' }], @@ -211,6 +226,22 @@ describe('Observability Logs Explorer Locators', () => { }); }); + it('should allow specifying breakdown field', async () => { + const params: ObsLogsExplorerDataViewLocatorParams = { + id: 'data-view-id', + breakdownField: 'service.name', + }; + + const { dataViewLocator } = await setup(); + const location = await dataViewLocator.getLocation(params); + + expect(location).toMatchObject({ + app: OBSERVABILITY_LOGS_EXPLORER_APP_ID, + path: `/?pageState=(breakdownField:service.name,dataSourceSelection:(selection:(dataView:(dataType:unresolved,id:data-view-id)),selectionType:dataView),v:2)`, + state: {}, + }); + }); + it('should allow specifying columns', async () => { const params: ObsLogsExplorerDataViewLocatorParams = { id: 'data-view-id', @@ -331,6 +362,23 @@ describe('Observability Logs Explorer Locators', () => { }); }); + it('should allow specifying breakdown field', async () => { + const params: SingleDatasetLocatorParams = { + integration, + dataset, + breakdownField: 'service.name', + }; + + const { singleDatasetLocator } = await setup(); + const location = await singleDatasetLocator.getLocation(params); + + expect(location).toMatchObject({ + app: OBSERVABILITY_LOGS_EXPLORER_APP_ID, + path: `/?pageState=(breakdownField:service.name,dataSourceSelection:(selection:(dataset:(name:'logs-test-*-*',title:test),name:Test),selectionType:unresolved),v:2)`, + state: {}, + }); + }); + it('should allow specifying columns', async () => { const params: SingleDatasetLocatorParams = { integration, diff --git a/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/utils/construct_locator_path.ts b/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/utils/construct_locator_path.ts index eb96fb81ae2f3..fd1a0249b32f8 100644 --- a/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/utils/construct_locator_path.ts +++ b/x-pack/plugins/observability_solution/observability_logs_explorer/common/locators/utils/construct_locator_path.ts @@ -35,7 +35,16 @@ interface LocatorPathConstructionParams { export const constructLocatorPath = async (params: LocatorPathConstructionParams) => { const { dataSourceSelection, - locatorParams: { filterControls, filters, query, refreshInterval, timeRange, columns, origin }, + locatorParams: { + filterControls, + filters, + query, + refreshInterval, + timeRange, + columns, + origin, + breakdownField, + }, useHash, } = params; @@ -47,6 +56,7 @@ export const constructLocatorPath = async (params: LocatorPathConstructionParams query, refreshInterval, time: timeRange, + breakdownField, columns: columns?.map((column) => { return column.type === 'smart-field' ? SMART_FALLBACK_FIELDS[column.smartField] : column; }), From 42fa118b7dd4e0ec9108ca056d5f705d6f5617e9 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Wed, 24 Apr 2024 16:38:24 +0300 Subject: [PATCH 03/67] [Cases] Populate user info from fake requests (#180671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Set a system user name when the request is fake. This is helpful to show user information to the case created by the case action. ## Testing 1. Create a rule with a case action 2. In the created case verify that the `elastic/kibana` user is shown and not the `Unknown` user Screenshot 2024-04-22 at 10 37 46 PM ### Checklist Delete any items that are not applicable to this PR. - [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 ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../actions_client/actions_client.mock.ts | 2 +- .../actions_authorization.mock.ts | 2 +- x-pack/plugins/actions/server/feature.ts | 2 +- x-pack/plugins/actions/tsconfig.json | 3 +- .../plugins/cases/common/constants/index.ts | 1 + .../cases/server/client/factory.test.ts | 124 ++++++++++++++++++ x-pack/plugins/cases/server/client/factory.ts | 10 +- x-pack/plugins/cases/server/client/mocks.ts | 36 ++++- x-pack/plugins/cases/server/plugin.test.ts | 4 +- x-pack/plugins/cases/tsconfig.json | 1 + 10 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 x-pack/plugins/cases/server/client/factory.test.ts diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts index d58476738b9be..433e3850cae2a 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ActionsClient } from './actions_client'; +import type { ActionsClient } from './actions_client'; type ActionsClientContract = PublicMethodsOf; export type ActionsClientMock = jest.Mocked; diff --git a/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts b/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts index 20e95f1560c5a..ba106d014c28d 100644 --- a/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts +++ b/x-pack/plugins/actions/server/authorization/actions_authorization.mock.ts @@ -6,7 +6,7 @@ */ import type { PublicMethodsOf } from '@kbn/utility-types'; -import { ActionsAuthorization } from './actions_authorization'; +import type { ActionsAuthorization } from './actions_authorization'; export type ActionsAuthorizationMock = jest.Mocked>; diff --git a/x-pack/plugins/actions/server/feature.ts b/x-pack/plugins/actions/server/feature.ts index b44aaf61cad62..9fc48b705d25b 100644 --- a/x-pack/plugins/actions/server/feature.ts +++ b/x-pack/plugins/actions/server/feature.ts @@ -5,8 +5,8 @@ * 2.0. */ +import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { i18n } from '@kbn/i18n'; -import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { ACTION_SAVED_OBJECT_TYPE, ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, diff --git a/x-pack/plugins/actions/tsconfig.json b/x-pack/plugins/actions/tsconfig.json index 76ca916bc0ad0..d060287d24143 100644 --- a/x-pack/plugins/actions/tsconfig.json +++ b/x-pack/plugins/actions/tsconfig.json @@ -46,7 +46,8 @@ "@kbn/actions-types", "@kbn/core-http-server", "@kbn/core-test-helpers-kbn-server", - "@kbn/security-plugin-types-server" + "@kbn/security-plugin-types-server", + "@kbn/core-application-common" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/cases/common/constants/index.ts b/x-pack/plugins/cases/common/constants/index.ts index 6b6b914826b61..a8868010d2312 100644 --- a/x-pack/plugins/cases/common/constants/index.ts +++ b/x-pack/plugins/cases/common/constants/index.ts @@ -192,6 +192,7 @@ export const GET_CONNECTORS_CONFIGURE_API_TAG = 'casesGetConnectorsConfigure'; export const DEFAULT_USER_SIZE = 10; export const MAX_ASSIGNEES_PER_CASE = 10; export const NO_ASSIGNEES_FILTERING_KEYWORD = 'none'; +export const KIBANA_SYSTEM_USERNAME = 'elastic/kibana'; /** * Delays diff --git a/x-pack/plugins/cases/server/client/factory.test.ts b/x-pack/plugins/cases/server/client/factory.test.ts new file mode 100644 index 0000000000000..69147e888aeec --- /dev/null +++ b/x-pack/plugins/cases/server/client/factory.test.ts @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock, httpServerMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { CasesClientFactory } from './factory'; +import { createCasesClientFactoryMockArgs } from './mocks'; +import { createCasesClient } from './client'; +import type { FakeRawRequest } from '@kbn/core-http-server'; +import { CoreKibanaRequest } from '@kbn/core-http-router-server-internal'; + +jest.mock('./client'); + +describe('CasesClientFactory', () => { + const coreStart = coreMock.createStart(); + const request = httpServerMock.createKibanaRequest(); + + const rawRequest: FakeRawRequest = { + headers: {}, + path: '/', + }; + + const fakeRequest = CoreKibanaRequest.from(rawRequest); + const createCasesClientMocked = createCasesClient as jest.Mock; + const logger = loggingSystemMock.createLogger(); + const args = createCasesClientFactoryMockArgs(); + let casesClientFactory: CasesClientFactory; + + args.featuresPluginStart.getKibanaFeatures.mockReturnValue([]); + + beforeEach(() => { + casesClientFactory = new CasesClientFactory(logger); + casesClientFactory.initialize(args); + jest.clearAllMocks(); + }); + + describe('user info', () => { + it('constructs the user info from user profiles', async () => { + const scopedClusterClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser; + args.securityPluginStart.userProfiles.getCurrent.mockResolvedValueOnce({ + // @ts-expect-error: not all fields are needed + user: { username: 'my_user', full_name: 'My user', email: 'elastic@elastic.co' }, + }); + + await casesClientFactory.create({ + request, + savedObjectsService: coreStart.savedObjects, + scopedClusterClient, + }); + + expect(args.securityPluginStart.userProfiles.getCurrent).toHaveBeenCalled(); + expect(args.securityPluginStart.authc.getCurrentUser).not.toHaveBeenCalled(); + expect(createCasesClientMocked.mock.calls[0][0].user).toEqual({ + username: 'my_user', + full_name: 'My user', + email: 'elastic@elastic.co', + }); + }); + + it('constructs the user info from the authc service if the user profile is not available', async () => { + const scopedClusterClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser; + // @ts-expect-error: not all fields are needed + args.securityPluginStart.authc.getCurrentUser.mockReturnValueOnce({ + username: 'my_user_2', + full_name: 'My user 2', + email: 'elastic2@elastic.co', + }); + + await casesClientFactory.create({ + request, + savedObjectsService: coreStart.savedObjects, + scopedClusterClient, + }); + + expect(args.securityPluginStart.userProfiles.getCurrent).toHaveBeenCalled(); + expect(args.securityPluginStart.authc.getCurrentUser).toHaveBeenCalled(); + expect(createCasesClientMocked.mock.calls[0][0].user).toEqual({ + username: 'my_user_2', + full_name: 'My user 2', + email: 'elastic2@elastic.co', + }); + }); + + it('constructs the user info from fake requests correctly', async () => { + const scopedClusterClient = + coreStart.elasticsearch.client.asScoped(fakeRequest).asCurrentUser; + + await casesClientFactory.create({ + request: fakeRequest, + savedObjectsService: coreStart.savedObjects, + scopedClusterClient, + }); + + expect(args.securityPluginStart.userProfiles.getCurrent).toHaveBeenCalled(); + expect(args.securityPluginStart.authc.getCurrentUser).toHaveBeenCalled(); + expect(createCasesClientMocked.mock.calls[0][0].user).toEqual({ + username: 'elastic/kibana', + full_name: null, + email: null, + }); + }); + + it('return null for all user fields if it cannot find the user info', async () => { + const scopedClusterClient = coreStart.elasticsearch.client.asScoped(request).asCurrentUser; + + await casesClientFactory.create({ + request, + savedObjectsService: coreStart.savedObjects, + scopedClusterClient, + }); + + expect(args.securityPluginStart.userProfiles.getCurrent).toHaveBeenCalled(); + expect(args.securityPluginStart.authc.getCurrentUser).toHaveBeenCalled(); + expect(createCasesClientMocked.mock.calls[0][0].user).toEqual({ + username: null, + full_name: null, + email: null, + }); + }); + }); +}); diff --git a/x-pack/plugins/cases/server/client/factory.ts b/x-pack/plugins/cases/server/client/factory.ts index 137cf69e0763a..5bb04c1da9e86 100644 --- a/x-pack/plugins/cases/server/client/factory.ts +++ b/x-pack/plugins/cases/server/client/factory.ts @@ -34,7 +34,7 @@ import type { import type { PublicMethodsOf } from '@kbn/utility-types'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import type { FilesStart } from '@kbn/files-plugin/server'; -import { SAVED_OBJECT_TYPES } from '../../common/constants'; +import { KIBANA_SYSTEM_USERNAME, SAVED_OBJECT_TYPES } from '../../common/constants'; import { Authorization } from '../authorization/authorization'; import { CaseConfigureService, @@ -286,6 +286,14 @@ export class CasesClientFactory { this.logger.debug(`Failed to retrieve user info from authc: ${error}`); } + if (request.isFakeRequest) { + return { + username: KIBANA_SYSTEM_USERNAME, + full_name: null, + email: null, + }; + } + return { username: null, full_name: null, diff --git a/x-pack/plugins/cases/server/client/mocks.ts b/x-pack/plugins/cases/server/client/mocks.ts index 608a9ae2ff510..3de350f5a3981 100644 --- a/x-pack/plugins/cases/server/client/mocks.ts +++ b/x-pack/plugins/cases/server/client/mocks.ts @@ -9,12 +9,20 @@ import type { PublicContract, PublicMethodsOf } from '@kbn/utility-types'; import { loggingSystemMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; import type { ISavedObjectsSerializer } from '@kbn/core-saved-objects-server'; -import { createFileServiceMock } from '@kbn/files-plugin/server/mocks'; +import { + createFileServiceFactoryMock, + createFileServiceMock, +} from '@kbn/files-plugin/server/mocks'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { actionsClientMock } from '@kbn/actions-plugin/server/actions_client/actions_client.mock'; import { makeLensEmbeddableFactory } from '@kbn/lens-plugin/server/embeddable/make_lens_embeddable_factory'; import { serializerMock } from '@kbn/core-saved-objects-base-server-mocks'; - +import { spacesMock } from '@kbn/spaces-plugin/server/mocks'; +import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; +import { actionsMock } from '@kbn/actions-plugin/server/mocks'; +import { notificationsMock } from '@kbn/notifications-plugin/server/mocks'; +import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; +import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; import type { CasesSearchRequest } from '../../common/types/api'; import type { CasesClient, CasesClientInternal } from '.'; import type { AttachmentsSubClient } from './attachments/client'; @@ -214,6 +222,30 @@ export const createCasesClientMockArgs = () => { }; }; +export const createCasesClientFactoryMockArgs = () => { + return { + securityPluginSetup: securityMock.createSetup(), + securityPluginStart: securityMock.createStart(), + spacesPluginStart: spacesMock.createStart(), + featuresPluginStart: featuresPluginMock.createSetup(), + actionsPluginStart: actionsMock.createStart(), + licensingPluginStart: licensingMock.createStart(), + notifications: notificationsMock.createStart(), + ruleRegistry: { getRacClientWithRequest: jest.fn(), alerting: alertsMock.createStart() }, + filesPluginStart: { fileServiceFactory: createFileServiceFactoryMock() }, + publicBaseUrl: 'https//example.com', + lensEmbeddableFactory: jest.fn().mockReturnValue( + makeLensEmbeddableFactory( + () => ({}), + () => ({}), + {} + ) + ), + externalReferenceAttachmentTypeRegistry: createExternalReferenceAttachmentTypeRegistryMock(), + persistableStateAttachmentTypeRegistry: createPersistableStateAttachmentTypeRegistryMock(), + }; +}; + export const createCasesClientMockSearchRequest = ( overwrites?: CasesSearchRequest ): CasesSearchRequest => ({ diff --git a/x-pack/plugins/cases/server/plugin.test.ts b/x-pack/plugins/cases/server/plugin.test.ts index 8c669f6de0e68..ac328f25de391 100644 --- a/x-pack/plugins/cases/server/plugin.test.ts +++ b/x-pack/plugins/cases/server/plugin.test.ts @@ -11,7 +11,7 @@ import { coreMock } from '@kbn/core/server/mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; -import { createFilesSetupMock } from '@kbn/files-plugin/server/mocks'; +import { createFileServiceFactoryMock, createFilesSetupMock } from '@kbn/files-plugin/server/mocks'; import { securityMock } from '@kbn/security-plugin/server/mocks'; import { makeLensEmbeddableFactory } from '@kbn/lens-plugin/server/embeddable/make_lens_embeddable_factory'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; @@ -69,7 +69,7 @@ describe('Cases Plugin', () => { pluginsStart = { licensing: licensingMock.createStart(), actions: actionsMock.createStart(), - files: { fileServiceFactory: { asScoped: jest.fn(), asInternal: jest.fn() } }, + files: { fileServiceFactory: createFileServiceFactoryMock() }, features: featuresPluginMock.createStart(), security: securityMock.createStart(), notifications: notificationsMock.createStart(), diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index b5a426c3f9c0b..535f4e5e106dc 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -74,6 +74,7 @@ "@kbn/core-logging-server-mocks", "@kbn/core-logging-browser-mocks", "@kbn/data-views-plugin", + "@kbn/core-http-router-server-internal", ], "exclude": [ "target/**/*", From 05478009c69f5993207f8db1f93f1230f4006a96 Mon Sep 17 00:00:00 2001 From: Jean-Louis Leysens Date: Wed, 24 Apr 2024 16:09:46 +0200 Subject: [PATCH 04/67] [HTTP/OAS] Support `deprecated` field (#181240) --- packages/kbn-config-schema/index.ts | 2 ++ .../kbn-config-schema/src/oas_meta_fields.ts | 1 + .../kbn-config-schema/src/types/type.test.ts | 24 ++++++++++++++----- packages/kbn-config-schema/src/types/type.ts | 14 +++++++++-- .../__snapshots__/generate_oas.test.ts.snap | 4 ++++ .../src/generate_oas.test.util.ts | 7 +++++- .../post_process_mutations/mutations/index.ts | 3 ++- .../post_process_mutations/mutations/utils.ts | 8 +++++++ 8 files changed, 53 insertions(+), 10 deletions(-) diff --git a/packages/kbn-config-schema/index.ts b/packages/kbn-config-schema/index.ts index dfb701f0a039c..c5b46932463db 100644 --- a/packages/kbn-config-schema/index.ts +++ b/packages/kbn-config-schema/index.ts @@ -246,6 +246,7 @@ export type Schema = typeof schema; import { META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_OPTIONAL, + META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_MAX_LENGTH, META_FIELD_X_OAS_MIN_LENGTH, META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES, @@ -254,6 +255,7 @@ import { export const metaFields = Object.freeze({ META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_OPTIONAL, + META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_MAX_LENGTH, META_FIELD_X_OAS_MIN_LENGTH, META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES, diff --git a/packages/kbn-config-schema/src/oas_meta_fields.ts b/packages/kbn-config-schema/src/oas_meta_fields.ts index 44422793558d4..ad04f9b30ef16 100644 --- a/packages/kbn-config-schema/src/oas_meta_fields.ts +++ b/packages/kbn-config-schema/src/oas_meta_fields.ts @@ -16,3 +16,4 @@ export const META_FIELD_X_OAS_MAX_LENGTH = 'x-oas-max-length' as const; export const META_FIELD_X_OAS_GET_ADDITIONAL_PROPERTIES = 'x-oas-get-additional-properties' as const; export const META_FIELD_X_OAS_REF_ID = 'x-oas-ref-id' as const; +export const META_FIELD_X_OAS_DEPRECATED = 'x-oas-deprecated' as const; diff --git a/packages/kbn-config-schema/src/types/type.test.ts b/packages/kbn-config-schema/src/types/type.test.ts index 4d6636a55b9ca..a4784af2e8b62 100644 --- a/packages/kbn-config-schema/src/types/type.test.ts +++ b/packages/kbn-config-schema/src/types/type.test.ts @@ -9,7 +9,7 @@ import { get } from 'lodash'; import { internals } from '../internals'; import { Type, TypeOptions } from './type'; -import { META_FIELD_X_OAS_REF_ID } from '../oas_meta_fields'; +import { META_FIELD_X_OAS_REF_ID, META_FIELD_X_OAS_DEPRECATED } from '../oas_meta_fields'; class MyType extends Type { constructor(opts: TypeOptions = {}) { @@ -17,9 +17,21 @@ class MyType extends Type { } } -test('meta', () => { - const type = new MyType({ meta: { description: 'my description', id: 'foo' } }); - const meta = type.getSchema().describe(); - expect(get(meta, 'flags.description')).toBe('my description'); - expect(get(meta, `metas[0].${META_FIELD_X_OAS_REF_ID}`)).toBe('foo'); +describe('meta', () => { + it('sets meta when provided', () => { + const type = new MyType({ + meta: { description: 'my description', id: 'foo', deprecated: true }, + }); + const meta = type.getSchema().describe(); + expect(get(meta, 'flags.description')).toBe('my description'); + expect(get(meta, `metas[0].${META_FIELD_X_OAS_REF_ID}`)).toBe('foo'); + expect(get(meta, `metas[1].${META_FIELD_X_OAS_DEPRECATED}`)).toBe(true); + }); + + it('does not set meta when no provided', () => { + const type = new MyType(); + const meta = type.getSchema().describe(); + expect(get(meta, 'flags.description')).toBeUndefined(); + expect(get(meta, 'metas')).toBeUndefined(); + }); }); diff --git a/packages/kbn-config-schema/src/types/type.ts b/packages/kbn-config-schema/src/types/type.ts index 1e312cc7adc7e..80ed3f90fdd2a 100644 --- a/packages/kbn-config-schema/src/types/type.ts +++ b/packages/kbn-config-schema/src/types/type.ts @@ -7,16 +7,23 @@ */ import type { AnySchema, CustomValidator, ErrorReport } from 'joi'; -import { META_FIELD_X_OAS_REF_ID } from '../oas_meta_fields'; +import { META_FIELD_X_OAS_DEPRECATED, META_FIELD_X_OAS_REF_ID } from '../oas_meta_fields'; import { SchemaTypeError, ValidationError } from '../errors'; import { Reference } from '../references'; -/** Meta fields used when introspecting runtime validation */ +/** + * Meta fields used when introspecting runtime validation. Most notably for + * generating OpenAPI spec. + */ export interface TypeMeta { /** * A human-friendly description of this type to be used in documentation. */ description?: string; + /** + * Whether this field is deprecated. + */ + deprecated?: boolean; /** * A string that uniquely identifies this schema. Used when generating OAS * to create refs instead of inline schemas. @@ -108,6 +115,9 @@ export abstract class Type { if (options.meta.id) { schema = schema.meta({ [META_FIELD_X_OAS_REF_ID]: options.meta.id }); } + if (options.meta.deprecated) { + schema = schema.meta({ [META_FIELD_X_OAS_DEPRECATED]: true }); + } } // Attach generic error handler only if it hasn't been attached yet since diff --git a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap index 42deee2907f43..aac31188c4985 100644 --- a/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap +++ b/packages/kbn-router-to-openapispec/src/__snapshots__/generate_oas.test.ts.snap @@ -155,6 +155,10 @@ Object { "schema": Object { "additionalProperties": false, "properties": Object { + "deprecatedFoo": Object { + "deprecated": true, + "type": "string", + }, "foo": Object { "type": "string", }, diff --git a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts index e435065f0089f..41a2458619000 100644 --- a/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts +++ b/packages/kbn-router-to-openapispec/src/generate_oas.test.util.ts @@ -79,7 +79,12 @@ const getVersionedRouterDefaults = () => ({ fn: jest.fn(), options: { validate: { - request: { body: schema.object({ foo: schema.string() }) }, + request: { + body: schema.object({ + foo: schema.string(), + deprecatedFoo: schema.maybe(schema.string({ meta: { deprecated: true } })), + }), + }, response: { [200]: { body: schema.object({ fooResponse: schema.string() }) }, }, diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts index 4f5b31030695e..e200ba7d1ec27 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/index.ts @@ -10,7 +10,7 @@ import Joi from 'joi'; import { metaFields } from '@kbn/config-schema'; import type { OpenAPIV3 } from 'openapi-types'; import { parse } from '../../parse'; -import { deleteField, stripBadDefault } from './utils'; +import { deleteField, stripBadDefault, processDeprecated } from './utils'; import { IContext } from '../context'; const { @@ -62,6 +62,7 @@ export const processMap = (ctx: IContext, schema: OpenAPIV3.SchemaObject): void }; export const processAny = (schema: OpenAPIV3.SchemaObject): void => { + processDeprecated(schema); stripBadDefault(schema); }; diff --git a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/utils.ts b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/utils.ts index 5bad28b276d10..eacc005936a28 100644 --- a/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/utils.ts +++ b/packages/kbn-router-to-openapispec/src/oas_converter/kbn_config_schema/post_process_mutations/mutations/utils.ts @@ -7,6 +7,7 @@ */ import type { OpenAPIV3 } from 'openapi-types'; +import { metaFields } from '@kbn/config-schema'; export const stripBadDefault = (schema: OpenAPIV3.SchemaObject): void => { if (schema.default?.special === 'deep') { @@ -26,6 +27,13 @@ export const stripBadDefault = (schema: OpenAPIV3.SchemaObject): void => { } }; +export const processDeprecated = (schema: OpenAPIV3.SchemaObject): void => { + if (metaFields.META_FIELD_X_OAS_DEPRECATED in schema) { + schema.deprecated = true; + deleteField(schema, metaFields.META_FIELD_X_OAS_DEPRECATED); + } +}; + /** Just for type convenience */ export const deleteField = (schema: Record, field: string): void => { delete schema[field]; From d5999c339a615a4e7cbd23741747dffa984da678 Mon Sep 17 00:00:00 2001 From: Dima Arnautov Date: Wed, 24 Apr 2024 16:29:06 +0200 Subject: [PATCH 05/67] [ML] Fix responsive layout for Trained Models table (#181541) ## Summary Closes https://github.com/elastic/kibana/issues/181530 - Sets percentage width for all columns - Sets responsive breakpoint - Makes Deployment stats table responsive as well ![Apr-24-2024 12-16-48](https://github.com/elastic/kibana/assets/5236598/2a14ffb9-de15-45e9-b8bc-276e10080864) ### Checklist - [x] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [x] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- .../nodes_overview/allocated_models.tsx | 29 ++++++++++--------- .../model_management/model_actions.tsx | 6 ++-- .../model_management/models_list.tsx | 15 +++++----- 3 files changed, 24 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx index f0ff64eae6445..4a31112255d92 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx @@ -41,21 +41,22 @@ export const AllocatedModels: FC = ({ const columns: Array> = [ { + width: '10%', id: 'deployment_id', field: 'deployment_id', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.deploymentIdHeader', { defaultMessage: 'ID', }), - width: '150px', sortable: true, truncateText: false, + isExpander: false, 'data-test-subj': 'mlAllocatedModelsTableDeploymentId', }, { + width: '8%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelRoutingStateHeader', { defaultMessage: 'Routing state', }), - width: '100px', 'data-test-subj': 'mlAllocatedModelsTableRoutingState', render: (v: AllocatedModel) => { const { routing_state: routingState, reason } = v.node.routing_state; @@ -68,32 +69,32 @@ export const AllocatedModels: FC = ({ }, }, { + width: '8%', id: 'node_name', field: 'node.name', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.nodeNameHeader', { defaultMessage: 'Node name', }), - width: '150px', sortable: true, truncateText: false, 'data-test-subj': 'mlAllocatedModelsTableNodeName', }, { + width: '10%', id: 'model_id', field: 'model_id', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelNameHeader', { defaultMessage: 'Name', }), - width: '250px', sortable: true, truncateText: false, 'data-test-subj': 'mlAllocatedModelsTableName', }, { + width: '8%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelSizeHeader', { defaultMessage: 'Size', }), - width: '100px', truncateText: true, 'data-test-subj': 'mlAllocatedModelsTableSize', render: (v: AllocatedModel) => { @@ -101,6 +102,7 @@ export const AllocatedModels: FC = ({ }, }, { + width: '8%', name: ( = ({ ), - width: '100px', truncateText: false, 'data-test-subj': 'mlAllocatedModelsTableAllocation', render: (v: AllocatedModel) => { @@ -129,6 +130,7 @@ export const AllocatedModels: FC = ({ }, }, { + width: '8%', name: ( = ({ ), field: 'node.throughput_last_minute', - width: '100px', truncateText: false, 'data-test-subj': 'mlAllocatedModelsTableThroughput', }, { + width: '8%', name: ( = ({ ), - width: '100px', truncateText: false, 'data-test-subj': 'mlAllocatedModelsTableAvgInferenceTime', render: (v: AllocatedModel) => { @@ -196,56 +197,56 @@ export const AllocatedModels: FC = ({ }, }, { + width: '8%', name: i18n.translate( 'xpack.ml.trainedModels.nodesList.modelsList.modelInferenceCountHeader', { defaultMessage: 'Inference count', } ), - width: '100px', 'data-test-subj': 'mlAllocatedModelsTableInferenceCount', render: (v: AllocatedModel) => { return v.node.inference_count; }, }, { + width: '12%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelStartTimeHeader', { defaultMessage: 'Start time', }), - width: '200px', 'data-test-subj': 'mlAllocatedModelsTableStartedTime', render: (v: AllocatedModel) => { return dateFormatter(v.node.start_time); }, }, { + width: '12%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelLastAccessHeader', { defaultMessage: 'Last access', }), - width: '200px', 'data-test-subj': 'mlAllocatedModelsTableInferenceCount', render: (v: AllocatedModel) => { return v.node.last_access ? dateFormatter(v.node.last_access) : '-'; }, }, { + width: '8%', name: i18n.translate( 'xpack.ml.trainedModels.nodesList.modelsList.modelNumberOfPendingRequestsHeader', { defaultMessage: 'Pending requests', } ), - width: '100px', 'data-test-subj': 'mlAllocatedModelsTableNumberOfPendingRequests', render: (v: AllocatedModel) => { return v.node.number_of_pending_requests; }, }, { + width: '8%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.errorCountHeader', { defaultMessage: 'Errors', }), - width: '60px', 'data-test-subj': 'mlAllocatedModelsTableErrorCount', render: (v: AllocatedModel) => { return v.node.error_count ?? 0; @@ -255,6 +256,7 @@ export const AllocatedModels: FC = ({ return ( + responsiveBreakpoint={'xl'} allowNeutralSort={false} columns={columns} items={models} @@ -264,7 +266,6 @@ export const AllocatedModels: FC = ({ })} onTableChange={() => {}} data-test-subj={'mlNodesAllocatedModels'} - css={{ overflow: 'auto' }} /> ); }; diff --git a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx index c3b726d8bd2d6..5d690a7a58fd8 100644 --- a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx +++ b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx @@ -199,9 +199,8 @@ export function useModelActions({ } ), 'data-test-subj': 'mlModelsTableRowStartDeploymentAction', - // @ts-ignore EUI has a type check issue when type "button" is combined with an icon. icon: 'play', - type: 'button', + type: 'icon', isPrimary: true, enabled: (item) => { return canStartStopTrainedModels && !isLoading && item.state !== MODEL_STATE.DOWNLOADING; @@ -409,9 +408,8 @@ export function useModelActions({ defaultMessage: 'Download', }), 'data-test-subj': 'mlModelsTableRowDownloadModelAction', - // @ts-ignore EUI has a type check issue when type "button" is combined with an icon. icon: 'download', - type: 'button', + type: 'icon', isPrimary: true, available: (item) => canCreateTrainedModels && diff --git a/x-pack/plugins/ml/public/application/model_management/models_list.tsx b/x-pack/plugins/ml/public/application/model_management/models_list.tsx index 8f4a9ae1e55f1..242db5904252d 100644 --- a/x-pack/plugins/ml/public/application/model_management/models_list.tsx +++ b/x-pack/plugins/ml/public/application/model_management/models_list.tsx @@ -486,7 +486,7 @@ export const ModelsList: FC = ({ const columns: Array> = [ { align: 'left', - width: '40px', + width: '32px', isExpander: true, render: (item: ModelItem) => { if (!item.stats) { @@ -512,7 +512,7 @@ export const ModelsList: FC = ({ }, { name: modelIdColumnName, - width: '215px', + width: '15%', sortable: ({ model_id: modelId }: ModelItem) => modelId, truncateText: false, textOnly: false, @@ -533,7 +533,6 @@ export const ModelsList: FC = ({ }, }, { - width: '300px', name: i18n.translate('xpack.ml.trainedModels.modelsList.modelDescriptionHeader', { defaultMessage: 'Description', }), @@ -567,6 +566,7 @@ export const ModelsList: FC = ({ }, }, { + width: '15%', field: ModelsTableToConfigMapping.type, name: i18n.translate('xpack.ml.trainedModels.modelsList.typeHeader', { defaultMessage: 'Type', @@ -586,9 +586,9 @@ export const ModelsList: FC = ({ ), 'data-test-subj': 'mlModelsTableColumnType', - width: '130px', }, { + width: '10%', field: 'state', name: i18n.translate('xpack.ml.trainedModels.modelsList.stateHeader', { defaultMessage: 'State', @@ -604,9 +604,9 @@ export const ModelsList: FC = ({ ) : null; }, 'data-test-subj': 'mlModelsTableColumnDeploymentState', - width: '130px', }, { + width: '20%', field: ModelsTableToConfigMapping.createdAt, name: i18n.translate('xpack.ml.trainedModels.modelsList.createdAtHeader', { defaultMessage: 'Created at', @@ -615,10 +615,9 @@ export const ModelsList: FC = ({ render: (v: number) => dateFormatter(v), sortable: true, 'data-test-subj': 'mlModelsTableColumnCreatedAt', - width: '210px', }, { - width: '150px', + width: '15%', name: i18n.translate('xpack.ml.trainedModels.modelsList.actionsHeader', { defaultMessage: 'Actions', }), @@ -768,7 +767,7 @@ export const ModelsList: FC = ({
- css={{ overflowX: 'auto' }} + responsiveBreakpoint={'xl'} allowNeutralSort={false} columns={columns} itemIdToExpandedRowMap={itemIdToExpandedRowMap} From d635c6deeba5891b548eea9e04fb7e144cc9eac5 Mon Sep 17 00:00:00 2001 From: Julia Bardi <90178898+juliaElastic@users.noreply.github.com> Date: Wed, 24 Apr 2024 17:14:49 +0200 Subject: [PATCH 06/67] [Fleet] allow fleet-server agent upgrade to newer than fleet-server (#181575) ## Summary Closes https://github.com/elastic/kibana/issues/181394 Allow upgrade fleet-server even if fleet-server version is older than the upgrade version. See testing steps in the linked issue. ### 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 --- .../agent_upgrade_modal/index.test.tsx | 37 +++++++++++++++++++ .../components/agent_upgrade_modal/index.tsx | 5 +++ 2 files changed, 42 insertions(+) diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx index dc08d052a9152..a71329168d054 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.test.tsx @@ -334,6 +334,43 @@ describe('AgentUpgradeAgentModal', () => { expect(el).not.toBeDisabled(); }); }); + + it('should enable submit button for a single fleet-server when version is greater than maxFleetServerVersion', async () => { + mockSendGetAgentsAvailableVersions.mockClear(); + mockSendGetAgentsAvailableVersions.mockResolvedValue({ + data: { + items: ['8.10.4', '8.10.2', '8.9.0', '8.8.0'], + }, + }); + mockSendAllFleetServerAgents.mockResolvedValue({ + allFleetServerAgents: [ + { id: 'fleet-server', local_metadata: { elastic: { agent: { version: '8.9.0' } } } }, + ] as any, + }); + + const { utils } = renderAgentUpgradeAgentModal({ + agents: [ + { + id: 'fleet-server', + local_metadata: { + elastic: { + agent: { version: '8.9.0', upgradeable: true }, + }, + host: { hostname: 'host00001' }, + }, + }, + ] as any, + agentCount: 1, + }); + + await waitFor(() => { + const container = utils.getByTestId('agentUpgradeModal.VersionCombobox'); + const input = within(container).getByRole('combobox'); + expect(input?.value).toEqual('8.10.2'); + const el = utils.getByTestId('confirmModalConfirmButton'); + expect(el).toBeEnabled(); + }); + }); }); describe('restart upgrade', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx index 89531c2b01181..a82cef810f9cc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_upgrade_modal/index.tsx @@ -287,6 +287,9 @@ export const AgentUpgradeAgentModal: React.FunctionComponent agent.id).includes(agents[0].id); + const isSubmitButtonDisabled = useMemo( () => isSubmitting || @@ -294,6 +297,7 @@ export const AgentUpgradeAgentModal: React.FunctionComponent Date: Wed, 24 Apr 2024 17:21:25 +0200 Subject: [PATCH 07/67] Value list UI and telemetry (#180929) ## Add telemetry and change UI copy for value list: Screenshot 2024-04-17 at 15 09 47 Screenshot 2024-04-17 at 15 09 41 Screenshot 2024-04-17 at 15 09 30 Screenshot 2024-04-17 at 15 09 24 Screenshot 2024-04-17 at 15 09 18 --------- Co-authored-by: Nastasha Solomon <79124755+nastasha-solomon@users.noreply.github.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/common/lib/telemetry/constants.ts | 7 +++++ .../translations.ts | 2 +- .../detection_engine/rules/translations.ts | 2 +- .../components/add_list_item_popover.tsx | 4 +-- .../components/delete_list_item.tsx | 2 ++ .../inline_edit_list_item_value.tsx | 2 ++ .../value_list/components/list_item_table.tsx | 2 ++ .../components/show_value_list_modal.tsx | 6 ++++- .../components/upload_list_item.tsx | 2 ++ .../public/value_list/translations.ts | 27 +++++++++---------- .../value_lists/value_list_items.cy.ts | 2 +- 11 files changed, 37 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts index 72c38f1cc69b5..052a3296d8414 100644 --- a/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts +++ b/x-pack/plugins/security_solution/public/common/lib/telemetry/constants.ts @@ -34,6 +34,13 @@ export enum TELEMETRY_EVENT { // Landing page - dashboard DASHBOARD = 'navigate_to_dashboard', CREATE_DASHBOARD = 'create_dashboard', + + // value list + OPEN_VALUE_LIST_MODAL = 'open_value_list_modal', + CREATE_VALUE_LIST_ITEM = 'create_value_list_item', + DELETE_VALUE_LIST_ITEM = 'delete_value_list_item', + EDIT_VALUE_LIST_ITEM = 'edit_value_list_item', + ADDITIONAL_UPLOAD_VALUE_LIST_ITEM = 'additinonal_upload_value_list_item', } export enum TelemetryEventTypes { diff --git a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout/translations.ts b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout/translations.ts index 37fbfaf09f6d8..caea46a2417d0 100644 --- a/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout/translations.ts @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; export const VALUE_LISTS_FLYOUT_TITLE = i18n.translate( 'xpack.securitySolution.lists.importValueListTitle', { - defaultMessage: 'Import value lists', + defaultMessage: 'Manage value lists', } ); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts index a7823f39abb70..7ceb3fa661ba6 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/translations.ts @@ -23,7 +23,7 @@ export const IMPORT_RULE = i18n.translate( export const IMPORT_VALUE_LISTS = i18n.translate( 'xpack.securitySolution.lists.detectionEngine.rules.importValueListsButton', { - defaultMessage: 'Import value lists', + defaultMessage: 'Manage value lists', } ); diff --git a/x-pack/plugins/security_solution/public/value_list/components/add_list_item_popover.tsx b/x-pack/plugins/security_solution/public/value_list/components/add_list_item_popover.tsx index 6dabd24f3f8ac..1a0a41c602641 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/add_list_item_popover.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/add_list_item_popover.tsx @@ -23,10 +23,10 @@ import { SUCCESSFULLY_ADDED_ITEM, VALUE_REQUIRED, VALUE_LABEL, - ADD_VALUE_LIST_PLACEHOLDER, ADDING_LIST_ITEM_BUTTON, ADD_LIST_ITEM_BUTTON, } from '../translations'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; export const AddListItemPopover = ({ listId }: { listId: string }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -53,6 +53,7 @@ export const AddListItemPopover = ({ listId }: { listId: string }) => { } }, onSubmit: async (values) => { + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.CREATE_VALUE_LIST_ITEM); await createListItemMutation.mutateAsync({ listId, value: values.value, http }); setIsPopoverOpen(false); formik.resetForm(); @@ -93,7 +94,6 @@ export const AddListItemPopover = ({ listId }: { listId: string }) => { name="value" icon="listAdd" data-test-subj="value-list-item-add-input" - placeholder={ADD_VALUE_LIST_PLACEHOLDER} isInvalid={!!formik.errors.value} /> diff --git a/x-pack/plugins/security_solution/public/value_list/components/delete_list_item.tsx b/x-pack/plugins/security_solution/public/value_list/components/delete_list_item.tsx index d9ad65a60cf0b..520d9668f5ad5 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/delete_list_item.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/delete_list_item.tsx @@ -11,6 +11,7 @@ import { useDeleteListItemMutation } from '@kbn/securitysolution-list-hooks'; import { useAppToasts } from '../../common/hooks/use_app_toasts'; import { useKibana } from '../../common/lib/kibana'; import { SUCCESSFULLY_DELETED_ITEM } from '../translations'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; const toastOptions = { toastLifeTimeMs: 5000, @@ -32,6 +33,7 @@ export const DeleteListItem = ({ id, value }: { id: string; value: string }) => }); const deleteListItem = useCallback(() => { + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.DELETE_VALUE_LIST_ITEM); deleteListItemMutation.mutate({ id, http }); }, [deleteListItemMutation, id, http]); diff --git a/x-pack/plugins/security_solution/public/value_list/components/inline_edit_list_item_value.tsx b/x-pack/plugins/security_solution/public/value_list/components/inline_edit_list_item_value.tsx index 4ef639bcdbebb..d8777a8d83d00 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/inline_edit_list_item_value.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/inline_edit_list_item_value.tsx @@ -12,6 +12,7 @@ import { usePatchListItemMutation } from '@kbn/securitysolution-list-hooks'; import { useAppToasts } from '../../common/hooks/use_app_toasts'; import { useKibana } from '../../common/lib/kibana/kibana_react'; import { EDIT_TEXT_INLINE_LABEL, SUCCESSFULLY_UPDATED_LIST_ITEM } from '../translations'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; const toastOptions = { toastLifeTimeMs: 5000, @@ -41,6 +42,7 @@ export const InlineEditListItemValue = ({ listItem }: { listItem: ListItemSchema const onSave = useCallback( async (newValue) => { + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.EDIT_VALUE_LIST_ITEM); await patchListItemMutation.mutateAsync({ id: listItem.id, value: newValue, diff --git a/x-pack/plugins/security_solution/public/value_list/components/list_item_table.tsx b/x-pack/plugins/security_solution/public/value_list/components/list_item_table.tsx index 50226ea047acc..11ecd486aa452 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/list_item_table.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/list_item_table.tsx @@ -20,6 +20,7 @@ import { FAILED_TO_FETCH_LIST_ITEM, DELETE_LIST_ITEM, DELETE_LIST_ITEM_DESCRIPTION, + NOT_FOUND_ITEMS, } from '../translations'; export const ListItemTable = ({ @@ -80,6 +81,7 @@ export const ListItemTable = ({ error={isError ? FAILED_TO_FETCH_LIST_ITEM : undefined} loading={loading} onChange={onChange} + noItemsMessage={NOT_FOUND_ITEMS} /> ); }; diff --git a/x-pack/plugins/security_solution/public/value_list/components/show_value_list_modal.tsx b/x-pack/plugins/security_solution/public/value_list/components/show_value_list_modal.tsx index 0cf0608425b2f..96ab0ab599ee4 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/show_value_list_modal.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/show_value_list_modal.tsx @@ -10,6 +10,7 @@ import React, { useState, useCallback } from 'react'; import { useListsPrivileges } from '../../detections/containers/detection_engine/lists/use_lists_privileges'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { ValueListModal } from './value_list_modal'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; export const ShowValueListModal = ({ listId, @@ -27,7 +28,10 @@ export const ShowValueListModal = ({ ); const onCloseModal = useCallback(() => setShowModal(false), []); - const onShowModal = useCallback(() => setShowModal(true), []); + const onShowModal = useCallback(() => { + track(METRIC_TYPE.CLICK, TELEMETRY_EVENT.OPEN_VALUE_LIST_MODAL); + setShowModal(true); + }, []); if (loading) return null; diff --git a/x-pack/plugins/security_solution/public/value_list/components/upload_list_item.tsx b/x-pack/plugins/security_solution/public/value_list/components/upload_list_item.tsx index 7e43629a6578c..3fe12339fe095 100644 --- a/x-pack/plugins/security_solution/public/value_list/components/upload_list_item.tsx +++ b/x-pack/plugins/security_solution/public/value_list/components/upload_list_item.tsx @@ -20,6 +20,7 @@ import { FAILED_TO_UPLOAD_LIST_ITEM, SUCCESSFULY_UPLOAD_LIST_ITEMS, } from '../translations'; +import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../common/lib/telemetry'; const validFileTypes = ['text/csv', 'text/plain']; @@ -45,6 +46,7 @@ export const UploadListItem = ({ listId, type }: { listId: string; type: ListTyp const handleImport = useCallback(() => { if (!importState.loading && file) { ctrl.current = new AbortController(); + track(METRIC_TYPE.COUNT, TELEMETRY_EVENT.ADDITIONAL_UPLOAD_VALUE_LIST_ITEM); importList({ file, listId, diff --git a/x-pack/plugins/security_solution/public/value_list/translations.ts b/x-pack/plugins/security_solution/public/value_list/translations.ts index 62b81fa61cab2..d97ece63dbe15 100644 --- a/x-pack/plugins/security_solution/public/value_list/translations.ts +++ b/x-pack/plugins/security_solution/public/value_list/translations.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; export const ADD_LIST_ITEM = i18n.translate('xpack.securitySolution.listItems.addListItem', { - defaultMessage: 'Add list item', + defaultMessage: 'Create list item', }); export const SUCCESSFULLY_ADDED_ITEM = i18n.translate( @@ -23,20 +23,13 @@ export const VALUE_REQUIRED = i18n.translate('xpack.securitySolution.listItems.v }); export const VALUE_LABEL = i18n.translate('xpack.securitySolution.listItems.valueLabel', { - defaultMessage: 'Value', + defaultMessage: 'Enter a new value for the list', }); -export const ADD_VALUE_LIST_PLACEHOLDER = i18n.translate( - 'xpack.securitySolution.listItems.addValueListPlaceholder', - { - defaultMessage: 'Add list item..', - } -); - export const ADD_LIST_ITEM_BUTTON = i18n.translate( 'xpack.securitySolution.listItems.addListItemButton', { - defaultMessage: 'Add', + defaultMessage: 'Add list item', } ); @@ -75,19 +68,19 @@ export const COLUMN_VALUE = i18n.translate('xpack.securitySolution.listItems.col export const COLUMN_UPDATED_AT = i18n.translate( 'xpack.securitySolution.listItems.columnUpdatedAt', { - defaultMessage: 'Updated At', + defaultMessage: 'Updated at', } ); export const COLUMN_UPDATED_BY = i18n.translate( 'xpack.securitySolution.listItems.columnUpdatedBy', { - defaultMessage: 'Updated By', + defaultMessage: 'Updated by', } ); export const COLUMN_ACTIONS = i18n.translate('xpack.securitySolution.listItems.columnActions', { - defaultMessage: 'Actions', + defaultMessage: 'Action', }); export const FAILED_TO_FETCH_LIST_ITEM = i18n.translate( @@ -131,7 +124,7 @@ export const FAILED_TO_UPLOAD_LIST_ITEM_TITLE = i18n.translate( ); export const UPLOAD_TOOLTIP = i18n.translate('xpack.securitySolution.listItems.uploadTooltip', { - defaultMessage: 'All items from the file will be added as new items', + defaultMessage: 'All items from the file will be added to the value list.', }); export const UPLOAD_FILE_PICKER_INITAL_PROMT_TEXT = i18n.translate( @@ -163,6 +156,10 @@ export const INFO_TOTAL_ITEMS = i18n.translate('xpack.securitySolution.listItems export const getInfoTotalItems = (listType: string) => i18n.translate('xpack.securitySolution.listItems.searchBar', { - defaultMessage: 'Filter your data using KQL syntax - {listType}:*', + defaultMessage: 'Filter your data using KQL syntax, for example: {listType}:*', values: { listType }, }); + +export const NOT_FOUND_ITEMS = i18n.translate('xpack.securitySolution.listItems.notFoundItems', { + defaultMessage: '0 list items match your search criteria.', +}); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/value_lists/value_list_items.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/value_lists/value_list_items.cy.ts index c8fd74fa64397..79933ea4d7f33 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/value_lists/value_list_items.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/value_lists/value_list_items.cy.ts @@ -88,7 +88,7 @@ describe( getValueListItemsTableRow().should('have.length', perPage); searchValueListItemsModal('keyword:not_exists'); getValueListItemsTableRow().should('have.length', 1); - cy.get(VALUE_LIST_ITEMS_MODAL_TABLE).contains('No items found'); + cy.get(VALUE_LIST_ITEMS_MODAL_TABLE).contains('0 list items match your search criteria.'); searchValueListItemsModal('keyword:*or*'); getValueListItemsTableRow().should('have.length', 4); From f2f5ec927c8439b536e874ff04e081ec95758fad Mon Sep 17 00:00:00 2001 From: Jon Date: Wed, 24 Apr 2024 10:26:11 -0500 Subject: [PATCH 08/67] [build/serverless] Do not use spot instances (#181578) This build step doesn't support retries, if the docker image has already been uploaded once it exits early. We want to rule out spot preemptions as a cause of failure. --- .buildkite/pipelines/artifacts_container_image.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.buildkite/pipelines/artifacts_container_image.yml b/.buildkite/pipelines/artifacts_container_image.yml index 972fada9ddde2..63744d64aba92 100644 --- a/.buildkite/pipelines/artifacts_container_image.yml +++ b/.buildkite/pipelines/artifacts_container_image.yml @@ -2,9 +2,5 @@ steps: - command: .buildkite/scripts/steps/artifacts/docker_image.sh label: Build serverless container images agents: - queue: n2-16-spot + queue: c2-16 timeout_in_minutes: 60 - retry: - automatic: - - exit_status: '-1' - limit: 3 From 4cf38adac29c7a65ab142ba428cdc3ae0648f2c4 Mon Sep 17 00:00:00 2001 From: "Eyo O. Eyo" <7893459+eokoneyo@users.noreply.github.com> Date: Wed, 24 Apr 2024 16:30:35 +0100 Subject: [PATCH 09/67] [ES|QL] Multiline query in expanded mode shows undefined for line number (#181544) ## Summary closes https://github.com/elastic/kibana/issues/180570 Thanks to @drewdaemon for the preliminary investigation to the root cause of the issue, see https://github.com/elastic/kibana/issues/180570#issuecomment-2059590022. Building off of this, I noticed there's actually a first render pass where the code editor renders just fine, but for some reason it renders again ~causing~ which in turn causes the issue to happen see Screenshot 2024-04-24 at 01 48 18 From the image above we see that the editor has it's line numbers rendered appropriately but then there's another render triggered which causes the issue, we'll notice that the dynamic overlay instance in the image above have their property of `_shouldRender` marked as false, this is because a render already happened see line 97 from the same image where said dynamic overlay is marked as rendered; Screenshot 2024-04-24 at 09 09 51 See [here](https://github.com/microsoft/vscode/blob/a3944f74adb303047355e8c7d4b401bfba4e1a0d/src/vs/editor/common/viewEventHandler.ts#L30-L32) for the definition of `onDidRender`. This then makes it such that for the next render pass the render result isn't available. My assumption is that because we are updating the layout value of the editor, on every model change without actually taking into consideration the state of the editor it causes the editor to go out of sync, see Screenshot 2024-04-24 at 09 31 45 To counteract this, this PR introduces a guard that only updates the editor height when the event received actually has a diff in `contentHeight` property. Alongside this computation of the editor height is now inferred by reading values provided by the editor itself and not the DOM element of the editor. ## Visuals https://github.com/elastic/kibana/assets/7893459/26bb60ad-9ea1-41fe-854a-5c8a7be2e29d --- .../src/text_based_languages_editor.styles.ts | 2 +- .../src/text_based_languages_editor.tsx | 45 ++++++++----------- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts index 8d8bd72eb8dcd..8e5fbb1974a55 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.styles.ts @@ -12,7 +12,7 @@ export const EDITOR_INITIAL_HEIGHT_EXPANDED = 140; export const EDITOR_MIN_HEIGHT = 40; export const EDITOR_MAX_HEIGHT = 400; -export const textBasedLanguagedEditorStyles = ( +export const textBasedLanguageEditorStyles = ( euiTheme: EuiThemeComputed, isCompactFocused: boolean, editorHeight: number, diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index cf026c79fbc55..7cbf3a5a5cbf4 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -43,7 +43,7 @@ import { import { CodeEditor, CodeEditorProps } from '@kbn/code-editor'; import { - textBasedLanguagedEditorStyles, + textBasedLanguageEditorStyles, EDITOR_INITIAL_HEIGHT, EDITOR_INITIAL_HEIGHT_EXPANDED, EDITOR_MAX_HEIGHT, @@ -189,7 +189,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ kibana.services; const timeZone = core?.uiSettings?.get('dateFormat:tz'); const [code, setCode] = useState(queryString ?? ''); - const [codeOneLiner, setCodeOneLiner] = useState(''); + const [codeOneLiner, setCodeOneLiner] = useState(null); // To make server side errors less "sticky", register the state of the code when submitting const [codeWhenSubmitted, setCodeStateOnSubmission] = useState(code); const [editorHeight, setEditorHeight] = useState( @@ -273,7 +273,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ }); }); - const styles = textBasedLanguagedEditorStyles( + const styles = textBasedLanguageEditorStyles( euiTheme, isCompactFocused, editorHeight, @@ -342,34 +342,24 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ updateLinesFromModel = false; clickedOutside = true; if (editor1.current) { - const editorElement = editor1.current.getDomNode(); - if (editorElement) { - editorElement.style.height = `${EDITOR_INITIAL_HEIGHT}px`; - const contentWidth = Number(editorElement?.style.width.replace('px', '')); - calculateVisibleCode(contentWidth, true); - editor1.current.layout({ width: contentWidth, height: EDITOR_INITIAL_HEIGHT }); - } + const contentWidth = editor1.current.getLayoutInfo().width; + calculateVisibleCode(contentWidth, true); + editor1.current.layout({ width: contentWidth, height: EDITOR_INITIAL_HEIGHT }); } }; const updateHeight = useCallback((editor: monaco.editor.IStandaloneCodeEditor) => { - if (lines === 1 || clickedOutside || initialRender) return; - const editorElement = editor.getDomNode(); + if (clickedOutside || initialRender) return; const contentHeight = Math.min(MAX_COMPACT_VIEW_LENGTH, editor.getContentHeight()); - - if (editorElement) { - editorElement.style.height = `${contentHeight}px`; - } - const contentWidth = Number(editorElement?.style.width.replace('px', '')); - editor.layout({ width: contentWidth, height: contentHeight }); setEditorHeight(contentHeight); + editor.layout({ width: editor.getLayoutInfo().width, height: contentHeight }); }, []); const onEditorFocus = useCallback(() => { setIsCompactFocused(true); setIsCodeEditorExpandedFocused(true); setShowLineNumbers(true); - setCodeOneLiner(''); + setCodeOneLiner(null); clickedOutside = false; initialRender = false; updateLinesFromModel = true; @@ -598,13 +588,9 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ useEffect(() => { if (editor1.current && !isCompactFocused) { - const editorElement = editor1.current.getDomNode(); - if (editorElement) { - const contentWidth = Number(editorElement?.style.width.replace('px', '')); - if (code !== queryString) { - setCode(queryString); - calculateVisibleCode(contentWidth); - } + if (code !== queryString) { + setCode(queryString); + calculateVisibleCode(editor1.current.getLayoutInfo().width); } } }, [calculateVisibleCode, code, isCompactFocused, queryString]); @@ -944,9 +930,14 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ monaco.KeyMod.CtrlCmd | monaco.KeyCode.Enter, onQuerySubmit ); + if (!isCodeEditorExpanded) { editor.onDidContentSizeChange((e) => { - updateHeight(editor); + // @ts-expect-error the property _oldContentHeight exists on the event object received but + // is not available on the type definition + if (e.contentHeight !== e._oldContentHeight) { + updateHeight(editor); + } }); } }} From 4bfe566c18f6c6ef7e347c2a4e0d59b08da6ad51 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Wed, 24 Apr 2024 11:53:39 -0400 Subject: [PATCH 10/67] Use internal formatErrors (#181065) --- .../src/decode_request_params.test.ts | 3 ++- .../src/decode_request_params.ts | 11 +++++------ packages/kbn-server-route-repository/tsconfig.json | 1 - .../apm_routes/register_apm_server_routes.test.ts | 3 ++- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/kbn-server-route-repository/src/decode_request_params.test.ts b/packages/kbn-server-route-repository/src/decode_request_params.test.ts index 8f7e6f421cd36..0cb8d280f28e4 100644 --- a/packages/kbn-server-route-repository/src/decode_request_params.test.ts +++ b/packages/kbn-server-route-repository/src/decode_request_params.test.ts @@ -69,7 +69,8 @@ describe('decodeRequestParams', () => { }; expect(decode).toThrowErrorMatchingInlineSnapshot(` - "Excess keys are not allowed: + "Failed to validate: + Excess keys are not allowed: path.extraKey" `); }); diff --git a/packages/kbn-server-route-repository/src/decode_request_params.ts b/packages/kbn-server-route-repository/src/decode_request_params.ts index e9b75ded73d01..0893524a3f9e9 100644 --- a/packages/kbn-server-route-repository/src/decode_request_params.ts +++ b/packages/kbn-server-route-repository/src/decode_request_params.ts @@ -5,12 +5,11 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import * as t from 'io-ts'; -import { omitBy, isPlainObject, isEmpty } from 'lodash'; -import { isLeft } from 'fp-ts/lib/Either'; import Boom from '@hapi/boom'; -import { strictKeysRt } from '@kbn/io-ts-utils'; -import { formatErrors } from '@kbn/securitysolution-io-ts-utils'; +import { formatErrors, strictKeysRt } from '@kbn/io-ts-utils'; +import { isLeft } from 'fp-ts/lib/Either'; +import * as t from 'io-ts'; +import { isEmpty, isPlainObject, omitBy } from 'lodash'; import { RouteParamsRT } from './typings'; interface KibanaRequestParams { @@ -36,7 +35,7 @@ export function decodeRequestParams( const result = strictKeysRt(paramsRt).decode(paramMap); if (isLeft(result)) { - throw Boom.badRequest(formatErrors(result.left).join('|')); + throw Boom.badRequest(formatErrors(result.left)); } return result.right; diff --git a/packages/kbn-server-route-repository/tsconfig.json b/packages/kbn-server-route-repository/tsconfig.json index f5f84f5114b7d..67a5631bca59e 100644 --- a/packages/kbn-server-route-repository/tsconfig.json +++ b/packages/kbn-server-route-repository/tsconfig.json @@ -18,7 +18,6 @@ "@kbn/core-http-server", "@kbn/core-lifecycle-server", "@kbn/logging", - "@kbn/securitysolution-io-ts-utils" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.test.ts b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.test.ts index 47ada9ee20f4c..c5e652fa910d0 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.test.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.test.ts @@ -256,7 +256,8 @@ describe('createApi', () => { expect(response.custom).toHaveBeenCalledWith({ body: { attributes: { _inspect: [], data: null }, - message: 'Invalid value "1" supplied to "query,_inspect"', + message: `Failed to validate: + in /query/_inspect: 1 does not match expected type pipe(JSON, boolean)`, }, statusCode: 400, }); From ed2f63bf7e540d63229dfc32dc6d8f6a6b895485 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 24 Apr 2024 18:18:42 +0200 Subject: [PATCH 11/67] [Discover] Split functional tests in more groups (#180046) ## Summary This PR splits existing functional tests into more groups so each of them finishes running quicker. - `group1` into `group1` and `group5` - `group2` into `group2_data_grid1`, `group2_data_grid2`, `group2_data_grid3` - `group3` into `group3` and `group6` - `group4` into `group4`, `group7` and `group8` (almost empty) --------- Co-authored-by: Davis McPhee --- .buildkite/ftr_configs.yml | 8 ++++- test/functional/apps/discover/group1/index.ts | 10 ------ .../_data_grid.ts | 0 .../_data_grid_context.ts | 0 .../_data_grid_copy_to_clipboard.ts | 0 .../_data_grid_doc_navigation.ts | 0 .../_data_grid_doc_table.ts | 0 .../{group2 => group2_data_grid1}/config.ts | 0 .../{group2 => group2_data_grid1}/index.ts | 10 +----- .../_data_grid_field_data.ts | 0 .../_data_grid_field_tokens.ts | 0 .../_data_grid_footer.ts | 0 .../_data_grid_new_line.ts | 0 .../apps/discover/group2_data_grid2/config.ts | 18 ++++++++++ .../apps/discover/group2_data_grid2/index.ts | 28 +++++++++++++++ .../_data_grid_pagination.ts | 0 .../_data_grid_row_height.ts | 0 .../_data_grid_row_navigation.ts | 0 .../_data_grid_sample_size.ts | 0 .../apps/discover/group2_data_grid3/config.ts | 18 ++++++++++ .../apps/discover/group2_data_grid3/index.ts | 28 +++++++++++++++ test/functional/apps/discover/group3/index.ts | 5 --- test/functional/apps/discover/group4/index.ts | 8 ----- .../{group1 => group5}/_field_data.ts | 0 .../_field_data_with_fields_api.ts | 0 .../{group1 => group5}/_filter_editor.ts | 0 .../{group1 => group5}/_greeting_screen.ts | 0 .../discover/{group1 => group5}/_inspector.ts | 0 .../{group1 => group5}/_large_string.ts | 0 .../discover/{group1 => group5}/_no_data.ts | 0 .../{group1 => group5}/_shared_links.ts | 0 .../{group1 => group5}/_source_filters.ts | 0 .../discover/{group1 => group5}/_url_state.ts | 0 .../functional/apps/discover/group5/config.ts | 18 ++++++++++ test/functional/apps/discover/group5/index.ts | 34 +++++++++++++++++++ .../discover/{group3 => group6}/_sidebar.ts | 0 .../_sidebar_field_stats.ts | 0 .../{group3 => group6}/_time_field_column.ts | 0 .../_unsaved_changes_badge.ts | 0 .../{group3 => group6}/_view_mode_toggle.ts | 0 .../functional/apps/discover/group6/config.ts | 18 ++++++++++ test/functional/apps/discover/group6/index.ts | 29 ++++++++++++++++ .../{group4 => group7}/_huge_fields.ts | 0 .../_indexpattern_with_unmapped_fields.ts | 0 .../_indexpattern_without_timefield.ts | 0 .../{group4 => group7}/_new_search.ts | 0 .../_request_cancellation.ts | 0 .../_runtime_fields_editor.ts | 0 .../_search_on_page_load.ts | 0 .../functional/apps/discover/group7/config.ts | 18 ++++++++++ test/functional/apps/discover/group7/index.ts | 31 +++++++++++++++++ .../{group4 => group8}/_hide_announcements.ts | 0 .../functional/apps/discover/group8/config.ts | 18 ++++++++++ test/functional/apps/discover/group8/index.ts | 25 ++++++++++++++ test/functional/firefox/discover.config.ts | 8 ++++- .../common/discover/group1/index.ts | 1 - .../common/discover/group2/index.ts | 1 - .../common/discover/group3/index.ts | 2 -- .../{group2 => group4}/_adhoc_data_views.ts | 0 .../common/discover/group4/index.ts | 25 ++++++++++++++ .../discover/{group1 => group5}/_url_state.ts | 0 .../common/discover/group5/index.ts | 25 ++++++++++++++ .../discover/{group3 => group6}/_sidebar.ts | 0 .../_unsaved_changes_badge.ts | 0 .../common/discover/group6/index.ts | 26 ++++++++++++++ .../common_configs/config.group5.ts | 3 ++ .../search/common_configs/config.group5.ts | 3 ++ .../security/common_configs/config.group5.ts | 3 ++ 68 files changed, 383 insertions(+), 38 deletions(-) rename test/functional/apps/discover/{group2 => group2_data_grid1}/_data_grid.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/_data_grid_context.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/_data_grid_copy_to_clipboard.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/_data_grid_doc_navigation.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/_data_grid_doc_table.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/config.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid1}/index.ts (67%) rename test/functional/apps/discover/{group2 => group2_data_grid2}/_data_grid_field_data.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid2}/_data_grid_field_tokens.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid2}/_data_grid_footer.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid2}/_data_grid_new_line.ts (100%) create mode 100644 test/functional/apps/discover/group2_data_grid2/config.ts create mode 100644 test/functional/apps/discover/group2_data_grid2/index.ts rename test/functional/apps/discover/{group2 => group2_data_grid3}/_data_grid_pagination.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid3}/_data_grid_row_height.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid3}/_data_grid_row_navigation.ts (100%) rename test/functional/apps/discover/{group2 => group2_data_grid3}/_data_grid_sample_size.ts (100%) create mode 100644 test/functional/apps/discover/group2_data_grid3/config.ts create mode 100644 test/functional/apps/discover/group2_data_grid3/index.ts rename test/functional/apps/discover/{group1 => group5}/_field_data.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_field_data_with_fields_api.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_filter_editor.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_greeting_screen.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_inspector.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_large_string.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_no_data.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_shared_links.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_source_filters.ts (100%) rename test/functional/apps/discover/{group1 => group5}/_url_state.ts (100%) create mode 100644 test/functional/apps/discover/group5/config.ts create mode 100644 test/functional/apps/discover/group5/index.ts rename test/functional/apps/discover/{group3 => group6}/_sidebar.ts (100%) rename test/functional/apps/discover/{group3 => group6}/_sidebar_field_stats.ts (100%) rename test/functional/apps/discover/{group3 => group6}/_time_field_column.ts (100%) rename test/functional/apps/discover/{group3 => group6}/_unsaved_changes_badge.ts (100%) rename test/functional/apps/discover/{group3 => group6}/_view_mode_toggle.ts (100%) create mode 100644 test/functional/apps/discover/group6/config.ts create mode 100644 test/functional/apps/discover/group6/index.ts rename test/functional/apps/discover/{group4 => group7}/_huge_fields.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_indexpattern_with_unmapped_fields.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_indexpattern_without_timefield.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_new_search.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_request_cancellation.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_runtime_fields_editor.ts (100%) rename test/functional/apps/discover/{group4 => group7}/_search_on_page_load.ts (100%) create mode 100644 test/functional/apps/discover/group7/config.ts create mode 100644 test/functional/apps/discover/group7/index.ts rename test/functional/apps/discover/{group4 => group8}/_hide_announcements.ts (100%) create mode 100644 test/functional/apps/discover/group8/config.ts create mode 100644 test/functional/apps/discover/group8/index.ts rename x-pack/test_serverless/functional/test_suites/common/discover/{group2 => group4}/_adhoc_data_views.ts (100%) create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/group4/index.ts rename x-pack/test_serverless/functional/test_suites/common/discover/{group1 => group5}/_url_state.ts (100%) create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/group5/index.ts rename x-pack/test_serverless/functional/test_suites/common/discover/{group3 => group6}/_sidebar.ts (100%) rename x-pack/test_serverless/functional/test_suites/common/discover/{group3 => group6}/_unsaved_changes_badge.ts (100%) create mode 100644 x-pack/test_serverless/functional/test_suites/common/discover/group6/index.ts diff --git a/.buildkite/ftr_configs.yml b/.buildkite/ftr_configs.yml index a4c7c64762299..b17a63170f907 100644 --- a/.buildkite/ftr_configs.yml +++ b/.buildkite/ftr_configs.yml @@ -115,9 +115,15 @@ enabled: - test/functional/apps/discover/classic/config.ts - test/functional/apps/discover/embeddable/config.ts - test/functional/apps/discover/group1/config.ts - - test/functional/apps/discover/group2/config.ts + - test/functional/apps/discover/group2_data_grid1/config.ts + - test/functional/apps/discover/group2_data_grid2/config.ts + - test/functional/apps/discover/group2_data_grid3/config.ts - test/functional/apps/discover/group3/config.ts - test/functional/apps/discover/group4/config.ts + - test/functional/apps/discover/group5/config.ts + - test/functional/apps/discover/group6/config.ts + - test/functional/apps/discover/group7/config.ts + - test/functional/apps/discover/group8/config.ts - test/functional/apps/getting_started/config.ts - test/functional/apps/home/config.ts - test/functional/apps/kibana_overview/config.ts diff --git a/test/functional/apps/discover/group1/index.ts b/test/functional/apps/discover/group1/index.ts index 375954797c3ca..2ca6413a11c22 100644 --- a/test/functional/apps/discover/group1/index.ts +++ b/test/functional/apps/discover/group1/index.ts @@ -20,23 +20,13 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); }); - loadTestFile(require.resolve('./_no_data')); loadTestFile(require.resolve('./_discover')); loadTestFile(require.resolve('./_discover_accessibility')); loadTestFile(require.resolve('./_discover_histogram_breakdown')); loadTestFile(require.resolve('./_discover_histogram')); loadTestFile(require.resolve('./_doc_accessibility')); - loadTestFile(require.resolve('./_filter_editor')); loadTestFile(require.resolve('./_errors')); - loadTestFile(require.resolve('./_field_data')); - loadTestFile(require.resolve('./_field_data_with_fields_api')); - loadTestFile(require.resolve('./_shared_links')); - loadTestFile(require.resolve('./_source_filters')); - loadTestFile(require.resolve('./_large_string')); - loadTestFile(require.resolve('./_greeting_screen')); - loadTestFile(require.resolve('./_inspector')); loadTestFile(require.resolve('./_date_nanos')); loadTestFile(require.resolve('./_date_nanos_mixed')); - loadTestFile(require.resolve('./_url_state')); }); } diff --git a/test/functional/apps/discover/group2/_data_grid.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid.ts rename to test/functional/apps/discover/group2_data_grid1/_data_grid.ts diff --git a/test/functional/apps/discover/group2/_data_grid_context.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_context.ts rename to test/functional/apps/discover/group2_data_grid1/_data_grid_context.ts diff --git a/test/functional/apps/discover/group2/_data_grid_copy_to_clipboard.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_copy_to_clipboard.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_copy_to_clipboard.ts rename to test/functional/apps/discover/group2_data_grid1/_data_grid_copy_to_clipboard.ts diff --git a/test/functional/apps/discover/group2/_data_grid_doc_navigation.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_navigation.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_doc_navigation.ts rename to test/functional/apps/discover/group2_data_grid1/_data_grid_doc_navigation.ts diff --git a/test/functional/apps/discover/group2/_data_grid_doc_table.ts b/test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_doc_table.ts rename to test/functional/apps/discover/group2_data_grid1/_data_grid_doc_table.ts diff --git a/test/functional/apps/discover/group2/config.ts b/test/functional/apps/discover/group2_data_grid1/config.ts similarity index 100% rename from test/functional/apps/discover/group2/config.ts rename to test/functional/apps/discover/group2_data_grid1/config.ts diff --git a/test/functional/apps/discover/group2/index.ts b/test/functional/apps/discover/group2_data_grid1/index.ts similarity index 67% rename from test/functional/apps/discover/group2/index.ts rename to test/functional/apps/discover/group2_data_grid1/index.ts index 2639601e12c17..c9e9e9739337a 100644 --- a/test/functional/apps/discover/group2/index.ts +++ b/test/functional/apps/discover/group2_data_grid1/index.ts @@ -11,7 +11,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const browser = getService('browser'); - describe('discover/group2', function () { + describe('discover/group2/data_grid1', function () { before(async function () { await browser.setWindowSize(1600, 1200); }); @@ -22,16 +22,8 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_data_grid')); loadTestFile(require.resolve('./_data_grid_context')); - loadTestFile(require.resolve('./_data_grid_field_data')); loadTestFile(require.resolve('./_data_grid_doc_navigation')); - loadTestFile(require.resolve('./_data_grid_row_navigation')); loadTestFile(require.resolve('./_data_grid_doc_table')); loadTestFile(require.resolve('./_data_grid_copy_to_clipboard')); - loadTestFile(require.resolve('./_data_grid_row_height')); - loadTestFile(require.resolve('./_data_grid_new_line')); - loadTestFile(require.resolve('./_data_grid_sample_size')); - loadTestFile(require.resolve('./_data_grid_pagination')); - loadTestFile(require.resolve('./_data_grid_footer')); - loadTestFile(require.resolve('./_data_grid_field_tokens')); }); } diff --git a/test/functional/apps/discover/group2/_data_grid_field_data.ts b/test/functional/apps/discover/group2_data_grid2/_data_grid_field_data.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_field_data.ts rename to test/functional/apps/discover/group2_data_grid2/_data_grid_field_data.ts diff --git a/test/functional/apps/discover/group2/_data_grid_field_tokens.ts b/test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_field_tokens.ts rename to test/functional/apps/discover/group2_data_grid2/_data_grid_field_tokens.ts diff --git a/test/functional/apps/discover/group2/_data_grid_footer.ts b/test/functional/apps/discover/group2_data_grid2/_data_grid_footer.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_footer.ts rename to test/functional/apps/discover/group2_data_grid2/_data_grid_footer.ts diff --git a/test/functional/apps/discover/group2/_data_grid_new_line.ts b/test/functional/apps/discover/group2_data_grid2/_data_grid_new_line.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_new_line.ts rename to test/functional/apps/discover/group2_data_grid2/_data_grid_new_line.ts diff --git a/test/functional/apps/discover/group2_data_grid2/config.ts b/test/functional/apps/discover/group2_data_grid2/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group2_data_grid2/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group2_data_grid2/index.ts b/test/functional/apps/discover/group2_data_grid2/index.ts new file mode 100644 index 0000000000000..1d3736cafe80b --- /dev/null +++ b/test/functional/apps/discover/group2_data_grid2/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group2/data_grid2', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_data_grid_new_line')); + loadTestFile(require.resolve('./_data_grid_footer')); + loadTestFile(require.resolve('./_data_grid_field_data')); + loadTestFile(require.resolve('./_data_grid_field_tokens')); + }); +} diff --git a/test/functional/apps/discover/group2/_data_grid_pagination.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_pagination.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_pagination.ts rename to test/functional/apps/discover/group2_data_grid3/_data_grid_pagination.ts diff --git a/test/functional/apps/discover/group2/_data_grid_row_height.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_row_height.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_row_height.ts rename to test/functional/apps/discover/group2_data_grid3/_data_grid_row_height.ts diff --git a/test/functional/apps/discover/group2/_data_grid_row_navigation.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_row_navigation.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_row_navigation.ts rename to test/functional/apps/discover/group2_data_grid3/_data_grid_row_navigation.ts diff --git a/test/functional/apps/discover/group2/_data_grid_sample_size.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_sample_size.ts similarity index 100% rename from test/functional/apps/discover/group2/_data_grid_sample_size.ts rename to test/functional/apps/discover/group2_data_grid3/_data_grid_sample_size.ts diff --git a/test/functional/apps/discover/group2_data_grid3/config.ts b/test/functional/apps/discover/group2_data_grid3/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group2_data_grid3/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group2_data_grid3/index.ts b/test/functional/apps/discover/group2_data_grid3/index.ts new file mode 100644 index 0000000000000..7200eb1e9bf10 --- /dev/null +++ b/test/functional/apps/discover/group2_data_grid3/index.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group2/data_grid3', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_data_grid_row_navigation')); + loadTestFile(require.resolve('./_data_grid_row_height')); + loadTestFile(require.resolve('./_data_grid_sample_size')); + loadTestFile(require.resolve('./_data_grid_pagination')); + }); +} diff --git a/test/functional/apps/discover/group3/index.ts b/test/functional/apps/discover/group3/index.ts index a80ae44e49801..582710e419a75 100644 --- a/test/functional/apps/discover/group3/index.ts +++ b/test/functional/apps/discover/group3/index.ts @@ -21,14 +21,9 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./_default_columns')); - loadTestFile(require.resolve('./_time_field_column')); loadTestFile(require.resolve('./_drag_drop')); - loadTestFile(require.resolve('./_sidebar')); - loadTestFile(require.resolve('./_sidebar_field_stats')); loadTestFile(require.resolve('./_request_counts')); loadTestFile(require.resolve('./_doc_viewer')); - loadTestFile(require.resolve('./_view_mode_toggle')); - loadTestFile(require.resolve('./_unsaved_changes_badge')); loadTestFile(require.resolve('./_panels_toggle')); loadTestFile(require.resolve('./_lens_vis')); }); diff --git a/test/functional/apps/discover/group4/index.ts b/test/functional/apps/discover/group4/index.ts index 4a145b06cf248..211b4501ed329 100644 --- a/test/functional/apps/discover/group4/index.ts +++ b/test/functional/apps/discover/group4/index.ts @@ -20,22 +20,14 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); }); - loadTestFile(require.resolve('./_indexpattern_without_timefield')); loadTestFile(require.resolve('./_discover_fields_api')); loadTestFile(require.resolve('./_adhoc_data_views')); loadTestFile(require.resolve('./_esql_view')); - loadTestFile(require.resolve('./_indexpattern_with_unmapped_fields')); - loadTestFile(require.resolve('./_runtime_fields_editor')); - loadTestFile(require.resolve('./_huge_fields')); loadTestFile(require.resolve('./_date_nested')); - loadTestFile(require.resolve('./_search_on_page_load')); loadTestFile(require.resolve('./_chart_hidden')); loadTestFile(require.resolve('./_context_encoded_url_params')); - loadTestFile(require.resolve('./_hide_announcements')); loadTestFile(require.resolve('./_data_view_edit')); loadTestFile(require.resolve('./_field_list_new_fields')); - loadTestFile(require.resolve('./_request_cancellation')); - loadTestFile(require.resolve('./_new_search')); loadTestFile(require.resolve('./_document_comparison')); }); } diff --git a/test/functional/apps/discover/group1/_field_data.ts b/test/functional/apps/discover/group5/_field_data.ts similarity index 100% rename from test/functional/apps/discover/group1/_field_data.ts rename to test/functional/apps/discover/group5/_field_data.ts diff --git a/test/functional/apps/discover/group1/_field_data_with_fields_api.ts b/test/functional/apps/discover/group5/_field_data_with_fields_api.ts similarity index 100% rename from test/functional/apps/discover/group1/_field_data_with_fields_api.ts rename to test/functional/apps/discover/group5/_field_data_with_fields_api.ts diff --git a/test/functional/apps/discover/group1/_filter_editor.ts b/test/functional/apps/discover/group5/_filter_editor.ts similarity index 100% rename from test/functional/apps/discover/group1/_filter_editor.ts rename to test/functional/apps/discover/group5/_filter_editor.ts diff --git a/test/functional/apps/discover/group1/_greeting_screen.ts b/test/functional/apps/discover/group5/_greeting_screen.ts similarity index 100% rename from test/functional/apps/discover/group1/_greeting_screen.ts rename to test/functional/apps/discover/group5/_greeting_screen.ts diff --git a/test/functional/apps/discover/group1/_inspector.ts b/test/functional/apps/discover/group5/_inspector.ts similarity index 100% rename from test/functional/apps/discover/group1/_inspector.ts rename to test/functional/apps/discover/group5/_inspector.ts diff --git a/test/functional/apps/discover/group1/_large_string.ts b/test/functional/apps/discover/group5/_large_string.ts similarity index 100% rename from test/functional/apps/discover/group1/_large_string.ts rename to test/functional/apps/discover/group5/_large_string.ts diff --git a/test/functional/apps/discover/group1/_no_data.ts b/test/functional/apps/discover/group5/_no_data.ts similarity index 100% rename from test/functional/apps/discover/group1/_no_data.ts rename to test/functional/apps/discover/group5/_no_data.ts diff --git a/test/functional/apps/discover/group1/_shared_links.ts b/test/functional/apps/discover/group5/_shared_links.ts similarity index 100% rename from test/functional/apps/discover/group1/_shared_links.ts rename to test/functional/apps/discover/group5/_shared_links.ts diff --git a/test/functional/apps/discover/group1/_source_filters.ts b/test/functional/apps/discover/group5/_source_filters.ts similarity index 100% rename from test/functional/apps/discover/group1/_source_filters.ts rename to test/functional/apps/discover/group5/_source_filters.ts diff --git a/test/functional/apps/discover/group1/_url_state.ts b/test/functional/apps/discover/group5/_url_state.ts similarity index 100% rename from test/functional/apps/discover/group1/_url_state.ts rename to test/functional/apps/discover/group5/_url_state.ts diff --git a/test/functional/apps/discover/group5/config.ts b/test/functional/apps/discover/group5/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group5/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group5/index.ts b/test/functional/apps/discover/group5/index.ts new file mode 100644 index 0000000000000..bc875494307d6 --- /dev/null +++ b/test/functional/apps/discover/group5/index.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group5', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_no_data')); + loadTestFile(require.resolve('./_filter_editor')); + loadTestFile(require.resolve('./_field_data')); + loadTestFile(require.resolve('./_field_data_with_fields_api')); + loadTestFile(require.resolve('./_shared_links')); + loadTestFile(require.resolve('./_source_filters')); + loadTestFile(require.resolve('./_large_string')); + loadTestFile(require.resolve('./_greeting_screen')); + loadTestFile(require.resolve('./_inspector')); + loadTestFile(require.resolve('./_url_state')); + }); +} diff --git a/test/functional/apps/discover/group3/_sidebar.ts b/test/functional/apps/discover/group6/_sidebar.ts similarity index 100% rename from test/functional/apps/discover/group3/_sidebar.ts rename to test/functional/apps/discover/group6/_sidebar.ts diff --git a/test/functional/apps/discover/group3/_sidebar_field_stats.ts b/test/functional/apps/discover/group6/_sidebar_field_stats.ts similarity index 100% rename from test/functional/apps/discover/group3/_sidebar_field_stats.ts rename to test/functional/apps/discover/group6/_sidebar_field_stats.ts diff --git a/test/functional/apps/discover/group3/_time_field_column.ts b/test/functional/apps/discover/group6/_time_field_column.ts similarity index 100% rename from test/functional/apps/discover/group3/_time_field_column.ts rename to test/functional/apps/discover/group6/_time_field_column.ts diff --git a/test/functional/apps/discover/group3/_unsaved_changes_badge.ts b/test/functional/apps/discover/group6/_unsaved_changes_badge.ts similarity index 100% rename from test/functional/apps/discover/group3/_unsaved_changes_badge.ts rename to test/functional/apps/discover/group6/_unsaved_changes_badge.ts diff --git a/test/functional/apps/discover/group3/_view_mode_toggle.ts b/test/functional/apps/discover/group6/_view_mode_toggle.ts similarity index 100% rename from test/functional/apps/discover/group3/_view_mode_toggle.ts rename to test/functional/apps/discover/group6/_view_mode_toggle.ts diff --git a/test/functional/apps/discover/group6/config.ts b/test/functional/apps/discover/group6/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group6/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group6/index.ts b/test/functional/apps/discover/group6/index.ts new file mode 100644 index 0000000000000..f71d96e63d2fd --- /dev/null +++ b/test/functional/apps/discover/group6/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group6', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_sidebar')); + loadTestFile(require.resolve('./_sidebar_field_stats')); + loadTestFile(require.resolve('./_time_field_column')); + loadTestFile(require.resolve('./_unsaved_changes_badge')); + loadTestFile(require.resolve('./_view_mode_toggle')); + }); +} diff --git a/test/functional/apps/discover/group4/_huge_fields.ts b/test/functional/apps/discover/group7/_huge_fields.ts similarity index 100% rename from test/functional/apps/discover/group4/_huge_fields.ts rename to test/functional/apps/discover/group7/_huge_fields.ts diff --git a/test/functional/apps/discover/group4/_indexpattern_with_unmapped_fields.ts b/test/functional/apps/discover/group7/_indexpattern_with_unmapped_fields.ts similarity index 100% rename from test/functional/apps/discover/group4/_indexpattern_with_unmapped_fields.ts rename to test/functional/apps/discover/group7/_indexpattern_with_unmapped_fields.ts diff --git a/test/functional/apps/discover/group4/_indexpattern_without_timefield.ts b/test/functional/apps/discover/group7/_indexpattern_without_timefield.ts similarity index 100% rename from test/functional/apps/discover/group4/_indexpattern_without_timefield.ts rename to test/functional/apps/discover/group7/_indexpattern_without_timefield.ts diff --git a/test/functional/apps/discover/group4/_new_search.ts b/test/functional/apps/discover/group7/_new_search.ts similarity index 100% rename from test/functional/apps/discover/group4/_new_search.ts rename to test/functional/apps/discover/group7/_new_search.ts diff --git a/test/functional/apps/discover/group4/_request_cancellation.ts b/test/functional/apps/discover/group7/_request_cancellation.ts similarity index 100% rename from test/functional/apps/discover/group4/_request_cancellation.ts rename to test/functional/apps/discover/group7/_request_cancellation.ts diff --git a/test/functional/apps/discover/group4/_runtime_fields_editor.ts b/test/functional/apps/discover/group7/_runtime_fields_editor.ts similarity index 100% rename from test/functional/apps/discover/group4/_runtime_fields_editor.ts rename to test/functional/apps/discover/group7/_runtime_fields_editor.ts diff --git a/test/functional/apps/discover/group4/_search_on_page_load.ts b/test/functional/apps/discover/group7/_search_on_page_load.ts similarity index 100% rename from test/functional/apps/discover/group4/_search_on_page_load.ts rename to test/functional/apps/discover/group7/_search_on_page_load.ts diff --git a/test/functional/apps/discover/group7/config.ts b/test/functional/apps/discover/group7/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group7/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group7/index.ts b/test/functional/apps/discover/group7/index.ts new file mode 100644 index 0000000000000..3abc84514f15d --- /dev/null +++ b/test/functional/apps/discover/group7/index.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group7', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_indexpattern_without_timefield')); + loadTestFile(require.resolve('./_indexpattern_with_unmapped_fields')); + loadTestFile(require.resolve('./_runtime_fields_editor')); + loadTestFile(require.resolve('./_huge_fields')); + loadTestFile(require.resolve('./_search_on_page_load')); + loadTestFile(require.resolve('./_request_cancellation')); + loadTestFile(require.resolve('./_new_search')); + }); +} diff --git a/test/functional/apps/discover/group4/_hide_announcements.ts b/test/functional/apps/discover/group8/_hide_announcements.ts similarity index 100% rename from test/functional/apps/discover/group4/_hide_announcements.ts rename to test/functional/apps/discover/group8/_hide_announcements.ts diff --git a/test/functional/apps/discover/group8/config.ts b/test/functional/apps/discover/group8/config.ts new file mode 100644 index 0000000000000..a70a190ca63f8 --- /dev/null +++ b/test/functional/apps/discover/group8/config.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 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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/test/functional/apps/discover/group8/index.ts b/test/functional/apps/discover/group8/index.ts new file mode 100644 index 0000000000000..09aaca23e8b95 --- /dev/null +++ b/test/functional/apps/discover/group8/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { FtrProviderContext } from '../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group8', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_hide_announcements')); + }); +} diff --git a/test/functional/firefox/discover.config.ts b/test/functional/firefox/discover.config.ts index 8b7e7205cd434..5c9f9c0939754 100644 --- a/test/functional/firefox/discover.config.ts +++ b/test/functional/firefox/discover.config.ts @@ -19,9 +19,15 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { testFiles: [ require.resolve('../apps/discover/classic'), require.resolve('../apps/discover/group1'), - require.resolve('../apps/discover/group2'), + require.resolve('../apps/discover/group2_data_grid1'), + require.resolve('../apps/discover/group2_data_grid2'), + require.resolve('../apps/discover/group2_data_grid3'), require.resolve('../apps/discover/group3'), require.resolve('../apps/discover/group4'), + require.resolve('../apps/discover/group5'), + require.resolve('../apps/discover/group6'), + require.resolve('../apps/discover/group7'), + require.resolve('../apps/discover/group8'), ], junit: { diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts index 4ad60320df38b..9fc6d4447e8c7 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group1/index.ts @@ -22,6 +22,5 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_discover')); loadTestFile(require.resolve('./_discover_histogram')); - loadTestFile(require.resolve('./_url_state')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts index c579eca3bb7bd..658b92845ffca 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group2/index.ts @@ -22,6 +22,5 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_data_grid_doc_navigation')); loadTestFile(require.resolve('./_data_grid_doc_table')); - loadTestFile(require.resolve('./_adhoc_data_views')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts index 9f322013d986b..70d95fef41958 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/index.ts @@ -20,8 +20,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); }); - loadTestFile(require.resolve('./_sidebar')); loadTestFile(require.resolve('./_request_counts')); - loadTestFile(require.resolve('./_unsaved_changes_badge')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group2/_adhoc_data_views.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group4/_adhoc_data_views.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/discover/group2/_adhoc_data_views.ts rename to x-pack/test_serverless/functional/test_suites/common/discover/group4/_adhoc_data_views.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group4/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group4/index.ts new file mode 100644 index 0000000000000..c262798065000 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group4/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group4', function () { + before(async function () { + await browser.setWindowSize(1600, 1200); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_adhoc_data_views')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group1/_url_state.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group5/_url_state.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/discover/group1/_url_state.ts rename to x-pack/test_serverless/functional/test_suites/common/discover/group5/_url_state.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group5/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group5/index.ts new file mode 100644 index 0000000000000..a38a6d4e33dd6 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group5/index.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group5', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_url_state')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_sidebar.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/discover/group3/_sidebar.ts rename to x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_unsaved_changes_badge.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group6/_unsaved_changes_badge.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/common/discover/group3/_unsaved_changes_badge.ts rename to x-pack/test_serverless/functional/test_suites/common/discover/group6/_unsaved_changes_badge.ts diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group6/index.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group6/index.ts new file mode 100644 index 0000000000000..8857ebe9bf310 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group6/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover/group6', function () { + before(async function () { + await browser.setWindowSize(1300, 800); + }); + + after(async function unloadMakelogs() { + await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); + }); + + loadTestFile(require.resolve('./_sidebar')); + loadTestFile(require.resolve('./_unsaved_changes_badge')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts index 7b8fb4b072847..be3c0098d35d2 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts @@ -16,6 +16,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/discover/group1'), require.resolve('../../common/discover/group2'), require.resolve('../../common/discover/group3'), + require.resolve('../../common/discover/group4'), + require.resolve('../../common/discover/group5'), + require.resolve('../../common/discover/group6'), ], junit: { reportName: 'Serverless Observability Functional Tests - Common Group 5', diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts index 70cabf59051a9..ad661b474a33d 100644 --- a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts @@ -16,6 +16,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/discover/group1'), require.resolve('../../common/discover/group2'), require.resolve('../../common/discover/group3'), + require.resolve('../../common/discover/group4'), + require.resolve('../../common/discover/group5'), + require.resolve('../../common/discover/group6'), ], junit: { reportName: 'Serverless Search Functional Tests - Common Group 5', diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts index d1637bf34b4fd..c65131e27e9e8 100644 --- a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts @@ -16,6 +16,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/discover/group1'), require.resolve('../../common/discover/group2'), require.resolve('../../common/discover/group3'), + require.resolve('../../common/discover/group4'), + require.resolve('../../common/discover/group5'), + require.resolve('../../common/discover/group6'), ], junit: { reportName: 'Serverless Security Functional Tests - Common Group 5', From 1eb43c1c797a8a37f1db32e0d611b9a83bd0fb38 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:00:16 +0100 Subject: [PATCH 12/67] skip flaky suite (#170674) --- .../cypress/e2e/response_actions/document_signing.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts index b806323726018..4093581366321 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts @@ -22,7 +22,8 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -describe('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/170674 +describe.skip('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; From fadce7939195ef903f116752db13ddb003eaf1a6 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:01:04 -0400 Subject: [PATCH 13/67] skip failing test suite (#170674) --- .../cypress/e2e/response_actions/document_signing.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts index 4093581366321..ec41ffa31edc9 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/document_signing.cy.ts @@ -23,6 +23,7 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170674 +// Failing: See https://github.com/elastic/kibana/issues/170674 describe.skip('Document signing:', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; From 14bf23cd0e871742da31ffe4f5114ef9ed9d9dda Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:02:26 +0100 Subject: [PATCH 14/67] skip flaky suite (#170811) --- ...t_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts index 3d92528c2eee7..dfa36e67bb030 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts @@ -22,7 +22,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170811 +describe.skip( 'Unenroll agent from fleet when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, () => { From 95f9163ddb6a194a1d6b9fe882e6abb2544e3744 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:03:06 -0400 Subject: [PATCH 15/67] skip failing test suite (#170811) --- ...ent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts index dfa36e67bb030..03eef1c4337c2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_disabled_to_enabled.cy.ts @@ -23,6 +23,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170811 +// Failing: See https://github.com/elastic/kibana/issues/170811 describe.skip( 'Unenroll agent from fleet when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, From 19f6fc1d1906e7b98874f00812c58c601adba58d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:03:37 -0400 Subject: [PATCH 16/67] skip failing test suite (#169821) --- .../e2e/response_actions/endpoints_list_response_console.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts index 75074b0d3f94a..10a8908684577 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/endpoints_list_response_console.cy.ts @@ -20,7 +20,8 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/169821 +describe.skip('Response console', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { beforeEach(() => { login(); }); From fefe90889fa02b5e1c05682d3303d7fd40fc1da1 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:05:01 +0100 Subject: [PATCH 17/67] skip flaky suite (#170817) --- ...t_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts index a9508a13f719b..7ffc7b39c373b 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts @@ -22,7 +22,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170817 +describe.skip( 'Unenroll agent from fleet changing when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, () => { From 4ba1be2b306baef0329d70710df60cff181e5fcc Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:05:35 -0400 Subject: [PATCH 18/67] skip failing test suite (#170817) --- ...ent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts index 7ffc7b39c373b..b36f7eca756e2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_disabled.cy.ts @@ -23,6 +23,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170817 +// Failing: See https://github.com/elastic/kibana/issues/170817 describe.skip( 'Unenroll agent from fleet changing when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, From 5f51e05ffe561524c65314e6bd6145368be4a57c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:06:23 +0100 Subject: [PATCH 19/67] skip flaky suite (#170816) --- ...nt_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts index a5654734c15e4..bacea254e34c3 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts @@ -21,7 +21,8 @@ import { login } from '../../../tasks/login'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170816 +describe.skip( 'Unenroll agent from fleet changing agent policy when agent tamper protection is enabled but then is switched to a policy with it also enabled', { tags: ['@ess'] }, () => { From f5877fada114a443f3e699c370ed4cb8a96f6c4a Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:06:59 -0400 Subject: [PATCH 20/67] skip failing test suite (#170816) --- ...gent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts index bacea254e34c3..414f18fb1fac7 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/unenroll_agent_from_fleet_changing_policy_from_enabled_to_enabled.cy.ts @@ -22,6 +22,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170816 +// Failing: See https://github.com/elastic/kibana/issues/170816 describe.skip( 'Unenroll agent from fleet changing agent policy when agent tamper protection is enabled but then is switched to a policy with it also enabled', { tags: ['@ess'] }, From d11a5e77f67a05dfd5ab5cfaac683b9ee457493c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:08:17 +0100 Subject: [PATCH 21/67] skip flaky suite (#170601) --- .../tamper_protection/enabled/uninstall_agent_from_host.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts index 527566bed608b..8f45e3d70b5e6 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts @@ -22,7 +22,8 @@ import { login } from '../../../tasks/login'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170601 +describe.skip( 'Uninstall agent from host when agent tamper protection is enabled', { tags: ['@ess'] }, () => { From 8d79cebadec8e492f252b9a786507472ac5874ee Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:08:53 -0400 Subject: [PATCH 22/67] skip failing test suite (#170601) --- .../tamper_protection/enabled/uninstall_agent_from_host.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts index 8f45e3d70b5e6..7cbcaf361a38c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/uninstall_agent_from_host.cy.ts @@ -23,6 +23,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170601 +// Failing: See https://github.com/elastic/kibana/issues/170601 describe.skip( 'Uninstall agent from host when agent tamper protection is enabled', { tags: ['@ess'] }, From 33c6a6b01f515be7035411171996ff1b4b896c31 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:10:51 +0100 Subject: [PATCH 23/67] skip flaky suite (#179598) --- .../cypress/e2e/response_actions/alerts_response_console.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts index 63428ec6018d2..a9b9dc0c1f1a3 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts @@ -27,7 +27,8 @@ import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/179598 +describe.skip( 'Response console: From Alerts', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, () => { From 13bf1b02118c0cd5b7a64650a88355dbbbf1e25b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:11:25 -0400 Subject: [PATCH 24/67] skip failing test suite (#179598) --- .../cypress/e2e/response_actions/alerts_response_console.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts index a9b9dc0c1f1a3..db1477916f75a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/alerts_response_console.cy.ts @@ -28,6 +28,7 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/179598 +// Failing: See https://github.com/elastic/kibana/issues/179598 describe.skip( 'Response console: From Alerts', { tags: ['@ess', '@serverless', '@brokenInServerless'] }, From 5b92a879577149f4b35d8701b1690e87bf4da5d8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:12:09 +0100 Subject: [PATCH 25/67] skip flaky suite (#170563) --- .../response_actions/response_console/process_operations.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts index f7c70ebf8c7e9..0f6da6fb9fad1 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/process_operations.cy.ts @@ -26,7 +26,8 @@ import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_ const AGENT_BEAT_FILE_PATH_SUFFIX = '/components/agentbeat'; -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/170563 +describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); }); From 0fdc7ecaf1708a8bf2dd74ed92d26578f35f5808 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:13:25 +0100 Subject: [PATCH 26/67] skip flaky suite (#172326) --- .../e2e/response_actions/response_console/release.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts index 47d30ad96699c..d4c72699efd32 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts @@ -27,7 +27,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/172326 +describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; From 0702f99e8ba24ad57e4cb5bd2935ffa2c8a8435b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:14:27 -0400 Subject: [PATCH 27/67] skip failing test suite (#172326) --- .../cypress/e2e/response_actions/response_console/release.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts index d4c72699efd32..50630b8fc1b46 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/release.cy.ts @@ -28,6 +28,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/172326 +// Failing: See https://github.com/elastic/kibana/issues/172326 describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; From c72c714ed36ff30eb65a1114c08061cc2455f639 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:16:19 +0100 Subject: [PATCH 28/67] skip flaky suite (#168340) --- .../automated_response_actions.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts index adaaf9c99059a..30a961858b52c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts @@ -20,7 +20,8 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/168340 +describe.skip( 'Automated Response Actions', { tags: ['@ess', '@serverless'], From dff298da4a88d3d2b1416b38142aed417c645a47 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:16:56 -0400 Subject: [PATCH 29/67] skip failing test suite (#168340) --- .../automated_response_actions/automated_response_actions.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts index 30a961858b52c..c295de7dd0b3e 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/automated_response_actions/automated_response_actions.cy.ts @@ -21,6 +21,7 @@ import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_dat import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; // FLAKY: https://github.com/elastic/kibana/issues/168340 +// Failing: See https://github.com/elastic/kibana/issues/168340 describe.skip( 'Automated Response Actions', { From 971c08e537f52d32e6976be965230069bdc88b9a Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:17:18 +0100 Subject: [PATCH 30/67] skip flaky suite (#170424) --- .../response_actions/response_console/file_operations.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts index 70b008f7eda7b..38f442dec0e63 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/file_operations.cy.ts @@ -21,7 +21,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/170424 +describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); }); From 7e4082243dffba5f958d9dc317d642c78526a97e Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:18:40 +0100 Subject: [PATCH 31/67] skip flaky suite (#169958) --- .../public/management/cypress/e2e/endpoint_alerts.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts index 06b33141bad1b..e4f913d851735 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts @@ -19,7 +19,8 @@ import { login, ROLE } from '../tasks/login'; import { EXECUTE_ROUTE } from '../../../../common/endpoint/constants'; import { waitForActionToComplete } from '../tasks/response_actions'; -describe('Endpoint generated alerts', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/169958 +describe.skip('Endpoint generated alerts', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; From 0dae7073f256a5e562a1580fd447b6b52f48845c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:20:01 -0400 Subject: [PATCH 32/67] skip failing test suite (#169958) --- .../public/management/cypress/e2e/endpoint_alerts.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts index e4f913d851735..2de94b7ca0557 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_alerts.cy.ts @@ -20,6 +20,7 @@ import { EXECUTE_ROUTE } from '../../../../common/endpoint/constants'; import { waitForActionToComplete } from '../tasks/response_actions'; // FLAKY: https://github.com/elastic/kibana/issues/169958 +// Failing: See https://github.com/elastic/kibana/issues/169958 describe.skip('Endpoint generated alerts', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; From c630c7f21b9b860930f780723a5a85dd9f372ec4 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:21:48 +0100 Subject: [PATCH 33/67] skip flaky suite (#168284) --- .../management/cypress/e2e/endpoint_list/endpoints.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts index 4396937e57228..0aeb46b32fb43 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts @@ -28,7 +28,8 @@ import { createEndpointHost } from '../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_data'; import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; -describe('Endpoints page', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/168284 +describe.skip('Endpoints page', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; let createdHost: CreateAndEnrollEndpointHostResponse; From bac14aa30bb8a590b9be3005a3018211f0d4a303 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:22:25 -0400 Subject: [PATCH 34/67] skip failing test suite (#168284) --- .../public/management/cypress/e2e/endpoint_list/endpoints.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts index 0aeb46b32fb43..c0b12f6bd700c 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/endpoint_list/endpoints.cy.ts @@ -29,6 +29,7 @@ import { deleteAllLoadedEndpointData } from '../../tasks/delete_all_endpoint_dat import { enableAllPolicyProtections } from '../../tasks/endpoint_policy'; // FLAKY: https://github.com/elastic/kibana/issues/168284 +// Failing: See https://github.com/elastic/kibana/issues/168284 describe.skip('Endpoints page', { tags: ['@ess', '@serverless'] }, () => { let indexedPolicy: IndexedFleetEndpointPolicyResponse; let policy: PolicyData; From 55556e252bffbe9f69023c65bd9ce6144fb9a88c Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:22:44 +0100 Subject: [PATCH 35/67] skip flaky suite (#170812) --- ...ent_from_host_changing_policy_from_enabled_to_enabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts index d8630a50a83b9..f2397225a10a1 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts @@ -23,7 +23,8 @@ import { login } from '../../../tasks/login'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170812 +describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is enabled but then is switched to a policy with it also enabled', { tags: ['@ess'] }, () => { From 520f06320c362679298dab57d6c006563dfd48a6 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:23:17 -0400 Subject: [PATCH 36/67] skip failing test suite (#170812) --- ...agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts index f2397225a10a1..d0b16f5b757ff 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_enabled.cy.ts @@ -24,6 +24,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170812 +// Failing: See https://github.com/elastic/kibana/issues/170812 describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is enabled but then is switched to a policy with it also enabled', { tags: ['@ess'] }, From f77d3c9b7b1adb3e7b5f7b7576391e9d005bf96d Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:24:23 +0100 Subject: [PATCH 37/67] skip flaky suite (#170373) --- .../e2e/response_actions/response_console/execute.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts index dad573bb09c2b..d43037f4d7f97 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/response_actions/response_console/execute.cy.ts @@ -21,7 +21,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe('Response console', { tags: ['@ess', '@serverless'] }, () => { +// FLAKY: https://github.com/elastic/kibana/issues/170373 +describe.skip('Response console', { tags: ['@ess', '@serverless'] }, () => { beforeEach(() => { login(); }); From fb9c906d48bd7e626ee310e8fe67e9c242d581d8 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:28:08 +0100 Subject: [PATCH 38/67] skip flaky suite (#170667) --- .../tamper_protection/disabled/uninstall_agent_from_host.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts index ed47855ac894a..34aba3fcfccf2 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts @@ -21,7 +21,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170667 +describe.skip( 'Uninstall agent from host when agent tamper protection is disabled', { tags: ['@ess'] }, () => { From b8e8b5ebfec650d145ec868328aedbb861e8bf1c Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:28:41 -0400 Subject: [PATCH 39/67] skip failing test suite (#170667) --- .../tamper_protection/disabled/uninstall_agent_from_host.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts index 34aba3fcfccf2..a32932e0ed508 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/uninstall_agent_from_host.cy.ts @@ -22,6 +22,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170667 +// Failing: See https://github.com/elastic/kibana/issues/170667 describe.skip( 'Uninstall agent from host when agent tamper protection is disabled', { tags: ['@ess'] }, From 908a3cd3dadf9645b9e34443be83965df1b42c47 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:29:11 +0100 Subject: [PATCH 40/67] skip flaky suite (#170604) --- ...nt_from_host_changing_policy_from_enabled_to_disabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts index 0768c4a49ca39..f5665d830eb4a 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts @@ -23,7 +23,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170604 +describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, () => { From afaae2c961a457b4d60d249cc184656639c839ee Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:29:41 -0400 Subject: [PATCH 41/67] skip failing test suite (#170604) --- ...gent_from_host_changing_policy_from_enabled_to_disabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts index f5665d830eb4a..665e51ea56da5 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_enabled_to_disabled.cy.ts @@ -24,6 +24,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170604 +// Failing: See https://github.com/elastic/kibana/issues/170604 describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is enabled but then is switched to a policy with it disabled', { tags: ['@ess'] }, From b9902f6f223148859f3d28173641fcb979adf3ca Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:31:13 +0100 Subject: [PATCH 42/67] skip flaky suite (#170794) --- ...nt_from_host_changing_policy_from_disabled_to_enabled.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts index bbb675cf56d5e..6e09cd0301f9b 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts @@ -24,7 +24,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170794 +describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, () => { From b0962bc124494806510b2746ee81eb75f34ef0f7 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:31:45 -0400 Subject: [PATCH 43/67] skip failing test suite (#170794) --- ...gent_from_host_changing_policy_from_disabled_to_enabled.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts index 6e09cd0301f9b..d256fb2f990b3 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/switching_policies/uninstall_agent_from_host_changing_policy_from_disabled_to_enabled.cy.ts @@ -25,6 +25,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170794 +// Failing: See https://github.com/elastic/kibana/issues/170794 describe.skip( 'Uninstall agent from host changing agent policy when agent tamper protection is disabled but then is switched to a policy with it enabled', { tags: ['@ess'] }, From 5e9042dd9d12be582f1cb6d7dfcabe9cf43ecefe Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:32:23 +0100 Subject: [PATCH 44/67] skip flaky suite (#170814) --- .../tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts index e0b26bc2f77dd..3edf2d1327d74 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts @@ -20,7 +20,8 @@ import { enableAllPolicyProtections } from '../../../tasks/endpoint_policy'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170814 +describe.skip( 'Unenroll agent from fleet with agent tamper protection is disabled', { tags: ['@ess'] }, () => { From 0a8fcc9d8d91eed1e0ed5531c0f9ab7368facf23 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:33:13 -0400 Subject: [PATCH 45/67] skip failing test suite (#170814) --- .../tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts index 3edf2d1327d74..3a35f49d0ddcf 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/disabled/unenroll_agent_from_fleet.cy.ts @@ -21,6 +21,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170814 +// Failing: See https://github.com/elastic/kibana/issues/170814 describe.skip( 'Unenroll agent from fleet with agent tamper protection is disabled', { tags: ['@ess'] }, From 7fd9faec4b0815f3dbd2a3f03d5b2f18cf852d58 Mon Sep 17 00:00:00 2001 From: Tiago Costa Date: Wed, 24 Apr 2024 18:33:47 +0100 Subject: [PATCH 46/67] skip flaky suite (#170706) --- .../tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts index 17cb52c2cb042..f2aef24ad5e12 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts @@ -20,7 +20,8 @@ import { login } from '../../../tasks/login'; import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; -describe( +// FLAKY: https://github.com/elastic/kibana/issues/170706 +describe.skip( 'Unenroll agent from fleet when agent tamper protection is enabled', { tags: ['@ess'] }, () => { From 2b2fe3903b8cc21c77b6304340285d47693f8a60 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 24 Apr 2024 13:34:17 -0400 Subject: [PATCH 47/67] skip failing test suite (#170706) --- .../tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts index f2aef24ad5e12..61af90092c06d 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/e2e/tamper_protection/enabled/unenroll_agent_from_fleet.cy.ts @@ -21,6 +21,7 @@ import { createEndpointHost } from '../../../tasks/create_endpoint_host'; import { deleteAllLoadedEndpointData } from '../../../tasks/delete_all_endpoint_data'; // FLAKY: https://github.com/elastic/kibana/issues/170706 +// Failing: See https://github.com/elastic/kibana/issues/170706 describe.skip( 'Unenroll agent from fleet when agent tamper protection is enabled', { tags: ['@ess'] }, From 6d06a565b79249f81f868a9d494fea5cf6903989 Mon Sep 17 00:00:00 2001 From: Rodney Norris Date: Wed, 24 Apr 2024 13:23:10 -0500 Subject: [PATCH 48/67] [Console] Allow persistent console to be resizable (#180985) ## Summary Updates the Persistent console to be resizable by the user using an `EuiResizableButton` at the top of the console flyout. - Persistent console now defaults to the maximum size for the window - Top of console can be dragged to resize - On resize console size is saved to local storage and used as default - Double-clicking resize border will maximize console, or set it to 50% height if currently at the max height. https://github.com/elastic/kibana/assets/1972968/46c8da24-56c8-4bda-82f9-f9498ec209a0 --- .../embeddable/_embeddable_console.scss | 47 +----- .../containers/embeddable/_variables.scss | 7 - .../embeddable/console_resize_button.tsx | 142 ++++++++++++++++++ .../containers/embeddable/console_wrapper.tsx | 14 +- .../embeddable/embeddable_console.tsx | 96 ++++++++---- .../containers/embeddable/index.tsx | 7 +- src/plugins/console/public/index.ts | 1 - src/plugins/console/public/plugin.ts | 27 +++- .../services/embeddable_console.test.ts | 31 +++- .../public/services/embeddable_console.ts | 20 +++ .../public/types/embeddable_console.ts | 12 +- .../public/types/plugin_dependencies.ts | 4 +- 12 files changed, 297 insertions(+), 111 deletions(-) create mode 100644 src/plugins/console/public/application/containers/embeddable/console_resize_button.tsx diff --git a/src/plugins/console/public/application/containers/embeddable/_embeddable_console.scss b/src/plugins/console/public/application/containers/embeddable/_embeddable_console.scss index d7fa11e89f72d..8c00712bdaadc 100644 --- a/src/plugins/console/public/application/containers/embeddable/_embeddable_console.scss +++ b/src/plugins/console/public/application/containers/embeddable/_embeddable_console.scss @@ -38,24 +38,9 @@ animation-duration: $euiAnimSpeedNormal; animation-timing-function: $euiAnimSlightResistance; animation-fill-mode: forwards; - } - - &-isOpen.embeddableConsole--large { - animation-name: embeddableConsoleOpenPanelLarge; - height: $embeddableConsoleMaxHeight; - bottom: map-get($embeddableConsoleHeights, 'l') * -1; - } - - &-isOpen.embeddableConsole--medium { - animation-name: embeddableConsoleOpenPanelMedium; - height: map-get($embeddableConsoleHeights, 'm'); - bottom: map-get($embeddableConsoleHeights, 'm') * -1; - } - - &-isOpen.embeddableConsole--small { - animation-name: embeddableConsoleOpenPanelSmall; - height: map-get($embeddableConsoleHeights, 's'); - bottom: map-get($embeddableConsoleHeights, 's') * -1; + animation-name: embeddableConsoleOpenPanel; + height: var(--embedded-console-height); + bottom: var(--embedded-console-bottom); } } @@ -80,7 +65,6 @@ &--altViewButton-container { margin-left: auto; - // padding: $euiSizeS; } } @@ -132,34 +116,13 @@ } } -@keyframes embeddableConsoleOpenPanelLarge { - 0% { - // Accounts for the initial height offset from the top - transform: translateY(calc((#{$embeddableConsoleInitialHeight} * 3) * -1)); - } - - 100% { - transform: translateY(map-get($embeddableConsoleHeights, 'l') * -1); - } -} - -@keyframes embeddableConsoleOpenPanelMedium { - 0% { - transform: translateY(-$embeddableConsoleInitialHeight); - } - - 100% { - transform: translateY(map-get($embeddableConsoleHeights, 'm') * -1); - } -} - -@keyframes embeddableConsoleOpenPanelSmall { +@keyframes embeddableConsoleOpenPanel { 0% { transform: translateY(-$embeddableConsoleInitialHeight); } 100% { - transform: translateY(map-get($embeddableConsoleHeights, 's') * -1); + transform: translateY(var(--embedded-console-bottom)); } } diff --git a/src/plugins/console/public/application/containers/embeddable/_variables.scss b/src/plugins/console/public/application/containers/embeddable/_variables.scss index 33ecd64b999c9..9623db93b4ea7 100644 --- a/src/plugins/console/public/application/containers/embeddable/_variables.scss +++ b/src/plugins/console/public/application/containers/embeddable/_variables.scss @@ -3,10 +3,3 @@ $embeddableConsoleText: lighten(makeHighContrastColor($euiColorLightestShade, $e $embeddableConsoleBorderColor: transparentize($euiColorGhost, .8); $embeddableConsoleInitialHeight: $euiSizeXXL; $embeddableConsoleMaxHeight: calc(100vh - var(--euiFixedHeadersOffset, 0)); - -// Pixel heights ensure no blurriness caused by half pixel offsets -$embeddableConsoleHeights: ( - s: $euiSize * 30, - m: $euiSize * 50, - l: 100vh, -); diff --git a/src/plugins/console/public/application/containers/embeddable/console_resize_button.tsx b/src/plugins/console/public/application/containers/embeddable/console_resize_button.tsx new file mode 100644 index 0000000000000..0b29214594440 --- /dev/null +++ b/src/plugins/console/public/application/containers/embeddable/console_resize_button.tsx @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { useCallback, useEffect, useState, useRef } from 'react'; +import { EuiResizableButton, useEuiTheme, keys, EuiThemeComputed } from '@elastic/eui'; + +const CONSOLE_MIN_HEIGHT = 200; + +const getMouseOrTouchY = ( + e: TouchEvent | MouseEvent | React.MouseEvent | React.TouchEvent +): number => { + // Some Typescript fooling is needed here + const y = (e as TouchEvent).targetTouches + ? (e as TouchEvent).targetTouches[0].pageY + : (e as MouseEvent).pageY; + return y; +}; + +export interface EmbeddedConsoleResizeButtonProps { + consoleHeight: number; + setConsoleHeight: React.Dispatch>; +} + +export function getCurrentConsoleMaxSize(euiTheme: EuiThemeComputed<{}>) { + const euiBaseSize = parseInt(euiTheme.size.base, 10); + const winHeight = window.innerHeight; + const bodyStyle = getComputedStyle(document.body); + const headerOffset = parseInt(bodyStyle.getPropertyValue('--euiFixedHeadersOffset') ?? '0px', 10); + + // We leave a buffer of baseSize to allow room for the user to hover on the top border for resizing + return Math.max(winHeight - headerOffset - euiBaseSize, CONSOLE_MIN_HEIGHT); +} + +export const EmbeddedConsoleResizeButton = ({ + consoleHeight, + setConsoleHeight, +}: EmbeddedConsoleResizeButtonProps) => { + const { euiTheme } = useEuiTheme(); + const [maxConsoleHeight, setMaxConsoleHeight] = useState(800); + const initialConsoleHeight = useRef(consoleHeight); + const initialMouseY = useRef(0); + + useEffect(() => { + function handleResize() { + const newMaxConsoleHeight = getCurrentConsoleMaxSize(euiTheme); + // Calculate and save the console max height. This is the window height minus the header + // offset minuse the base size to allow a small buffer for grabbing the resize button. + if (maxConsoleHeight !== newMaxConsoleHeight) { + setMaxConsoleHeight(newMaxConsoleHeight); + } + if (consoleHeight > newMaxConsoleHeight && newMaxConsoleHeight > CONSOLE_MIN_HEIGHT) { + // When the current console height is greater than the new max height, + // we resize the console to the max height. This will ensure there is not weird + // behavior with the drag resize. + setConsoleHeight(newMaxConsoleHeight); + } + } + + handleResize(); + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, [maxConsoleHeight, euiTheme, consoleHeight, setConsoleHeight]); + const onResizeMouseMove = useCallback( + (e: MouseEvent | TouchEvent) => { + const currentMouseY = getMouseOrTouchY(e); + const mouseOffset = (currentMouseY - initialMouseY.current) * -1; + const changedConsoleHeight = initialConsoleHeight.current + mouseOffset; + + const newConsoleHeight = Math.min( + Math.max(changedConsoleHeight, CONSOLE_MIN_HEIGHT), + maxConsoleHeight + ); + + setConsoleHeight(newConsoleHeight); + }, + [maxConsoleHeight, setConsoleHeight] + ); + const onResizeMouseUp = useCallback( + (e: MouseEvent | TouchEvent) => { + initialMouseY.current = 0; + + window.removeEventListener('mousemove', onResizeMouseMove); + window.removeEventListener('mouseup', onResizeMouseUp); + window.removeEventListener('touchmove', onResizeMouseMove); + window.removeEventListener('touchend', onResizeMouseUp); + }, + [onResizeMouseMove] + ); + const onResizeMouseDown = useCallback( + (e: React.MouseEvent | React.TouchEvent) => { + initialMouseY.current = getMouseOrTouchY(e); + initialConsoleHeight.current = consoleHeight; + + // Window event listeners instead of React events are used + // in case the user's mouse leaves the component + window.addEventListener('mousemove', onResizeMouseMove); + window.addEventListener('mouseup', onResizeMouseUp); + window.addEventListener('touchmove', onResizeMouseMove); + window.addEventListener('touchend', onResizeMouseUp); + }, + [consoleHeight, onResizeMouseUp, onResizeMouseMove] + ); + const onResizeKeyDown = useCallback( + (e: React.KeyboardEvent) => { + const KEYBOARD_OFFSET = 10; + + switch (e.key) { + case keys.ARROW_UP: + e.preventDefault(); // Safari+VO will screen reader navigate off the button otherwise + setConsoleHeight((height) => Math.min(height + KEYBOARD_OFFSET, maxConsoleHeight)); + break; + case keys.ARROW_DOWN: + e.preventDefault(); // Safari+VO will screen reader navigate off the button otherwise + setConsoleHeight((height) => Math.max(height - KEYBOARD_OFFSET, CONSOLE_MIN_HEIGHT)); + } + }, + [maxConsoleHeight, setConsoleHeight] + ); + const onResizeDoubleClick = useCallback(() => { + if (consoleHeight < maxConsoleHeight) { + setConsoleHeight(maxConsoleHeight); + } else { + setConsoleHeight(maxConsoleHeight / 2); + } + }, [consoleHeight, maxConsoleHeight, setConsoleHeight]); + + return ( + + ); +}; diff --git a/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx b/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx index 6429d8894d33c..53c75706b9da0 100644 --- a/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx +++ b/src/plugins/console/public/application/containers/embeddable/console_wrapper.tsx @@ -29,10 +29,9 @@ import { History, Settings, Storage, - createStorage, createHistory, createSettings, - setStorage, + getStorage, } from '../../../services'; import { createUsageTracker } from '../../../services/tracker'; import { MetricsTracker, EmbeddableConsoleDependencies } from '../../../types'; @@ -78,11 +77,7 @@ const loadDependencies = async ( await loadActiveApi(core.http); const autocompleteInfo = getAutocompleteInfo(); - const storage = createStorage({ - engine: window.localStorage, - prefix: 'sense:', - }); - setStorage(storage); + const storage = getStorage(); const history = createHistory({ storage }); const settings = createSettings({ storage }); const objectStorageClient = localStorageObjectClient.create(storage); @@ -107,7 +102,10 @@ const loadDependencies = async ( }; interface ConsoleWrapperProps - extends Omit { + extends Omit< + EmbeddableConsoleDependencies, + 'setDispatch' | 'alternateView' | 'setConsoleHeight' | 'getConsoleHeight' + > { onKeyDown: (this: Window, ev: WindowEventMap['keydown']) => any; } diff --git a/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx b/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx index 218496b9d81ab..42a6c4b0efb92 100644 --- a/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx +++ b/src/plugins/console/public/application/containers/embeddable/embeddable_console.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useReducer, useEffect } from 'react'; +import React, { useReducer, useEffect, useState } from 'react'; import classNames from 'classnames'; import useObservable from 'react-use/lib/useObservable'; import { @@ -14,15 +14,17 @@ import { EuiFocusTrap, EuiPortal, EuiScreenReaderOnly, + EuiThemeComputed, EuiThemeProvider, EuiWindowEvent, keys, + useEuiTheme, + useEuiThemeCSSVariables, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { dynamic } from '@kbn/shared-ux-utility'; import { - EmbeddableConsoleProps, EmbeddableConsoleDependencies, EmbeddableConsoleView, } from '../../../types/embeddable_console'; @@ -31,6 +33,7 @@ import * as store from '../../stores/embeddable_console'; import { setLoadFromParameter, removeLoadFromParameter } from '../../lib/load_from'; import './_index.scss'; +import { EmbeddedConsoleResizeButton, getCurrentConsoleMaxSize } from './console_resize_button'; const KBN_BODY_CONSOLE_CLASS = 'kbnBody--hasEmbeddableConsole'; @@ -42,14 +45,39 @@ const ConsoleWrapper = dynamic(async () => ({ default: (await import('./console_wrapper')).ConsoleWrapper, })); +const getInitialConsoleHeight = ( + getConsoleHeight: EmbeddableConsoleDependencies['getConsoleHeight'], + euiTheme: EuiThemeComputed +) => { + const lastHeight = getConsoleHeight(); + if (lastHeight) { + try { + const value = parseInt(lastHeight, 10); + if (!isNaN(value) && value > 0) { + return value; + } + } catch { + // ignore bad local storage value + } + } + return getCurrentConsoleMaxSize(euiTheme); +}; + export const EmbeddableConsole = ({ - size = 'm', core, usageCollection, setDispatch, alternateView, isMonacoEnabled, -}: EmbeddableConsoleProps & EmbeddableConsoleDependencies) => { + getConsoleHeight, + setConsoleHeight, +}: EmbeddableConsoleDependencies) => { + const { euiTheme } = useEuiTheme(); + const { setGlobalCSSVariables } = useEuiThemeCSSVariables(); + const [consoleHeight, setConsoleHeightState] = useState( + getInitialConsoleHeight(getConsoleHeight, euiTheme) + ); + const [consoleState, consoleDispatch] = useReducer( store.reducer, store.initialValue, @@ -71,6 +99,13 @@ export const EmbeddableConsole = ({ document.body.classList.add(KBN_BODY_CONSOLE_CLASS); return () => document.body.classList.remove(KBN_BODY_CONSOLE_CLASS); }, []); + useEffect(() => { + setGlobalCSSVariables({ + '--embedded-console-height': `${consoleHeight}px`, + '--embedded-console-bottom': `-${consoleHeight}px`, + }); + setConsoleHeight(consoleHeight.toString()); + }, [consoleHeight, setGlobalCSSVariables, setConsoleHeight]); const isOpen = consoleState.view !== EmbeddableConsoleView.Closed; const showConsole = @@ -105,14 +140,10 @@ export const EmbeddableConsole = ({ const classes = classNames('embeddableConsole', { 'embeddableConsole-isOpen': isOpen, - 'embeddableConsole--large': size === 'l', - 'embeddableConsole--medium': size === 'm', - 'embeddableConsole--small': size === 's', 'embeddableConsole--classicChrome': chromeStyle === 'classic', 'embeddableConsole--projectChrome': chromeStyle === 'project', 'embeddableConsole--unknownChrome': chromeStyle === undefined, 'embeddableConsole--fixed': true, - 'embeddableConsole--showOnMobile': false, }); return ( @@ -127,27 +158,36 @@ export const EmbeddableConsole = ({

{landmarkHeading}

-
- - {i18n.translate('console.embeddableConsole.title', { - defaultMessage: 'Console', - })} - - {alternateView && ( -
- -
+
+ {isOpen && ( + )} + +
+ + {i18n.translate('console.embeddableConsole.title', { + defaultMessage: 'Console', + })} + + {alternateView && ( +
+ +
+ )} +
{showConsole ? ( diff --git a/src/plugins/console/public/application/containers/embeddable/index.tsx b/src/plugins/console/public/application/containers/embeddable/index.tsx index 0563a5f445da2..0ec32dbeaac91 100644 --- a/src/plugins/console/public/application/containers/embeddable/index.tsx +++ b/src/plugins/console/public/application/containers/embeddable/index.tsx @@ -8,12 +8,9 @@ import { dynamic } from '@kbn/shared-ux-utility'; import React from 'react'; -import { - EmbeddableConsoleProps, - EmbeddableConsoleDependencies, -} from '../../../types/embeddable_console'; +import { EmbeddableConsoleDependencies } from '../../../types/embeddable_console'; -type EmbeddableConsoleInternalProps = EmbeddableConsoleProps & EmbeddableConsoleDependencies; +type EmbeddableConsoleInternalProps = EmbeddableConsoleDependencies; const Console = dynamic(async () => ({ default: (await import('./embeddable_console')).EmbeddableConsole, })); diff --git a/src/plugins/console/public/index.ts b/src/plugins/console/public/index.ts index 4e907d4329d1e..277190a1a443c 100644 --- a/src/plugins/console/public/index.ts +++ b/src/plugins/console/public/index.ts @@ -17,7 +17,6 @@ export type { ConsoleUILocatorParams, ConsolePluginSetup, ConsolePluginStart, - EmbeddableConsoleProps, EmbeddedConsoleView, EmbeddedConsoleViewButtonProps, } from './types'; diff --git a/src/plugins/console/public/plugin.ts b/src/plugins/console/public/plugin.ts index 43cedf1fa4bb0..54d8d1db97bc7 100644 --- a/src/plugins/console/public/plugin.ts +++ b/src/plugins/console/public/plugin.ts @@ -18,18 +18,30 @@ import { ConsolePluginSetup, ConsolePluginStart, ConsoleUILocatorParams, - EmbeddableConsoleProps, EmbeddedConsoleView, } from './types'; -import { AutocompleteInfo, setAutocompleteInfo, EmbeddableConsoleInfo } from './services'; +import { + AutocompleteInfo, + setAutocompleteInfo, + EmbeddableConsoleInfo, + createStorage, + setStorage, +} from './services'; export class ConsoleUIPlugin implements Plugin { private readonly autocompleteInfo = new AutocompleteInfo(); - private _embeddableConsole: EmbeddableConsoleInfo = new EmbeddableConsoleInfo(); - - constructor(private ctx: PluginInitializerContext) {} + private _embeddableConsole: EmbeddableConsoleInfo; + + constructor(private ctx: PluginInitializerContext) { + const storage = createStorage({ + engine: window.localStorage, + prefix: 'sense:', + }); + setStorage(storage); + this._embeddableConsole = new EmbeddableConsoleInfo(storage); + } public setup( { notifications, getStartServices, http }: CoreSetup, @@ -126,9 +138,8 @@ export class ConsoleUIPlugin embeddedConsoleUiSetting; if (embeddedConsoleAvailable) { - consoleStart.EmbeddableConsole = (props: EmbeddableConsoleProps) => { + consoleStart.EmbeddableConsole = (_props: {}) => { return EmbeddableConsole({ - ...props, core, usageCollection: deps.usageCollection, setDispatch: (d) => { @@ -136,6 +147,8 @@ export class ConsoleUIPlugin }, alternateView: this._embeddableConsole.alternateView, isMonacoEnabled, + getConsoleHeight: this._embeddableConsole.getConsoleHeight.bind(this._embeddableConsole), + setConsoleHeight: this._embeddableConsole.setConsoleHeight.bind(this._embeddableConsole), }); }; consoleStart.isEmbeddedConsoleAvailable = () => diff --git a/src/plugins/console/public/services/embeddable_console.test.ts b/src/plugins/console/public/services/embeddable_console.test.ts index 7df8230b6dbdf..92cc4d8450906 100644 --- a/src/plugins/console/public/services/embeddable_console.test.ts +++ b/src/plugins/console/public/services/embeddable_console.test.ts @@ -6,12 +6,17 @@ * Side Public License, v 1. */ +import { StorageMock } from './storage.mock'; import { EmbeddableConsoleInfo } from './embeddable_console'; describe('EmbeddableConsoleInfo', () => { + jest.useFakeTimers(); + let eConsole: EmbeddableConsoleInfo; + let storage: StorageMock; beforeEach(() => { - eConsole = new EmbeddableConsoleInfo(); + storage = new StorageMock({} as unknown as Storage, 'test'); + eConsole = new EmbeddableConsoleInfo(storage); }); describe('isEmbeddedConsoleAvailable', () => { it('returns true if dispatch has been set', () => { @@ -50,4 +55,28 @@ describe('EmbeddableConsoleInfo', () => { }); }); }); + describe('getConsoleHeight', () => { + it('returns value in storage when found', () => { + storage.get.mockReturnValue('201'); + expect(eConsole.getConsoleHeight()).toEqual('201'); + expect(storage.get).toHaveBeenCalledWith('embeddedConsoleHeight', undefined); + }); + it('returns undefined when not found', () => { + storage.get.mockReturnValue(undefined); + expect(eConsole.getConsoleHeight()).toEqual(undefined); + }); + }); + describe('setConsoleHeight', () => { + it('stores value in storage', () => { + // setConsoleHeight calls are debounced + eConsole.setConsoleHeight('120'); + eConsole.setConsoleHeight('110'); + eConsole.setConsoleHeight('100'); + + jest.runAllTimers(); + + expect(storage.set).toHaveBeenCalledTimes(1); + expect(storage.set).toHaveBeenCalledWith('embeddedConsoleHeight', '100'); + }); + }); }); diff --git a/src/plugins/console/public/services/embeddable_console.ts b/src/plugins/console/public/services/embeddable_console.ts index 91bf086bc3e33..f5e0197ad833b 100644 --- a/src/plugins/console/public/services/embeddable_console.ts +++ b/src/plugins/console/public/services/embeddable_console.ts @@ -6,16 +6,28 @@ * Side Public License, v 1. */ import type { Dispatch } from 'react'; +import { debounce } from 'lodash'; import { EmbeddedConsoleAction as EmbeddableConsoleAction, EmbeddedConsoleView, } from '../types/embeddable_console'; +import { Storage } from '.'; + +const CONSOLE_HEIGHT_KEY = 'embeddedConsoleHeight'; +const CONSOLE_HEIGHT_LOCAL_STORAGE_DEBOUNCE_WAIT_TIME = 500; export class EmbeddableConsoleInfo { private _dispatch: Dispatch | null = null; private _alternateView: EmbeddedConsoleView | undefined; + constructor(private readonly storage: Storage) { + this.setConsoleHeight = debounce( + this.setConsoleHeight.bind(this), + CONSOLE_HEIGHT_LOCAL_STORAGE_DEBOUNCE_WAIT_TIME + ); + } + public get alternateView(): EmbeddedConsoleView | undefined { return this._alternateView; } @@ -38,4 +50,12 @@ export class EmbeddableConsoleInfo { public registerAlternateView(view: EmbeddedConsoleView | null) { this._alternateView = view ?? undefined; } + + public getConsoleHeight(): string | undefined { + return this.storage.get(CONSOLE_HEIGHT_KEY, undefined); + } + + public setConsoleHeight(value: string) { + this.storage.set(CONSOLE_HEIGHT_KEY, value); + } } diff --git a/src/plugins/console/public/types/embeddable_console.ts b/src/plugins/console/public/types/embeddable_console.ts index 07a801c40287b..9a31e0f1cf151 100644 --- a/src/plugins/console/public/types/embeddable_console.ts +++ b/src/plugins/console/public/types/embeddable_console.ts @@ -10,22 +10,14 @@ import type { CoreStart } from '@kbn/core/public'; import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public'; import type { Dispatch } from 'react'; -/** - * EmbeddableConsoleProps are optional props used when rendering the embeddable developer console. - */ -export interface EmbeddableConsoleProps { - /** - * The default height of the content area. - */ - size?: 's' | 'm' | 'l'; -} - export interface EmbeddableConsoleDependencies { core: CoreStart; usageCollection?: UsageCollectionStart; setDispatch: (dispatch: Dispatch | null) => void; alternateView?: EmbeddedConsoleView; isMonacoEnabled: boolean; + getConsoleHeight: () => string | undefined; + setConsoleHeight: (value: string) => void; } export type EmbeddedConsoleAction = diff --git a/src/plugins/console/public/types/plugin_dependencies.ts b/src/plugins/console/public/types/plugin_dependencies.ts index 03db14c181be8..63446135e7f3c 100644 --- a/src/plugins/console/public/types/plugin_dependencies.ts +++ b/src/plugins/console/public/types/plugin_dependencies.ts @@ -13,7 +13,7 @@ import { UsageCollectionSetup, UsageCollectionStart } from '@kbn/usage-collectio import { SharePluginSetup, SharePluginStart, LocatorPublic } from '@kbn/share-plugin/public'; import { ConsoleUILocatorParams } from './locator'; -import { EmbeddableConsoleProps, EmbeddedConsoleView } from './embeddable_console'; +import { EmbeddedConsoleView } from './embeddable_console'; export interface AppSetupUIPluginDependencies { home?: HomePublicPluginSetup; @@ -55,7 +55,7 @@ export interface ConsolePluginStart { /** * EmbeddableConsole is a functional component used to render a portable version of the dev tools console on any page in Kibana */ - EmbeddableConsole?: FC; + EmbeddableConsole?: FC<{}>; /** * Register an alternate view for the Embedded Console * From 7d13fbadea35072d07f6a4ca39b2460ee90d1a3a Mon Sep 17 00:00:00 2001 From: Saarika Bhasi <55930906+saarikabhasi@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:26:42 -0400 Subject: [PATCH 49/67] [Serverless Search] add readOnly and writeOnly privileges button in create api key flyout (#181472) ## Summary Add ready only and write only button to show privileges in code editor in`serverless_search` plugin in API key section https://github.com/elastic/kibana/assets/55930906/1e831194-218b-471a-9fd7-7737755e2c85 ### Checklist - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [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 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../api_key/security_privileges_form.tsx | 77 ++++++++++++++++++- .../page_objects/svl_search_landing_page.ts | 2 + 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx b/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx index dcc301469837a..c647471f90e71 100644 --- a/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/api_key/security_privileges_form.tsx @@ -5,22 +5,51 @@ * 2.0. */ -import { EuiText, EuiLink, EuiSpacer } from '@elastic/eui'; +import { + EuiText, + EuiLink, + EuiSpacer, + EuiPanel, + EuiFlexItem, + EuiFlexGroup, + EuiButtonEmpty, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { CodeEditorField } from '@kbn/code-editor'; import React from 'react'; import { docLinks } from '../../../../common/doc_links'; - +const READ_ONLY_BOILERPLATE = `{ + "read-only-role": { + "cluster": [], + "indices": [ + { + "names": ["*"], + "privileges": ["read"] + } + ] + } +}`; +const WRITE_ONLY_BOILERPLATE = `{ + "write-only-role": { + "cluster": [], + "indices": [ + { + "names": ["*"], + "privileges": ["write"] + } + ] + } +}`; interface SecurityPrivilegesFormProps { - roleDescriptors: string; onChangeRoleDescriptors: (roleDescriptors: string) => void; error?: React.ReactNode | React.ReactNode[]; + roleDescriptors: string; } export const SecurityPrivilegesForm: React.FC = ({ - roleDescriptors, onChangeRoleDescriptors, error, + roleDescriptors, }) => { return (
@@ -39,6 +68,46 @@ export const SecurityPrivilegesForm: React.FC = ({

{error}

)} + + + + +

+ {i18n.translate('xpack.serverlessSearch.apiKey.privileges.boilerplate.label', { + defaultMessage: 'Replace with boilerplate:', + })} +

+
+
+ + + onChangeRoleDescriptors(READ_ONLY_BOILERPLATE)} + > + {i18n.translate( + 'xpack.serverlessSearch.apiKey.privileges.boilerplate.readOnlyLabel', + { + defaultMessage: 'Read-only', + } + )} + + + + onChangeRoleDescriptors(WRITE_ONLY_BOILERPLATE)} + > + {i18n.translate( + 'xpack.serverlessSearch.apiKey.privileges.boilerplate.writeOnlyLabel', + { + defaultMessage: 'Write-only', + } + )} + + +
+
Date: Wed, 24 Apr 2024 15:33:29 -0400 Subject: [PATCH 50/67] [APM] add filters support to apm latency, throughput, and error rate chart apis (#181359) ## Summary Rational: We'd like to embed APM visualizations across the observability solution, particularly within the SLO alert details page at this time. SLO configuration supports unified search filters. In order to ensure that the data accurately reflects the SLO configuration, API dependencies for APM visualizations must support filters. This PR adds filters support to: 1. `GET /internal/apm/services/{serviceName}/transactions/charts/latency` 2. `GET /internal/apm/services/{serviceName}/throughput` 3. `GET /internal/apm/services/{serviceName}/transactions/charts/error_rate` It is expected that consumers of the filters param send a serialized object containing a `filter` or `must_not` clause to include on the respective ES queries. Internally, it is expected that these objects are created using the `buildQueryFromFilters` helper exposed by `kbn/es-query`, passing the `Filter` object from the unified search `SearchBar` as the the parameter. ### Testing This feature is not yet available in the UI To test, I've added api integration tests for each api, as well as jest tests for any helpers introduced. --- .../get_failed_transaction_rate.ts | 8 +- .../server/routes/default_api_types.test.ts | 42 +++ .../apm/server/routes/default_api_types.ts | 30 +++ .../server/routes/services/get_throughput.ts | 6 +- .../apm/server/routes/services/route.ts | 5 +- .../get_failed_transaction_rate_periods.ts | 4 + .../transactions/get_latency_charts/index.ts | 12 +- .../apm/server/routes/transactions/route.ts | 10 +- .../tests/services/throughput.spec.ts | 245 ++++++++++++++++++ .../tests/transactions/error_rate.spec.ts | 132 ++++++++++ .../tests/transactions/latency.spec.ts | 120 +++++++++ 11 files changed, 606 insertions(+), 8 deletions(-) create mode 100644 x-pack/plugins/observability_solution/apm/server/routes/default_api_types.test.ts diff --git a/x-pack/plugins/observability_solution/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts b/x-pack/plugins/observability_solution/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts index 08448ef50dc4b..4b1ee98c48cd3 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/transaction_groups/get_failed_transaction_rate.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { BoolQuery } from '@kbn/es-query'; import { kqlQuery, rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ApmServiceTransactionDocumentType } from '../../../common/document_type'; import { SERVICE_NAME, TRANSACTION_NAME, TRANSACTION_TYPE } from '../../../common/es_fields/apm'; @@ -22,6 +22,7 @@ import { export async function getFailedTransactionRate({ environment, kuery, + filters, serviceName, transactionTypes, transactionName, @@ -35,6 +36,7 @@ export async function getFailedTransactionRate({ }: { environment: string; kuery: string; + filters?: BoolQuery; serviceName: string; transactionTypes: string[]; transactionName?: string; @@ -62,7 +64,9 @@ export async function getFailedTransactionRate({ ...rangeQuery(startWithOffset, endWithOffset), ...environmentQuery(environment), ...kqlQuery(kuery), + ...(filters?.filter || []), ]; + const mustNot = filters?.must_not || []; const outcomes = getOutcomeAggregation(documentType); @@ -73,7 +77,7 @@ export async function getFailedTransactionRate({ body: { track_total_hits: false, size: 0, - query: { bool: { filter } }, + query: { bool: { filter, must_not: mustNot } }, aggs: { ...outcomes, timeseries: { diff --git a/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.test.ts b/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.test.ts new file mode 100644 index 0000000000000..baeda52f7fc3c --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isLeft } from 'fp-ts/lib/Either'; +import { filtersRt } from './default_api_types'; + +describe('filtersRt', () => { + it('should decode', () => { + const filters = + '{"must_not":[{"term":{"service.name":"myService"}}],"filter":[{"range":{"@timestamp":{"gte":1617273600000,"lte":1617277200000}}}]}'; + const result = filtersRt.decode(filters); + expect(result).toEqual({ + _tag: 'Right', + right: { + should: [], + must: [], + must_not: [{ term: { 'service.name': 'myService' } }], + filter: [{ range: { '@timestamp': { gte: 1617273600000, lte: 1617277200000 } } }], + }, + }); + }); + + it.each(['3', 'true', '{}'])('should not decode invalid filter JSON: %s', (invalidJson) => { + const filters = `{ "filter": ${invalidJson}}`; + const result = filtersRt.decode(filters); + // @ts-ignore-next-line + expect(result.left[0].message).toEqual('filters.filter is not iterable'); + expect(isLeft(result)).toEqual(true); + }); + + it.each(['3', 'true', '{}'])('should not decode invalid must_not JSON: %s', (invalidJson) => { + const filters = `{ "must_not": ${invalidJson}}`; + const result = filtersRt.decode(filters); + // @ts-ignore-next-line + expect(result.left[0].message).toEqual('filters.must_not is not iterable'); + expect(isLeft(result)).toEqual(true); + }); +}); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.ts b/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.ts index a58a5a24af7b5..42ab1b63d431e 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/default_api_types.ts @@ -7,6 +7,8 @@ import * as t from 'io-ts'; import { isoToEpochRt, toNumberRt } from '@kbn/io-ts-utils'; +import { either } from 'fp-ts/lib/Either'; +import { BoolQuery } from '@kbn/es-query'; import { ApmDocumentType } from '../../common/document_type'; import { RollupInterval } from '../../common/rollup'; @@ -48,3 +50,31 @@ export const transactionDataSourceRt = t.type({ t.literal(RollupInterval.None), ]), }); + +const BoolQueryRt = t.type({ + should: t.array(t.record(t.string, t.unknown)), + must: t.array(t.record(t.string, t.unknown)), + must_not: t.array(t.record(t.string, t.unknown)), + filter: t.array(t.record(t.string, t.unknown)), +}); + +export const filtersRt = new t.Type( + 'BoolQuery', + BoolQueryRt.is, + (input: unknown, context: t.Context) => + either.chain(t.string.validate(input, context), (value: string) => { + try { + const filters = JSON.parse(value); + const decoded = { + should: [], + must: [], + must_not: filters.must_not ? [...filters.must_not] : [], + filter: filters.filter ? [...filters.filter] : [], + }; + return t.success(decoded); + } catch (err) { + return t.failure(input, context, err.message); + } + }), + (filters: BoolQuery): string => JSON.stringify(filters) +); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/services/get_throughput.ts b/x-pack/plugins/observability_solution/apm/server/routes/services/get_throughput.ts index 5d45ea28c95e5..b5c48484e1039 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/services/get_throughput.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/services/get_throughput.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { BoolQuery } from '@kbn/es-query'; import { kqlQuery, rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ApmServiceTransactionDocumentType } from '../../../common/document_type'; import { SERVICE_NAME, TRANSACTION_NAME, TRANSACTION_TYPE } from '../../../common/es_fields/apm'; @@ -17,6 +17,7 @@ import { Maybe } from '../../../typings/common'; interface Options { environment: string; kuery: string; + filters?: BoolQuery; serviceName: string; apmEventClient: APMEventClient; transactionType: string; @@ -34,6 +35,7 @@ export type ServiceThroughputResponse = Array<{ x: number; y: Maybe }>; export async function getThroughput({ environment, kuery, + filters, serviceName, apmEventClient, transactionType, @@ -67,7 +69,9 @@ export async function getThroughput({ ...environmentQuery(environment), ...kqlQuery(kuery), ...termQuery(TRANSACTION_NAME, transactionName), + ...(filters?.filter ?? []), ], + must_not: [...(filters?.must_not ?? [])], }, }, aggs: { diff --git a/x-pack/plugins/observability_solution/apm/server/routes/services/route.ts b/x-pack/plugins/observability_solution/apm/server/routes/services/route.ts index 05fdeec8fdf5d..4b0ef92450f34 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/services/route.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/services/route.ts @@ -33,6 +33,7 @@ import { withApmSpan } from '../../utils/with_apm_span'; import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, + filtersRt, kueryRt, probabilityRt, rangeRt, @@ -495,7 +496,7 @@ const serviceThroughputRoute = createApmServerRoute({ }), query: t.intersection([ t.type({ transactionType: t.string, bucketSizeInSeconds: toNumberRt }), - t.partial({ transactionName: t.string }), + t.partial({ transactionName: t.string, filters: filtersRt }), t.intersection([environmentRt, kueryRt, rangeRt, offsetRt, serviceTransactionDataSourceRt]), ]), }), @@ -512,6 +513,7 @@ const serviceThroughputRoute = createApmServerRoute({ const { environment, kuery, + filters, transactionType, transactionName, offset, @@ -525,6 +527,7 @@ const serviceThroughputRoute = createApmServerRoute({ const commonProps = { environment, kuery, + filters, serviceName, apmEventClient, transactionType, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts b/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts index 5b77a780bce6a..c2ba9d1014a67 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_failed_transaction_rate_periods.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { BoolQuery } from '@kbn/es-query'; import { getFailedTransactionRate } from '../../lib/transaction_groups/get_failed_transaction_rate'; import { offsetPreviousPeriodCoordinates } from '../../../common/utils/offset_previous_period_coordinate'; import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; @@ -25,6 +26,7 @@ export interface FailedTransactionRateResponse { export async function getFailedTransactionRatePeriods({ environment, kuery, + filters, serviceName, transactionType, transactionName, @@ -38,6 +40,7 @@ export async function getFailedTransactionRatePeriods({ }: { environment: string; kuery: string; + filters?: BoolQuery; serviceName: string; transactionType: string; transactionName?: string; @@ -52,6 +55,7 @@ export async function getFailedTransactionRatePeriods({ const commonProps = { environment, kuery, + filters, serviceName, transactionTypes: [transactionType], transactionName, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_latency_charts/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_latency_charts/index.ts index f05682ca047bb..70e9555af4849 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_latency_charts/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/transactions/get_latency_charts/index.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import { BoolQuery } from '@kbn/es-query'; import { kqlQuery, rangeQuery, termQuery } from '@kbn/observability-plugin/server'; import { ApmServiceTransactionDocumentType } from '../../../../common/document_type'; import { @@ -29,6 +29,7 @@ import { getDurationFieldForTransactions } from '../../../lib/helpers/transactio function searchLatency({ environment, kuery, + filters, serviceName, transactionType, transactionName, @@ -45,6 +46,7 @@ function searchLatency({ }: { environment: string; kuery: string; + filters?: BoolQuery; serviceName: string; transactionType: string | undefined; transactionName: string | undefined; @@ -87,7 +89,9 @@ function searchLatency({ ...termQuery(TRANSACTION_NAME, transactionName), ...termQuery(TRANSACTION_TYPE, transactionType), ...termQuery(FAAS_ID, serverlessId), + ...(filters?.filter || []), ], + must_not: filters?.must_not || [], }, }, aggs: { @@ -111,6 +115,7 @@ function searchLatency({ export async function getLatencyTimeseries({ environment, kuery, + filters, serviceName, transactionType, transactionName, @@ -127,6 +132,7 @@ export async function getLatencyTimeseries({ }: { environment: string; kuery: string; + filters?: BoolQuery; serviceName: string; transactionType?: string; transactionName?: string; @@ -144,6 +150,7 @@ export async function getLatencyTimeseries({ const response = await searchLatency({ environment, kuery, + filters, serviceName, transactionType, transactionName, @@ -195,6 +202,7 @@ export async function getLatencyPeriods({ apmEventClient, latencyAggregationType, kuery, + filters, environment, start, end, @@ -210,6 +218,7 @@ export async function getLatencyPeriods({ apmEventClient: APMEventClient; latencyAggregationType: LatencyAggregationType; kuery: string; + filters?: BoolQuery; environment: string; start: number; end: number; @@ -225,6 +234,7 @@ export async function getLatencyPeriods({ transactionName, apmEventClient, kuery, + filters, environment, documentType, rollupInterval, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/transactions/route.ts b/x-pack/plugins/observability_solution/apm/server/routes/transactions/route.ts index 8e6b8a654a030..816879d7cb40a 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/transactions/route.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/transactions/route.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import { jsonRt, toBooleanRt, toNumberRt } from '@kbn/io-ts-utils'; import * as t from 'io-ts'; import { offsetRt } from '../../../common/comparison_rt'; @@ -23,6 +22,7 @@ import { import { createApmServerRoute } from '../apm_routes/create_apm_server_route'; import { environmentRt, + filtersRt, kueryRt, rangeRt, serviceTransactionDataSourceRt, @@ -221,7 +221,7 @@ const transactionLatencyChartsRoute = createApmServerRoute({ bucketSizeInSeconds: toNumberRt, useDurationSummary: toBooleanRt, }), - t.partial({ transactionName: t.string }), + t.partial({ transactionName: t.string, filters: filtersRt }), t.intersection([environmentRt, kueryRt, rangeRt, offsetRt]), serviceTransactionDataSourceRt, ]), @@ -235,6 +235,7 @@ const transactionLatencyChartsRoute = createApmServerRoute({ const { environment, kuery, + filters, transactionType, transactionName, latencyAggregationType, @@ -250,6 +251,7 @@ const transactionLatencyChartsRoute = createApmServerRoute({ const options = { environment, kuery, + filters, serviceName, transactionType, transactionName, @@ -372,7 +374,7 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ }), query: t.intersection([ t.type({ transactionType: t.string, bucketSizeInSeconds: toNumberRt }), - t.partial({ transactionName: t.string }), + t.partial({ transactionName: t.string, filters: filtersRt }), t.intersection([environmentRt, kueryRt, rangeRt, offsetRt, serviceTransactionDataSourceRt]), ]), }), @@ -385,6 +387,7 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ const { environment, kuery, + filters, transactionType, transactionName, start, @@ -398,6 +401,7 @@ const transactionChartsErrorRateRoute = createApmServerRoute({ return getFailedTransactionRatePeriods({ environment, kuery, + filters, serviceName, transactionType, transactionName, diff --git a/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts b/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts index ef56e61bf4f82..624706d30115a 100644 --- a/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/throughput.spec.ts @@ -7,6 +7,7 @@ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; +import { buildQueryFromFilters } from '@kbn/es-query'; import { first, last, meanBy } from 'lodash'; import moment from 'moment'; import { isFiniteNumber } from '@kbn/apm-plugin/common/utils/is_finite_number'; @@ -285,6 +286,250 @@ export default function ApiTest({ getService }: FtrProviderContext) { ); }); }); + + describe('handles kuery', () => { + let throughputMetrics: ThroughputReturn; + let throughputTransactions: ThroughputReturn; + + before(async () => { + const [throughputMetricsResponse, throughputTransactionsResponse] = await Promise.all([ + callApi( + { + query: { + kuery: 'transaction.name : "GET /api/product/list"', + }, + }, + 'metric' + ), + callApi( + { + query: { + kuery: 'transaction.name : "GET /api/product/list"', + }, + }, + 'transaction' + ), + ]); + throughputMetrics = throughputMetricsResponse.body; + throughputTransactions = throughputTransactionsResponse.body; + }); + + it('returns some transactions data', () => { + expect(throughputTransactions.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputTransactions.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('returns some metrics data', () => { + expect(throughputMetrics.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputMetrics.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('has same mean value for metrics and transactions data', () => { + const transactionsMean = meanBy(throughputTransactions.currentPeriod, 'y'); + const metricsMean = meanBy(throughputMetrics.currentPeriod, 'y'); + [transactionsMean, metricsMean].forEach((value) => + expect(roundNumber(value)).to.be.equal(roundNumber(GO_PROD_RATE)) + ); + }); + + it('has a bucket size of 30 seconds for transactions data', () => { + const firstTimerange = throughputTransactions.currentPeriod[0].x; + const secondTimerange = throughputTransactions.currentPeriod[1].x; + const timeIntervalAsSeconds = (secondTimerange - firstTimerange) / 1000; + expect(timeIntervalAsSeconds).to.equal(30); + }); + + it('has a bucket size of 1 minute for metrics data', () => { + const firstTimerange = throughputMetrics.currentPeriod[0].x; + const secondTimerange = throughputMetrics.currentPeriod[1].x; + const timeIntervalAsMinutes = (secondTimerange - firstTimerange) / 1000 / 60; + expect(timeIntervalAsMinutes).to.equal(1); + }); + }); + + describe('handles filters', () => { + let throughputMetrics: ThroughputReturn; + let throughputTransactions: ThroughputReturn; + const filters = [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /api/product/list', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + + before(async () => { + const [throughputMetricsResponse, throughputTransactionsResponse] = await Promise.all([ + callApi( + { + query: { + filters: serializedFilters, + }, + }, + 'metric' + ), + callApi( + { + query: { + filters: serializedFilters, + }, + }, + 'transaction' + ), + ]); + throughputMetrics = throughputMetricsResponse.body; + throughputTransactions = throughputTransactionsResponse.body; + }); + + it('returns some transactions data', () => { + expect(throughputTransactions.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputTransactions.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('returns some metrics data', () => { + expect(throughputMetrics.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputMetrics.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('has same mean value for metrics and transactions data', () => { + const transactionsMean = meanBy(throughputTransactions.currentPeriod, 'y'); + const metricsMean = meanBy(throughputMetrics.currentPeriod, 'y'); + [transactionsMean, metricsMean].forEach((value) => + expect(roundNumber(value)).to.be.equal(roundNumber(GO_PROD_RATE)) + ); + }); + + it('has a bucket size of 30 seconds for transactions data', () => { + const firstTimerange = throughputTransactions.currentPeriod[0].x; + const secondTimerange = throughputTransactions.currentPeriod[1].x; + const timeIntervalAsSeconds = (secondTimerange - firstTimerange) / 1000; + expect(timeIntervalAsSeconds).to.equal(30); + }); + + it('has a bucket size of 1 minute for metrics data', () => { + const firstTimerange = throughputMetrics.currentPeriod[0].x; + const secondTimerange = throughputMetrics.currentPeriod[1].x; + const timeIntervalAsMinutes = (secondTimerange - firstTimerange) / 1000 / 60; + expect(timeIntervalAsMinutes).to.equal(1); + }); + }); + + describe('handles negate filters', () => { + let throughputMetrics: ThroughputReturn; + let throughputTransactions: ThroughputReturn; + const filters = [ + { + meta: { + disabled: false, + negate: true, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /api/product/list', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + + before(async () => { + const [throughputMetricsResponse, throughputTransactionsResponse] = await Promise.all([ + callApi( + { + query: { + filters: serializedFilters, + }, + }, + 'metric' + ), + callApi( + { + query: { + filters: serializedFilters, + }, + }, + 'transaction' + ), + ]); + throughputMetrics = throughputMetricsResponse.body; + throughputTransactions = throughputTransactionsResponse.body; + }); + + it('returns some transactions data', () => { + expect(throughputTransactions.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputTransactions.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('returns some metrics data', () => { + expect(throughputMetrics.currentPeriod.length).to.be.greaterThan(0); + const hasData = throughputMetrics.currentPeriod.some(({ y }) => isFiniteNumber(y)); + expect(hasData).to.equal(true); + }); + + it('has same mean value for metrics and transactions data', () => { + const transactionsMean = meanBy(throughputTransactions.currentPeriod, 'y'); + const metricsMean = meanBy(throughputMetrics.currentPeriod, 'y'); + [transactionsMean, metricsMean].forEach((value) => + expect(roundNumber(value)).to.be.equal(roundNumber(GO_DEV_RATE)) + ); + }); + + it('has a bucket size of 30 seconds for transactions data', () => { + const firstTimerange = throughputTransactions.currentPeriod[0].x; + const secondTimerange = throughputTransactions.currentPeriod[1].x; + const timeIntervalAsSeconds = (secondTimerange - firstTimerange) / 1000; + expect(timeIntervalAsSeconds).to.equal(30); + }); + + it('has a bucket size of 1 minute for metrics data', () => { + const firstTimerange = throughputMetrics.currentPeriod[0].x; + const secondTimerange = throughputMetrics.currentPeriod[1].x; + const timeIntervalAsMinutes = (secondTimerange - firstTimerange) / 1000 / 60; + expect(timeIntervalAsMinutes).to.equal(1); + }); + }); + + describe('handles bad filters request', () => { + it('throws bad request error', async () => { + try { + await callApi({ + query: { environment: 'production', filters: '{}}' }, + }); + } catch (error) { + expect(error.res.status).to.be(400); + } + }); + }); }); }); } diff --git a/x-pack/test/apm_api_integration/tests/transactions/error_rate.spec.ts b/x-pack/test/apm_api_integration/tests/transactions/error_rate.spec.ts index 996127103b090..123bb0d6d594d 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/error_rate.spec.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/error_rate.spec.ts @@ -6,6 +6,7 @@ */ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; +import { buildQueryFromFilters } from '@kbn/es-query'; import { first, last } from 'lodash'; import moment from 'moment'; import { @@ -297,5 +298,136 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); }); + + describe('handles kuery', () => { + let txMetricsErrorRateResponse: ErrorRate; + + before(async () => { + const txMetricsResponse = await fetchErrorCharts({ + query: { + kuery: 'transaction.name : "GET /pear 🍎 "', + }, + }); + txMetricsErrorRateResponse = txMetricsResponse.body; + }); + + describe('has the correct calculation for average with kuery', () => { + const expectedFailureRate = config.secondTransaction.failureRate / 100; + + it('for tx metrics', () => { + expect(txMetricsErrorRateResponse.currentPeriod.average).to.eql(expectedFailureRate); + }); + }); + }); + + describe('handles filters', () => { + const filters = [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /pear 🍎 ', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + let txMetricsErrorRateResponse: ErrorRate; + + before(async () => { + const txMetricsResponse = await fetchErrorCharts({ + query: { + filters: serializedFilters, + }, + }); + txMetricsErrorRateResponse = txMetricsResponse.body; + }); + + describe('has the correct calculation for average with filter', () => { + const expectedFailureRate = config.secondTransaction.failureRate / 100; + + it('for tx metrics', () => { + expect(txMetricsErrorRateResponse.currentPeriod.average).to.eql(expectedFailureRate); + }); + }); + + describe('has the correct calculation for average with negate filter', () => { + const expectedFailureRate = config.secondTransaction.failureRate / 100; + + it('for tx metrics', () => { + expect(txMetricsErrorRateResponse.currentPeriod.average).to.eql(expectedFailureRate); + }); + }); + }); + + describe('handles negate filters', () => { + const filters = [ + { + meta: { + disabled: false, + negate: true, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /pear 🍎 ', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + let txMetricsErrorRateResponse: ErrorRate; + + before(async () => { + const txMetricsResponse = await fetchErrorCharts({ + query: { + filters: serializedFilters, + }, + }); + txMetricsErrorRateResponse = txMetricsResponse.body; + }); + + describe('has the correct calculation for average with filter', () => { + const expectedFailureRate = config.firstTransaction.failureRate / 100; + + it('for tx metrics', () => { + expect(txMetricsErrorRateResponse.currentPeriod.average).to.eql(expectedFailureRate); + }); + }); + }); + + describe('handles bad filters request', () => { + it('for tx metrics', async () => { + try { + await fetchErrorCharts({ + query: { + filters: '{}}}', + }, + }); + } catch (e) { + expect(e.res.status).to.eql(400); + } + }); + }); }); } diff --git a/x-pack/test/apm_api_integration/tests/transactions/latency.spec.ts b/x-pack/test/apm_api_integration/tests/transactions/latency.spec.ts index a1cea01f408ca..eb876e6e312b7 100644 --- a/x-pack/test/apm_api_integration/tests/transactions/latency.spec.ts +++ b/x-pack/test/apm_api_integration/tests/transactions/latency.spec.ts @@ -6,6 +6,7 @@ */ import { apm, timerange } from '@kbn/apm-synthtrace-client'; import expect from '@kbn/expect'; +import { buildQueryFromFilters } from '@kbn/es-query'; import moment from 'moment'; import { APIClientRequestParamsOf, @@ -115,6 +116,9 @@ export default function ApiTest({ getService }: FtrProviderContext) { ((GO_PROD_RATE * GO_PROD_DURATION + GO_DEV_RATE * GO_DEV_DURATION) / (GO_PROD_RATE + GO_DEV_RATE)) * 1000; + const expectedLatencyAvgValueProdMs = + ((GO_PROD_RATE * GO_PROD_DURATION) / GO_PROD_RATE) * 1000; + const expectedLatencyAvgValueDevMs = ((GO_DEV_RATE * GO_DEV_DURATION) / GO_DEV_RATE) * 1000; describe('average latency type', () => { it('returns average duration and timeseries', async () => { @@ -319,6 +323,122 @@ export default function ApiTest({ getService }: FtrProviderContext) { }); }); }); + + describe('handles kuery', () => { + it('should return the appropriate latency values when a kuery is applied', async () => { + const response = await fetchLatencyCharts({ + query: { + latencyAggregationType: LatencyAggregationType.p95, + useDurationSummary: false, + kuery: 'transaction.name : "GET /api/product/list"', + }, + }); + + expect(response.status).to.be(200); + const latencyChartReturn = response.body as LatencyChartReturnType; + + expect(latencyChartReturn.currentPeriod.overallAvgDuration).to.be( + expectedLatencyAvgValueProdMs + ); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(15); + }); + }); + + describe('handles filters', () => { + it('should return the appropriate latency values when filters are applied', async () => { + const filters = [ + { + meta: { + disabled: false, + negate: false, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /api/product/list', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + const response = await fetchLatencyCharts({ + query: { + latencyAggregationType: LatencyAggregationType.p95, + useDurationSummary: false, + filters: serializedFilters, + }, + }); + + expect(response.status).to.be(200); + const latencyChartReturn = response.body as LatencyChartReturnType; + + expect(latencyChartReturn.currentPeriod.overallAvgDuration).to.be( + expectedLatencyAvgValueProdMs + ); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(15); + }); + + it('should return the appropriate latency values when negate filters are applied', async () => { + const filters = [ + { + meta: { + disabled: false, + negate: true, + alias: null, + key: 'transaction.name', + params: ['GET /api/product/list'], + type: 'phrases', + }, + query: { + bool: { + minimum_should_match: 1, + should: { + match_phrase: { + 'transaction.name': 'GET /api/product/list', + }, + }, + }, + }, + }, + ]; + const serializedFilters = JSON.stringify(buildQueryFromFilters(filters, undefined)); + const response = await fetchLatencyCharts({ + query: { + latencyAggregationType: LatencyAggregationType.p95, + useDurationSummary: false, + filters: serializedFilters, + }, + }); + + expect(response.status).to.be(200); + const latencyChartReturn = response.body as LatencyChartReturnType; + + expect(latencyChartReturn.currentPeriod.overallAvgDuration).to.be( + expectedLatencyAvgValueDevMs + ); + expect(latencyChartReturn.currentPeriod.latencyTimeseries.length).to.be.eql(15); + }); + }); + + describe('handles bad filters request', () => { + it('throws bad request error', async () => { + try { + await fetchLatencyCharts({ + query: { environment: 'production', filters: '{}}' }, + }); + } catch (error) { + expect(error.res.status).to.be(400); + } + }); + }); } ); } From f52db83d33735f2ce0463d510e75b81f05dab6f1 Mon Sep 17 00:00:00 2001 From: Jonathan Budzenski Date: Wed, 24 Apr 2024 14:40:47 -0500 Subject: [PATCH 51/67] Revert "Enable heap snapshots for all our distributables (#181363)" This reverts commit 26b8c71730de6686fe4fe5de5f60ab5577b79902. --- config/node.options | 4 ---- .../os_packages/docker_generator/templates/base/Dockerfile | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/config/node.options b/config/node.options index 2bc49f5db1f4a..abcb40a5c19d4 100644 --- a/config/node.options +++ b/config/node.options @@ -13,7 +13,3 @@ ## enable OpenSSL 3 legacy provider --openssl-legacy-provider - -# Enable capturing heap snapshots. See https://nodejs.org/api/cli.html#--heapsnapshot-signalsignal ---heapsnapshot-signal=SIGUSR2 ---diagnostic-dir=./data \ No newline at end of file diff --git a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile index 2284e504229a8..1869086b51ab7 100644 --- a/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile +++ b/src/dev/build/tasks/os_packages/docker_generator/templates/base/Dockerfile @@ -157,6 +157,9 @@ COPY --chown=1000:0 config/serverless.yml /usr/share/kibana/config/serverless.ym COPY --chown=1000:0 config/serverless.es.yml /usr/share/kibana/config/serverless.es.yml COPY --chown=1000:0 config/serverless.oblt.yml /usr/share/kibana/config/serverless.oblt.yml COPY --chown=1000:0 config/serverless.security.yml /usr/share/kibana/config/serverless.security.yml +# Supportability enhancement: enable capturing heap snapshots. See https://nodejs.org/api/cli.html#--heapsnapshot-signalsignal +RUN /usr/bin/echo -e '\n--heapsnapshot-signal=SIGUSR2' >> config/node.options +RUN /usr/bin/echo '--diagnostic-dir=./data' >> config/node.options ENV PROFILER_SIGNAL=SIGUSR1 {{/serverless}} {{^opensslLegacyProvider}} From 0bce10993fdf2d75bb2b1819b807654d5d5be777 Mon Sep 17 00:00:00 2001 From: christineweng <18648970+christineweng@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:58:50 -0500 Subject: [PATCH 52/67] [Security Solution][Alert Details] Fix ancestry and same source insights (#181095) ## Summary Commit f9259faa3d3f2dfbf824fe934f2a32ae1999cbe9 address https://github.com/elastic/kibana/issues/180842 - Fields like `kibana.alert.ancestors.id` and `kibana.alert.rule.parameters.index` were previously used to fetch insights, but they are specific to alerts. To enable alerts by ancestry and alerts by same source events for non-alerts, this PR adds event id and default indices as fall back. ![image](https://github.com/elastic/kibana/assets/18648970/6691f841-5906-48f6-af80-e99c03def092) Commit bf6f8b73080987067ad126056042e145c3da372b address https://github.com/elastic/kibana/issues/181237 - There are checks to guard whether we can show as least 1 insight ([here](https://github.com/elastic/kibana/blob/main/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.tsx#L59)). However, the guard is only checking whether we have valid parameters, there is still a possibility that 0 alert is returned. In that case, the correlations is blank. The alert flyout avoids this scenario because there is always at least 1 alert by same source - As part of the fix above, alert by same source is now always enabled. This PR ensures we show same source insight even though no alert is found. Before ![image](https://github.com/elastic/kibana/assets/18648970/f053bf11-644f-4a5a-bfeb-5e0ce574b84c) After ![image](https://github.com/elastic/kibana/assets/18648970/a7b4d568-4c1e-413a-8dc4-ecfefd9a6a74) **How to test** - Generate some events and alerts - Go to Explore -> Host -> Events table - Expand a row details, scroll down to insights -> correlations, alerts by same source and alerts by ancestry insights should be present for applicable events (if you have endpoint security rule enabled, filter by `event.kind==alert`) - Note you need premium and above to see alerts by ancestry insight. ### 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 --- .../components/correlations_details.test.tsx | 37 +++++-------------- .../left/components/correlations_details.tsx | 27 +++++--------- ...lated_alerts_by_same_source_event.test.tsx | 13 +++++-- .../related_alerts_by_same_source_event.tsx | 6 +-- .../components/correlations_overview.test.tsx | 35 +++++++----------- .../components/correlations_overview.tsx | 33 ++++++++--------- .../components/insights_section.test.tsx | 7 ++++ ...lated_alerts_by_same_source_event.test.tsx | 11 ++++-- .../related_alerts_by_same_source_event.tsx | 3 +- ...e_show_related_alerts_by_ancestry.test.tsx | 12 ------ .../use_show_related_alerts_by_ancestry.ts | 26 +------------ ...lated_alerts_by_same_source_event.test.tsx | 14 +++++-- ...how_related_alerts_by_same_source_event.ts | 15 +++++--- 13 files changed, 97 insertions(+), 142 deletions(-) diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx index aad62c152773a..a0a147d9754d5 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.test.tsx @@ -27,6 +27,7 @@ import { useFetchRelatedAlertsByAncestry } from '../../shared/hooks/use_fetch_re import { useFetchRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_fetch_related_alerts_by_same_source_event'; import { useFetchRelatedCases } from '../../shared/hooks/use_fetch_related_cases'; import { mockContextValue } from '../mocks/mock_context'; +import { useTimelineDataFilters } from '../../../../timelines/containers/use_timeline_data_filters'; import { EXPANDABLE_PANEL_HEADER_TITLE_TEXT_TEST_ID } from '../../../shared/components/test_ids'; jest.mock('react-router-dom', () => { @@ -43,6 +44,11 @@ jest.mock('../../shared/hooks/use_fetch_related_alerts_by_ancestry'); jest.mock('../../shared/hooks/use_fetch_related_alerts_by_same_source_event'); jest.mock('../../shared/hooks/use_fetch_related_cases'); +jest.mock('../../../../timelines/containers/use_timeline_data_filters', () => ({ + useTimelineDataFilters: jest.fn(), +})); +const mockUseTimelineDataFilters = useTimelineDataFilters as jest.Mock; + const renderCorrelationDetails = () => { return render( @@ -62,12 +68,13 @@ const NO_DATA_MESSAGE = 'No correlations data available.'; describe('CorrelationsDetails', () => { beforeEach(() => { jest.clearAllMocks(); + mockUseTimelineDataFilters.mockReturnValue({ selectedPatterns: ['index'] }); }); it('renders all sections', () => { jest .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: true, documentId: 'event-id', indices: ['index1'] }); + .mockReturnValue({ show: true, documentId: 'event-id' }); jest .mocked(useShowRelatedAlertsBySameSourceEvent) .mockReturnValue({ show: true, originalEventId: 'originalEventId' }); @@ -115,7 +122,7 @@ describe('CorrelationsDetails', () => { it('should render no section and show error message if show values are false', () => { jest .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: false, documentId: 'event-id', indices: ['index1'] }); + .mockReturnValue({ show: false, documentId: 'event-id' }); jest .mocked(useShowRelatedAlertsBySameSourceEvent) .mockReturnValue({ show: false, originalEventId: 'originalEventId' }); @@ -142,30 +149,4 @@ describe('CorrelationsDetails', () => { ).not.toBeInTheDocument(); expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); - - it('should render no section if values are null', () => { - jest - .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: true, documentId: 'event-id' }); - jest.mocked(useShowRelatedAlertsBySameSourceEvent).mockReturnValue({ show: true }); - jest.mocked(useShowRelatedAlertsBySession).mockReturnValue({ show: true }); - jest.mocked(useShowRelatedCases).mockReturnValue(false); - jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); - - const { queryByTestId } = renderCorrelationDetails(); - - expect( - queryByTestId(CORRELATIONS_DETAILS_BY_ANCESTRY_SECTION_TABLE_TEST_ID) - ).not.toBeInTheDocument(); - expect( - queryByTestId(CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID) - ).not.toBeInTheDocument(); - expect( - queryByTestId(CORRELATIONS_DETAILS_BY_SESSION_SECTION_TABLE_TEST_ID) - ).not.toBeInTheDocument(); - expect(queryByTestId(CORRELATIONS_DETAILS_CASES_SECTION_TABLE_TEST_ID)).not.toBeInTheDocument(); - expect( - queryByTestId(CORRELATIONS_DETAILS_SUPPRESSED_ALERTS_TITLE_TEST_ID) - ).not.toBeInTheDocument(); - }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.tsx index 226fbe4d7a4d6..9c5a33a04a243 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/correlations_details.tsx @@ -20,6 +20,8 @@ import { useShowRelatedAlertsBySameSourceEvent } from '../../shared/hooks/use_sh import { useShowRelatedAlertsBySession } from '../../shared/hooks/use_show_related_alerts_by_session'; import { RelatedAlertsByAncestry } from './related_alerts_by_ancestry'; import { SuppressedAlerts } from './suppressed_alerts'; +import { useTimelineDataFilters } from '../../../../timelines/containers/use_timeline_data_filters'; +import { isActiveTimeline } from '../../../../helpers'; export const CORRELATIONS_TAB_ID = 'correlations'; @@ -27,27 +29,18 @@ export const CORRELATIONS_TAB_ID = 'correlations'; * Correlations displayed in the document details expandable flyout left section under the Insights tab */ export const CorrelationsDetails: React.FC = () => { - const { - dataAsNestedObject, - dataFormattedForFieldBrowser, - eventId, - getFieldsData, - scopeId, - isPreview, - } = useLeftPanelContext(); + const { dataAsNestedObject, eventId, getFieldsData, scopeId, isPreview } = useLeftPanelContext(); + + const { selectedPatterns } = useTimelineDataFilters(isActiveTimeline(scopeId)); - const { - show: showAlertsByAncestry, - indices, - documentId, - } = useShowRelatedAlertsByAncestry({ + const { show: showAlertsByAncestry, documentId } = useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview, }); const { show: showSameSourceAlerts, originalEventId } = useShowRelatedAlertsBySameSourceEvent({ + eventId, getFieldsData, }); const { show: showAlertsBySession, entityId } = useShowRelatedAlertsBySession({ getFieldsData }); @@ -80,7 +73,7 @@ export const CorrelationsDetails: React.FC = () => { )} - {showSameSourceAlerts && originalEventId && ( + {showSameSourceAlerts && ( { )} - {showAlertsByAncestry && documentId && indices && ( + {showAlertsByAncestry && ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx index 66902bd9bda34..e8334613d1d24 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.test.tsx @@ -94,14 +94,21 @@ describe('', () => { expect(getByTestId(CORRELATIONS_DETAILS_BY_SOURCE_SECTION_TABLE_TEST_ID)).toBeInTheDocument(); }); - it('should render null if error', () => { + it('should render no data message if error', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: true, + data: [], + dataCount: 0, + }); + (usePaginatedAlerts as jest.Mock).mockReturnValue({ + loading: false, + error: false, + data: [], }); - const { container } = renderRelatedAlertsBySameSourceEvent(); - expect(container).toBeEmptyDOMElement(); + const { getByText } = renderRelatedAlertsBySameSourceEvent(); + expect(getByText('No related source events.')).toBeInTheDocument(); }); it('should render no data message', () => { diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.tsx index e3bbf48c5fe15..42c9d910d93c6 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/left/components/related_alerts_by_same_source_event.tsx @@ -34,15 +34,11 @@ export const RelatedAlertsBySameSourceEvent: React.VFC { - const { loading, error, data, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ + const { loading, data, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ originalEventId, scopeId, }); - if (error) { - return null; - } - return ( ({ ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}, })); +jest.mock('../../../../timelines/containers/use_timeline_data_filters', () => ({ + useTimelineDataFilters: jest.fn(), +})); +const mockUseTimelineDataFilters = useTimelineDataFilters as jest.Mock; + +const originalEventId = 'originalEventId'; + describe('', () => { beforeAll(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(flyoutContextValue); + mockUseTimelineDataFilters.mockReturnValue({ selectedPatterns: ['index'] }); }); it('should render wrapper component', () => { jest .mocked(useShowRelatedAlertsByAncestry) .mockReturnValue({ show: false, documentId: 'event-id' }); - jest.mocked(useShowRelatedAlertsBySameSourceEvent).mockReturnValue({ show: false }); + jest + .mocked(useShowRelatedAlertsBySameSourceEvent) + .mockReturnValue({ show: false, originalEventId }); jest.mocked(useShowRelatedAlertsBySession).mockReturnValue({ show: false }); jest.mocked(useShowRelatedCases).mockReturnValue(false); jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); @@ -117,7 +128,7 @@ describe('', () => { it('should show component with all rows in expandable panel', () => { jest .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: true, documentId: 'event-id', indices: ['index1'] }); + .mockReturnValue({ show: true, documentId: 'event-id' }); jest .mocked(useShowRelatedAlertsBySameSourceEvent) .mockReturnValue({ show: true, originalEventId: 'originalEventId' }); @@ -160,7 +171,7 @@ describe('', () => { it('should hide rows and show error message if show values are false', () => { jest .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: false, documentId: 'event-id', indices: ['index1'] }); + .mockReturnValue({ show: false, documentId: 'event-id' }); jest .mocked(useShowRelatedAlertsBySameSourceEvent) .mockReturnValue({ show: false, originalEventId: 'originalEventId' }); @@ -179,24 +190,6 @@ describe('', () => { expect(getByText(NO_DATA_MESSAGE)).toBeInTheDocument(); }); - it('should hide rows if values are null', () => { - jest - .mocked(useShowRelatedAlertsByAncestry) - .mockReturnValue({ show: true, documentId: 'event-id' }); - jest.mocked(useShowRelatedAlertsBySameSourceEvent).mockReturnValue({ show: true }); - jest.mocked(useShowRelatedAlertsBySession).mockReturnValue({ show: true }); - jest.mocked(useShowRelatedCases).mockReturnValue(false); - jest.mocked(useShowSuppressedAlerts).mockReturnValue({ show: false, alertSuppressionCount: 0 }); - - const { queryByTestId, queryByText } = render(renderCorrelationsOverview(panelContextValue)); - expect(queryByTestId(RELATED_ALERTS_BY_ANCESTRY_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SAME_SOURCE_EVENT_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_ALERTS_BY_SESSION_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(RELATED_CASES_TEST_ID)).not.toBeInTheDocument(); - expect(queryByTestId(SUPPRESSED_ALERTS_TEST_ID)).not.toBeInTheDocument(); - expect(queryByText(NO_DATA_MESSAGE)).not.toBeInTheDocument(); - }); - it('should navigate to the left section Insights tab when clicking on button', () => { const { getByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx index 6d91eabd00304..e272a058bf0da 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/correlations_overview.tsx @@ -24,6 +24,8 @@ import { CORRELATIONS_TEST_ID } from './test_ids'; import { useRightPanelContext } from '../context'; import { DocumentDetailsLeftPanelKey, LeftPanelInsightsTab } from '../../left'; import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details'; +import { useTimelineDataFilters } from '../../../../timelines/containers/use_timeline_data_filters'; +import { isActiveTimeline } from '../../../../helpers'; /** * Correlations section under Insights section, overview tab. @@ -31,17 +33,12 @@ import { CORRELATIONS_TAB_ID } from '../../left/components/correlations_details' * and the SummaryPanel component for data rendering. */ export const CorrelationsOverview: React.FC = () => { - const { - dataAsNestedObject, - dataFormattedForFieldBrowser, - eventId, - indexName, - getFieldsData, - scopeId, - isPreview, - } = useRightPanelContext(); + const { dataAsNestedObject, eventId, indexName, getFieldsData, scopeId, isPreview } = + useRightPanelContext(); const { openLeftPanel } = useExpandableFlyoutApi(); + const { selectedPatterns } = useTimelineDataFilters(isActiveTimeline(scopeId)); + const goToCorrelationsTab = useCallback(() => { openLeftPanel({ id: DocumentDetailsLeftPanelKey, @@ -57,18 +54,14 @@ export const CorrelationsOverview: React.FC = () => { }); }, [eventId, openLeftPanel, indexName, scopeId]); - const { - show: showAlertsByAncestry, - documentId, - indices, - } = useShowRelatedAlertsByAncestry({ + const { show: showAlertsByAncestry, documentId } = useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview, }); const { show: showSameSourceAlerts, originalEventId } = useShowRelatedAlertsBySameSourceEvent({ + eventId, getFieldsData, }); const { show: showAlertsBySession, entityId } = useShowRelatedAlertsBySession({ getFieldsData }); @@ -112,14 +105,18 @@ export const CorrelationsOverview: React.FC = () => { )} {showCases && } - {showSameSourceAlerts && originalEventId && ( + {showSameSourceAlerts && ( )} {showAlertsBySession && entityId && ( )} - {showAlertsByAncestry && documentId && indices && ( - + {showAlertsByAncestry && ( + )} ) : ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx index 71897773d801e..81f9c6d54457e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/insights_section.test.tsx @@ -28,6 +28,7 @@ import { InsightsSection } from './insights_section'; import { useAlertPrevalence } from '../../../../common/containers/alerts/use_alert_prevalence'; import { useRiskScore } from '../../../../entity_analytics/api/hooks/use_risk_score'; import { useExpandSection } from '../hooks/use_expand_section'; +import { useTimelineDataFilters } from '../../../../timelines/containers/use_timeline_data_filters'; jest.mock('../../../../common/containers/alerts/use_alert_prevalence'); @@ -55,6 +56,11 @@ jest.mock('react-router-dom', () => { alertIds: [], }); +jest.mock('../../../../timelines/containers/use_timeline_data_filters', () => ({ + useTimelineDataFilters: jest.fn(), +})); +const mockUseTimelineDataFilters = useTimelineDataFilters as jest.Mock; + const from = '2022-04-05T12:00:00.000Z'; const to = '2022-04-08T12:00:00.;000Z'; const selectedPatterns = 'alerts'; @@ -101,6 +107,7 @@ const renderInsightsSection = (contextValue: RightPanelContext) => describe('', () => { beforeEach(() => { + mockUseTimelineDataFilters.mockReturnValue({ selectedPatterns: ['index'] }); mockUseUserDetails.mockReturnValue([false, { userDetails: null }]); mockUseRiskScore.mockReturnValue({ data: null, isAuthorized: false }); mockUseHostDetails.mockReturnValue([false, { hostDetails: null }]); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx index 59dfb183a1338..d52d547397789 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.test.tsx @@ -79,13 +79,18 @@ describe('', () => { expect(getByTestId(LOADING_TEST_ID)).toBeInTheDocument(); }); - it('should render null if error', () => { + it('should render 0 same source alert if error', () => { (useFetchRelatedAlertsBySameSourceEvent as jest.Mock).mockReturnValue({ loading: false, error: true, + dataCount: 0, }); - const { container } = renderRelatedAlertsBySameSourceEvent(); - expect(container).toBeEmptyDOMElement(); + const { getByTestId } = renderRelatedAlertsBySameSourceEvent(); + expect(getByTestId(ICON_TEST_ID)).toBeInTheDocument(); + const value = getByTestId(VALUE_TEST_ID); + expect(value).toBeInTheDocument(); + expect(value).toHaveTextContent('0 alerts related by source event'); + expect(getByTestId(VALUE_TEST_ID)).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx index e309a2e4bc93a..0c1550dbb8692 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/related_alerts_by_same_source_event.tsx @@ -31,7 +31,7 @@ export const RelatedAlertsBySameSourceEvent: React.VFC { - const { loading, error, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ + const { loading, dataCount } = useFetchRelatedAlertsBySameSourceEvent({ originalEventId, scopeId, }); @@ -46,7 +46,6 @@ export const RelatedAlertsBySameSourceEvent: React.VFC; const eventId = 'event-id'; const dataAsNestedObject = mockDataAsNestedObject; -const dataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser; describe('useShowRelatedAlertsByAncestry', () => { let hookResult: RenderHookResult< @@ -53,7 +51,6 @@ describe('useShowRelatedAlertsByAncestry', () => { useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview: false, }) @@ -62,7 +59,6 @@ describe('useShowRelatedAlertsByAncestry', () => { expect(hookResult.result.current).toEqual({ show: false, documentId: 'event-id', - indices: ['rule-parameters-index'], }); }); @@ -74,7 +70,6 @@ describe('useShowRelatedAlertsByAncestry', () => { useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview: false, }) @@ -83,7 +78,6 @@ describe('useShowRelatedAlertsByAncestry', () => { expect(hookResult.result.current).toEqual({ show: false, documentId: 'event-id', - indices: ['rule-parameters-index'], }); }); @@ -95,7 +89,6 @@ describe('useShowRelatedAlertsByAncestry', () => { useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview: false, }) @@ -104,7 +97,6 @@ describe('useShowRelatedAlertsByAncestry', () => { expect(hookResult.result.current).toEqual({ show: false, documentId: 'event-id', - indices: ['rule-parameters-index'], }); }); @@ -117,7 +109,6 @@ describe('useShowRelatedAlertsByAncestry', () => { useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview: false, }) @@ -126,7 +117,6 @@ describe('useShowRelatedAlertsByAncestry', () => { expect(hookResult.result.current).toEqual({ show: true, documentId: 'event-id', - indices: ['rule-parameters-index'], }); }); @@ -139,7 +129,6 @@ describe('useShowRelatedAlertsByAncestry', () => { useShowRelatedAlertsByAncestry({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview: true, }) @@ -148,7 +137,6 @@ describe('useShowRelatedAlertsByAncestry', () => { expect(hookResult.result.current).toEqual({ show: true, documentId: 'ancestors-id', - indices: ['rule-parameters-index'], }); }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_ancestry.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_ancestry.ts index 5a3f9c4f0b657..b11485f67ae6e 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_ancestry.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_ancestry.ts @@ -6,14 +6,11 @@ */ import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs'; -import { useMemo } from 'react'; -import { find } from 'lodash/fp'; -import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; import type { GetFieldsData } from '../../../../common/hooks/use_get_fields_data'; import { useIsInvestigateInResolverActionEnabled } from '../../../../detections/components/alerts_table/timeline_actions/investigate_in_resolver'; import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; import { useLicense } from '../../../../common/hooks/use_license'; -import { ANCESTOR_ID, RULE_PARAMETERS_INDEX } from '../constants/field_names'; +import { ANCESTOR_ID } from '../constants/field_names'; import { getField } from '../utils'; export interface UseShowRelatedAlertsByAncestryParams { @@ -25,10 +22,6 @@ export interface UseShowRelatedAlertsByAncestryParams { * An object with top level fields from the ECS object */ dataAsNestedObject: Ecs; - /** - * An array of field objects with category and value - */ - dataFormattedForFieldBrowser: TimelineEventsDetailsItem[]; /** * Id of the event document */ @@ -44,10 +37,6 @@ export interface UseShowRelatedAlertsByAncestryResult { * Returns true if the user has at least platinum privilege, and if the document has ancestry data */ show: boolean; - /** - * Values of the kibana.alert.rule.parameters.index field - */ - indices?: string[]; /** * Value of the document id for fetching ancestry alerts */ @@ -60,7 +49,6 @@ export interface UseShowRelatedAlertsByAncestryResult { export const useShowRelatedAlertsByAncestry = ({ getFieldsData, dataAsNestedObject, - dataFormattedForFieldBrowser, eventId, isPreview, }: UseShowRelatedAlertsByAncestryParams): UseShowRelatedAlertsByAncestryResult => { @@ -71,24 +59,14 @@ export const useShowRelatedAlertsByAncestry = ({ const ancestorId = getField(getFieldsData(ANCESTOR_ID)) ?? ''; const documentId = isPreview ? ancestorId : eventId; - // can't use getFieldsData here as the kibana.alert.rule.parameters is different and can be nested - const originalDocumentIndex = useMemo( - () => find({ category: 'kibana', field: RULE_PARAMETERS_INDEX }, dataFormattedForFieldBrowser), - [dataFormattedForFieldBrowser] - ); const hasAtLeastPlatinum = useLicense().isPlatinumPlus(); const show = - isRelatedAlertsByProcessAncestryEnabled && - hasProcessEntityInfo && - originalDocumentIndex != null && - hasAtLeastPlatinum; + isRelatedAlertsByProcessAncestryEnabled && hasProcessEntityInfo && hasAtLeastPlatinum; return { show, documentId, - ...(originalDocumentIndex && - originalDocumentIndex.values && { indices: originalDocumentIndex.values }), }; }; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.test.tsx index 01a014409264c..dfbfeeccc655a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.test.tsx @@ -14,22 +14,28 @@ import type { } from './use_show_related_alerts_by_same_source_event'; import { useShowRelatedAlertsBySameSourceEvent } from './use_show_related_alerts_by_same_source_event'; +const eventId = 'eventId'; + describe('useShowRelatedAlertsBySameSourceEvent', () => { let hookResult: RenderHookResult< ShowRelatedAlertsBySameSourceEventParams, ShowRelatedAlertsBySameSourceEventResult >; - it('should return false if getFieldsData returns null', () => { + it('should return eventId if getFieldsData returns null', () => { const getFieldsData = () => null; - hookResult = renderHook(() => useShowRelatedAlertsBySameSourceEvent({ getFieldsData })); + hookResult = renderHook(() => + useShowRelatedAlertsBySameSourceEvent({ getFieldsData, eventId }) + ); - expect(hookResult.result.current).toEqual({ show: false }); + expect(hookResult.result.current).toEqual({ show: true, originalEventId: 'eventId' }); }); it('should return true if getFieldsData has the correct field', () => { const getFieldsData = () => 'original_event'; - hookResult = renderHook(() => useShowRelatedAlertsBySameSourceEvent({ getFieldsData })); + hookResult = renderHook(() => + useShowRelatedAlertsBySameSourceEvent({ getFieldsData, eventId }) + ); expect(hookResult.result.current).toEqual({ show: true, originalEventId: 'original_event' }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.ts b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.ts index 0d510400d5efe..2f76c74b329d1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/hooks/use_show_related_alerts_by_same_source_event.ts @@ -10,6 +10,10 @@ import { ANCESTOR_ID } from '../constants/field_names'; import { getField } from '../utils'; export interface ShowRelatedAlertsBySameSourceEventParams { + /** + * Id of the event document + */ + eventId: string; /** * Retrieves searchHit values for the provided field */ @@ -24,18 +28,19 @@ export interface ShowRelatedAlertsBySameSourceEventResult { /** * Value of the kibana.alert.original_event.id field */ - originalEventId?: string; + originalEventId: string; } /** - * Returns true if document has kibana.alert.original.event.id field with values + * Returns kibana.alert.ancestors.id field or default eventId */ export const useShowRelatedAlertsBySameSourceEvent = ({ + eventId, getFieldsData, }: ShowRelatedAlertsBySameSourceEventParams): ShowRelatedAlertsBySameSourceEventResult => { - const originalEventId = getField(getFieldsData(ANCESTOR_ID)); + const originalEventId = getField(getFieldsData(ANCESTOR_ID)) ?? eventId; return { - show: originalEventId != null, - ...(originalEventId && { originalEventId }), + show: true, + originalEventId, }; }; From 60ab2cfe956dc824b336f115a3a0fe91ee093a9d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 24 Apr 2024 14:05:19 -0600 Subject: [PATCH 53/67] PresentationPanel props hidePanelChrome (#181473) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Changes 1. adds `hidePanelChrome` parameter to `ReactEmbeddableRenderer`. When true, embeddable is rendered without `PresentationPanel` wrapper 2. Removes `embeddable-explorer` plugin 3. Moves Embeddable developer example into embeddable_examples plugin 4. Creates new examples that demonstrate how to use `ReactEmbeddableRenderer` Screenshot 2024-04-23 at 5 19 18 PM Follow-up work to narrow scope of this PR 1. add key concepts to embeddable overview 2. add "Register new embeddable type" tab that details how to create a new embeddable and shows how you can add embeddable examples to dashboard 3. group embeddable examples into a single item in "Add panel" menu - to show best practices of how to keep menu clean 4. remove class based example embeddables ### Test instructions 1. start kibana with `yarn start --run-examples` 5. Open kibana menu and click "Developer examples" 6. Click "Embeddables" card and run examples --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .github/CODEOWNERS | 1 - examples/embeddable_examples/kibana.jsonc | 3 +- .../embeddable_examples/public/app/app.tsx | 81 +++++++++++ .../public/app/overview.tsx} | 15 +- .../public/app/render_examples.tsx | 137 ++++++++++++++++++ .../public/app/setup_app.ts | 31 ++++ examples/embeddable_examples/public/plugin.ts | 39 ++--- .../search/search_embeddable_renderer.tsx | 53 +++++++ .../public/react_embeddables/search/types.ts | 3 + examples/embeddable_examples/tsconfig.json | 4 +- examples/embeddable_explorer/README.md | 10 -- examples/embeddable_explorer/kibana.jsonc | 20 --- examples/embeddable_explorer/public/app.tsx | 123 ---------------- .../public/embeddable_panel_example.tsx | 66 --------- .../public/embeddables.png | Bin 88399 -> 0 bytes .../public/hello_world_embeddable_example.tsx | 72 --------- .../public/list_container_example.tsx | 82 ----------- .../embeddable_explorer/public/plugin.tsx | 82 ----------- examples/embeddable_explorer/tsconfig.json | 25 ---- package.json | 1 - .../interfaces/fetch/fetch.ts | 22 +-- .../react_embeddable_renderer.tsx | 10 +- .../panel_component/presentation_panel.tsx | 48 ++++-- test/examples/config.js | 1 - .../embeddables/hello_world_embeddable.ts | 37 ----- test/examples/embeddables/index.ts | 29 ---- test/examples/embeddables/list_container.ts | 32 ---- tsconfig.base.json | 2 - yarn.lock | 4 - 29 files changed, 392 insertions(+), 641 deletions(-) create mode 100644 examples/embeddable_examples/public/app/app.tsx rename examples/{embeddable_explorer/public/index.ts => embeddable_examples/public/app/overview.tsx} (50%) create mode 100644 examples/embeddable_examples/public/app/render_examples.tsx create mode 100644 examples/embeddable_examples/public/app/setup_app.ts create mode 100644 examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx delete mode 100644 examples/embeddable_explorer/README.md delete mode 100644 examples/embeddable_explorer/kibana.jsonc delete mode 100644 examples/embeddable_explorer/public/app.tsx delete mode 100644 examples/embeddable_explorer/public/embeddable_panel_example.tsx delete mode 100644 examples/embeddable_explorer/public/embeddables.png delete mode 100644 examples/embeddable_explorer/public/hello_world_embeddable_example.tsx delete mode 100644 examples/embeddable_explorer/public/list_container_example.tsx delete mode 100644 examples/embeddable_explorer/public/plugin.tsx delete mode 100644 examples/embeddable_explorer/tsconfig.json delete mode 100644 test/examples/embeddables/hello_world_embeddable.ts delete mode 100644 test/examples/embeddables/index.ts delete mode 100644 test/examples/embeddables/list_container.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0c57ef0d7dc9a..0f58444069968 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -384,7 +384,6 @@ test/plugin_functional/plugins/elasticsearch_client_plugin @elastic/kibana-core x-pack/test/plugin_api_integration/plugins/elasticsearch_client @elastic/kibana-core x-pack/plugins/embeddable_enhanced @elastic/kibana-presentation examples/embeddable_examples @elastic/kibana-presentation -examples/embeddable_explorer @elastic/kibana-presentation src/plugins/embeddable @elastic/kibana-presentation x-pack/examples/embedded_lens_example @elastic/kibana-visualizations x-pack/plugins/encrypted_saved_objects @elastic/kibana-security diff --git a/examples/embeddable_examples/kibana.jsonc b/examples/embeddable_examples/kibana.jsonc index 0788268aedf3f..08e4a02360b2c 100644 --- a/examples/embeddable_examples/kibana.jsonc +++ b/examples/embeddable_examples/kibana.jsonc @@ -14,7 +14,8 @@ "dashboard", "data", "charts", - "fieldFormats" + "fieldFormats", + "developerExamples" ], "requiredBundles": ["presentationUtil"], "extraPublicDirs": ["public/hello_world"] diff --git a/examples/embeddable_examples/public/app/app.tsx b/examples/embeddable_examples/public/app/app.tsx new file mode 100644 index 0000000000000..72c5d4f11779a --- /dev/null +++ b/examples/embeddable_examples/public/app/app.tsx @@ -0,0 +1,81 @@ +/* + * Copyright 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, { useState } from 'react'; +import ReactDOM from 'react-dom'; + +import { AppMountParameters } from '@kbn/core-application-browser'; +import { + EuiPage, + EuiPageBody, + EuiPageHeader, + EuiPageSection, + EuiPageTemplate, + EuiSpacer, + EuiTab, + EuiTabs, +} from '@elastic/eui'; +import { Overview } from './overview'; +import { RenderExamples } from './render_examples'; + +const OVERVIEW_TAB_ID = 'overview'; +const RENDER_TAB_ID = 'render'; + +const App = () => { + const [selectedTabId, setSelectedTabId] = useState(OVERVIEW_TAB_ID); + + function onSelectedTabChanged(tabId: string) { + setSelectedTabId(tabId); + } + + function renderTabContent() { + if (selectedTabId === RENDER_TAB_ID) { + return ; + } + + return ; + } + + return ( + + + + + + + + + onSelectedTabChanged(OVERVIEW_TAB_ID)} + isSelected={OVERVIEW_TAB_ID === selectedTabId} + > + Embeddables overview + + onSelectedTabChanged(RENDER_TAB_ID)} + isSelected={RENDER_TAB_ID === selectedTabId} + > + Rendering embeddables in your application + + + + + + {renderTabContent()} + + + + + ); +}; + +export const renderApp = (element: AppMountParameters['element']) => { + ReactDOM.render(, element); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/examples/embeddable_explorer/public/index.ts b/examples/embeddable_examples/public/app/overview.tsx similarity index 50% rename from examples/embeddable_explorer/public/index.ts rename to examples/embeddable_examples/public/app/overview.tsx index 7620d1daf20f6..e074cd148f77e 100644 --- a/examples/embeddable_explorer/public/index.ts +++ b/examples/embeddable_examples/public/app/overview.tsx @@ -6,6 +6,17 @@ * Side Public License, v 1. */ -import { EmbeddableExplorerPlugin } from './plugin'; +import React from 'react'; -export const plugin = () => new EmbeddableExplorerPlugin(); +import { EuiText } from '@elastic/eui'; + +export const Overview = () => { + return ( + +

+ Embeddables are React components that manage their own state, can be serialized and + deserialized, and return an API that can be used to interact with them imperatively. +

+
+ ); +}; diff --git a/examples/embeddable_examples/public/app/render_examples.tsx b/examples/embeddable_examples/public/app/render_examples.tsx new file mode 100644 index 0000000000000..c3e9b0a79a55b --- /dev/null +++ b/examples/embeddable_examples/public/app/render_examples.tsx @@ -0,0 +1,137 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { useMemo, useState } from 'react'; + +import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import { + EuiCodeBlock, + EuiFlexGroup, + EuiFlexItem, + EuiSpacer, + EuiSuperDatePicker, + EuiSwitch, + EuiText, + OnTimeChangeProps, +} from '@elastic/eui'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { TimeRange } from '@kbn/es-query'; +import { useBatchedOptionalPublishingSubjects } from '@kbn/presentation-publishing'; +import { SearchEmbeddableRenderer } from '../react_embeddables/search/search_embeddable_renderer'; +import { SEARCH_EMBEDDABLE_ID } from '../react_embeddables/search/constants'; +import type { Api, State } from '../react_embeddables/search/types'; + +export const RenderExamples = () => { + const initialState = useMemo(() => { + return { + rawState: { + timeRange: undefined, + }, + references: [], + }; + // only run onMount + }, []); + + const parentApi = useMemo(() => { + return { + reload$: new Subject(), + timeRange$: new BehaviorSubject({ + from: 'now-24h', + to: 'now', + }), + }; + // only run onMount + }, []); + + const [api, setApi] = useState(null); + const [hidePanelChrome, setHidePanelChrome] = useState(false); + const [dataLoading, timeRange] = useBatchedOptionalPublishingSubjects( + api?.dataLoading, + parentApi.timeRange$ + ); + + return ( +
+ { + parentApi.timeRange$.next({ + from: start, + to: end, + }); + }} + onRefresh={() => { + parentApi.reload$.next(); + }} + /> + + + + + + +

+ Use ReactEmbeddableRenderer to render embeddables. +

+
+ + + {` + type={SEARCH_EMBEDDABLE_ID} + state={initialState} + parentApi={parentApi} + onApiAvailable={(newApi) => { + setApi(newApi); + }} + hidePanelChrome={hidePanelChrome} +/>`} + + + + + setHidePanelChrome(e.target.checked)} + /> + + + + + key={hidePanelChrome ? 'hideChrome' : 'showChrome'} + type={SEARCH_EMBEDDABLE_ID} + state={initialState} + parentApi={parentApi} + onApiAvailable={(newApi) => { + setApi(newApi); + }} + hidePanelChrome={hidePanelChrome} + /> +
+ + + +

To avoid leaking embeddable details, wrap ReactEmbeddableRenderer in a component.

+
+ + + {``} + + + + + +
+
+
+ ); +}; diff --git a/examples/embeddable_examples/public/app/setup_app.ts b/examples/embeddable_examples/public/app/setup_app.ts new file mode 100644 index 0000000000000..c489b603c877b --- /dev/null +++ b/examples/embeddable_examples/public/app/setup_app.ts @@ -0,0 +1,31 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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 { AppMountParameters, CoreSetup } from '@kbn/core/public'; +import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; +import type { StartDeps } from '../plugin'; + +const APP_ID = 'embeddablesApp'; +const title = 'Embeddables'; + +export function setupApp(core: CoreSetup, developerExamples: DeveloperExamplesSetup) { + core.application.register({ + id: APP_ID, + title, + visibleIn: [], + async mount(params: AppMountParameters) { + const { renderApp } = await import('./app'); + return renderApp(params.element); + }, + }); + developerExamples.register({ + appId: APP_ID, + title, + description: `Learn how to create new embeddable types and use embeddables in your application.`, + }); +} diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index e3916b8b409cb..85faad072920a 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -17,6 +17,7 @@ import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; import { HelloWorldEmbeddableFactory, HELLO_WORLD_EMBEDDABLE, @@ -45,13 +46,15 @@ import { registerAddSearchPanelAction } from './react_embeddables/search/registe import { EUI_MARKDOWN_ID } from './react_embeddables/eui_markdown/constants'; import { FIELD_LIST_ID } from './react_embeddables/field_list/constants'; import { SEARCH_EMBEDDABLE_ID } from './react_embeddables/search/constants'; +import { setupApp } from './app/setup_app'; -export interface EmbeddableExamplesSetupDependencies { +export interface SetupDeps { + developerExamples: DeveloperExamplesSetup; embeddable: EmbeddableSetup; uiActions: UiActionsStart; } -export interface EmbeddableExamplesStartDependencies { +export interface StartDeps { dataViews: DataViewsPublicPluginStart; embeddable: EmbeddableStart; uiActions: UiActionsStart; @@ -67,40 +70,31 @@ interface ExampleEmbeddableFactories { getFilterDebuggerEmbeddableFactory: () => FilterDebuggerEmbeddableFactory; } -export interface EmbeddableExamplesStart { +export interface StartApi { createSampleData: () => Promise; factories: ExampleEmbeddableFactories; } -export class EmbeddableExamplesPlugin - implements - Plugin< - void, - EmbeddableExamplesStart, - EmbeddableExamplesSetupDependencies, - EmbeddableExamplesStartDependencies - > -{ +export class EmbeddableExamplesPlugin implements Plugin { private exampleEmbeddableFactories: Partial = {}; - public setup( - core: CoreSetup, - deps: EmbeddableExamplesSetupDependencies - ) { + public setup(core: CoreSetup, { embeddable, developerExamples }: SetupDeps) { + setupApp(core, developerExamples); + this.exampleEmbeddableFactories.getHelloWorldEmbeddableFactory = - deps.embeddable.registerEmbeddableFactory( + embeddable.registerEmbeddableFactory( HELLO_WORLD_EMBEDDABLE, new HelloWorldEmbeddableFactoryDefinition() ); this.exampleEmbeddableFactories.getMigrationsEmbeddableFactory = - deps.embeddable.registerEmbeddableFactory( + embeddable.registerEmbeddableFactory( SIMPLE_EMBEDDABLE, new SimpleEmbeddableFactoryDefinition() ); this.exampleEmbeddableFactories.getListContainerEmbeddableFactory = - deps.embeddable.registerEmbeddableFactory( + embeddable.registerEmbeddableFactory( LIST_CONTAINER, new ListContainerFactoryDefinition(async () => ({ embeddableServices: (await core.getStartServices())[1].embeddable, @@ -108,16 +102,13 @@ export class EmbeddableExamplesPlugin ); this.exampleEmbeddableFactories.getFilterDebuggerEmbeddableFactory = - deps.embeddable.registerEmbeddableFactory( + embeddable.registerEmbeddableFactory( FILTER_DEBUGGER_EMBEDDABLE, new FilterDebuggerEmbeddableFactoryDefinition() ); } - public start( - core: CoreStart, - deps: EmbeddableExamplesStartDependencies - ): EmbeddableExamplesStart { + public start(core: CoreStart, deps: StartDeps): StartApi { registerCreateFieldListAction(deps.uiActions); registerReactEmbeddableFactory(FIELD_LIST_ID, async () => { const { getFieldListFactory } = await import( diff --git a/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx b/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx new file mode 100644 index 0000000000000..0fa6e785b72c1 --- /dev/null +++ b/examples/embeddable_examples/public/react_embeddables/search/search_embeddable_renderer.tsx @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 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, { useEffect, useMemo } from 'react'; +import { BehaviorSubject } from 'rxjs'; +import { TimeRange } from '@kbn/es-query'; +import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import type { Api, State } from './types'; +import { SEARCH_EMBEDDABLE_ID } from './constants'; + +interface Props { + timeRange?: TimeRange; +} + +export function SearchEmbeddableRenderer(props: Props) { + const initialState = useMemo(() => { + return { + rawState: { + timeRange: undefined, + }, + references: [], + }; + // only run onMount + }, []); + + const parentApi = useMemo(() => { + return { + timeRange$: new BehaviorSubject(props.timeRange), + }; + // only run onMount + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + parentApi.timeRange$.next(props.timeRange); + }, [props.timeRange, parentApi.timeRange$]); + + return ( +
+ + type={SEARCH_EMBEDDABLE_ID} + state={initialState} + parentApi={parentApi} + hidePanelChrome={true} + /> +
+ ); +} diff --git a/examples/embeddable_examples/public/react_embeddables/search/types.ts b/examples/embeddable_examples/public/react_embeddables/search/types.ts index 5ba940b2d40b0..dffe119eee7a0 100644 --- a/examples/embeddable_examples/public/react_embeddables/search/types.ts +++ b/examples/embeddable_examples/public/react_embeddables/search/types.ts @@ -19,6 +19,9 @@ import { } from '@kbn/presentation-publishing'; export interface State { + /* + * Time range only applied to this embeddable, overrides parentApi.timeRange$ + */ timeRange: TimeRange | undefined; } diff --git a/examples/embeddable_examples/tsconfig.json b/examples/embeddable_examples/tsconfig.json index 0225005262720..1165c05b189ad 100644 --- a/examples/embeddable_examples/tsconfig.json +++ b/examples/embeddable_examples/tsconfig.json @@ -29,6 +29,8 @@ "@kbn/core-lifecycle-browser", "@kbn/presentation-util-plugin", "@kbn/unified-field-list", - "@kbn/presentation-containers" + "@kbn/presentation-containers", + "@kbn/core-application-browser", + "@kbn/developer-examples-plugin" ] } diff --git a/examples/embeddable_explorer/README.md b/examples/embeddable_explorer/README.md deleted file mode 100644 index 0425790f07487..0000000000000 --- a/examples/embeddable_explorer/README.md +++ /dev/null @@ -1,10 +0,0 @@ -## Embeddable explorer - -This example app shows how to: - - Create a basic "hello world" embeddable - - Create embeddables that accept inputs and use an EmbeddableRenderer - - Nest embeddables inside a container - - Dynamically add children to embeddable containers - - Work with the EmbeddablePanel component - -To run this example, use the command `yarn start --run-examples`. diff --git a/examples/embeddable_explorer/kibana.jsonc b/examples/embeddable_explorer/kibana.jsonc deleted file mode 100644 index 3279a7ef92f51..0000000000000 --- a/examples/embeddable_explorer/kibana.jsonc +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "plugin", - "id": "@kbn/embeddable-explorer-plugin", - "owner": "@elastic/kibana-presentation", - "description": "Example app that relies on registered functionality in the embeddable_examples plugin", - "plugin": { - "id": "embeddableExplorer", - "server": false, - "browser": true, - "requiredPlugins": [ - "uiActions", - "inspector", - "embeddable", - "embeddableExamples", - "developerExamples", - "dashboard", - "kibanaReact" - ] - } -} diff --git a/examples/embeddable_explorer/public/app.tsx b/examples/embeddable_explorer/public/app.tsx deleted file mode 100644 index 1d1938c8dbebd..0000000000000 --- a/examples/embeddable_explorer/public/app.tsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0 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 ReactDOM from 'react-dom'; -import { BrowserRouter as Router, withRouter, RouteComponentProps } from 'react-router-dom'; -import { Route } from '@kbn/shared-ux-router'; -import { EuiPageTemplate, EuiSideNav } from '@elastic/eui'; -import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; -import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; -import { AppMountParameters, CoreStart, IUiSettingsClient, OverlayStart } from '@kbn/core/public'; -import { EmbeddableExamplesStart } from '@kbn/embeddable-examples-plugin/public/plugin'; -import { HelloWorldEmbeddableExample } from './hello_world_embeddable_example'; -import { ListContainerExample } from './list_container_example'; -import { EmbeddablePanelExample } from './embeddable_panel_example'; - -interface PageDef { - title: string; - id: string; - component: React.ReactNode; -} - -type NavProps = RouteComponentProps & { - navigateToApp: CoreStart['application']['navigateToApp']; - pages: PageDef[]; -}; - -const Nav = withRouter(({ history, navigateToApp, pages }: NavProps) => { - const navItems = pages.map((page) => ({ - id: page.id, - name: page.title, - onClick: () => history.push(`/${page.id}`), - 'data-test-subj': page.id, - })); - - return ( - - ); -}); - -interface Props { - basename: string; - navigateToApp: CoreStart['application']['navigateToApp']; - embeddableApi: EmbeddableStart; - uiActionsApi: UiActionsStart; - overlays: OverlayStart; - notifications: CoreStart['notifications']; - inspector: InspectorStartContract; - uiSettingsClient: IUiSettingsClient; - embeddableExamples: EmbeddableExamplesStart; -} - -const EmbeddableExplorerApp = ({ - basename, - navigateToApp, - embeddableApi, - embeddableExamples, -}: Props) => { - const pages: PageDef[] = [ - { - title: 'Render embeddable', - id: 'helloWorldEmbeddableSection', - component: ( - - ), - }, - { - title: 'Groups of embeddables', - id: 'listContainerSection', - component: ( - - ), - }, - { - title: 'Context menu', - id: 'embeddablePanelExample', - component: ( - - ), - }, - ]; - - const routes = pages.map((page, i) => ( - page.component} /> - )); - - return ( - - - -