From 834e54f1581951165625f6ef2fbeafe49494c229 Mon Sep 17 00:00:00 2001 From: Ido Cohen <90558359+CohenIdo@users.noreply.github.com> Date: Thu, 20 Feb 2025 15:28:29 +0200 Subject: [PATCH 01/23] [8.x] Deprecate universal entity (#211771) # Backport This will backport the following commits from `main` to `8.x`: - [Deprecate universal entity](https://github.com/elastic/kibana/pull/210978) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .buildkite/ftr_security_stateful_configs.yml | 2 +- .github/CODEOWNERS | 37 +++++ oas_docs/output/kibana.serverless.yaml | 2 - oas_docs/output/kibana.yaml | 2 - .../asset_criticality/common.gen.ts | 2 +- .../asset_criticality/common.schema.yaml | 1 - .../entity_store/common.gen.ts | 2 +- .../entity_store/common.schema.yaml | 1 - .../asset_criticality/utils.ts | 8 +- .../entity_analytics/entity_store/utils.ts | 10 +- .../entity_analytics/risk_engine/utils.ts | 8 +- .../common/entity_analytics/types.ts | 3 - .../common/entity_analytics/utils.test.ts | 27 +-- .../common/entity_analytics/utils.ts | 5 - .../common/experimental_features.ts | 6 - .../security_solution/risk_score/all/index.ts | 2 - ...alytics_api_2023_10_31.bundled.schema.yaml | 2 - ...alytics_api_2023_10_31.bundled.schema.yaml | 2 - .../components/entity_store/helpers.tsx | 1 - .../flyout/entity_details/shared/constants.ts | 2 - .../asset_criticality/helpers.ts | 1 - .../entity_definitions/constants.ts | 2 - .../entity_descriptions/index.ts | 1 - .../entity_descriptions/universal.ts | 96 ----------- .../entity_store_data_client.test.ts | 9 - .../entity_store/entity_store_data_client.ts | 6 - .../installation/engine_description.ts | 2 - .../asset_inventory_pipeline.ts | 157 ------------------ .../trial_license_complete_tier/index.ts | 1 - 29 files changed, 45 insertions(+), 355 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/universal.ts delete mode 100644 x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/asset_inventory_pipeline.ts diff --git a/.buildkite/ftr_security_stateful_configs.yml b/.buildkite/ftr_security_stateful_configs.yml index 6f55319523c87..9ff2753dec6a3 100644 --- a/.buildkite/ftr_security_stateful_configs.yml +++ b/.buildkite/ftr_security_stateful_configs.yml @@ -104,4 +104,4 @@ enabled: - x-pack/test/cloud_security_posture_functional/config.agentless.ts - x-pack/test/cloud_security_posture_functional/data_views/config.ts - x-pack/test/automatic_import_api_integration/apis/config_basic.ts - - x-pack/test/automatic_import_api_integration/apis/config_graphs.ts + - x-pack/test/automatic_import_api_integration/apis/config_graphs.ts \ No newline at end of file diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index bef88d3f69a81..88a92a0df92b9 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1961,6 +1961,7 @@ x-pack/plugins/osquery @elastic/security-defend-workflows # Cloud Security Posture x-pack/packages/kbn-cloud-security-posture @elastic/kibana-cloud-security-posture +<<<<<<< HEAD /x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.* @elastic/kibana-cloud-security-posture /x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture /x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture @@ -1977,6 +1978,42 @@ x-pack/packages/kbn-cloud-security-posture @elastic/kibana-cloud-security-postur /x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture /x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/misconfiguration_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture /x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/vulnerabilities_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture +======= +## Plugins +x-pack/plugins/cloud_defend @elastic/kibana-cloud-security-posture +x-pack/plugins/cloud_security_posture @elastic/kibana-cloud-security-posture +x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture +## Security Solution sub teams +x-pack/solutions/security/plugins/security_solution/public/common/components/sessions_viewer @elastic/kibana-cloud-security-posture +x-pack/solutions/security/plugins/security_solution/public/cloud_defend @elastic/kibana-cloud-security-posture +x-pack/solutions/security/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture +x-pack/solutions/security/plugins/security_solution/public/kubernetes @elastic/kibana-cloud-security-posture +x-pack/solutions/security/plugins/security_solution/server/lib/asset_inventory @elastic/kibana-cloud-security-posture + +## Fleet plugin (co-owned with Fleet team) +x-pack/platform/plugins/shared/fleet/public/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/platform/plugins/shared/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/platform/plugins/shared/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.* @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/platform/plugins/shared/fleet/public/applications/integrations/sections/epm/screens/detail/components/cloud_posture_third_party_support_callout.* @elastic/fleet @elastic/kibana-cloud-security-posture +## Kubernetes Security tests +x-pack/test/functional/es_archives/kubernetes_security @elastic/kibana-cloud-security-posture +x-pack/test/kubernetes_security @elastic/kibana-cloud-security-posture +## SessionView tests +x-pack/test/functional/es_archives/session_view @elastic/kibana-cloud-security-posture +x-pack/test/session_view @elastic/kibana-cloud-security-posture # Assigned per https://github.com/elastic/kibana/blob/main/api_docs/session_view.mdx#L18 +## CSP tests +x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture +x-pack/test/cloud_security_posture_functional/ @elastic/kibana-cloud-security-posture +x-pack/test/cloud_security_posture_api/ @elastic/kibana-cloud-security-posture +## CSP Serverless tests +x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.* @elastic/kibana-cloud-security-posture +x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/ @elastic/kibana-cloud-security-posture +x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/ @elastic/kibana-cloud-security-posture +## CSP e2e tests +x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/misconfiguration_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture +x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/vulnerabilities_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture +x-pack/test/security_solution_cypress/cypress/e2e/asset_inventory @elastic/kibana-cloud-security-posture +>>>>>>> f5c9529e37e (Deprecate universal entity) # Security Solution onboarding tour /x-pack/solutions/security/plugins/security_solution/public/common/components/guided_onboarding @elastic/security-threat-hunting-explore diff --git a/oas_docs/output/kibana.serverless.yaml b/oas_docs/output/kibana.serverless.yaml index 04b11950deba6..e796e9a5b04cc 100644 --- a/oas_docs/output/kibana.serverless.yaml +++ b/oas_docs/output/kibana.serverless.yaml @@ -47985,7 +47985,6 @@ components: - user - host - service - - universal type: string Security_Entity_Analytics_API_HostEntity: type: object @@ -48061,7 +48060,6 @@ components: - host.name - user.name - service.name - - related.entity type: string Security_Entity_Analytics_API_IndexPattern: type: string diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 7a032c4031d05..8d9702c12cea8 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -36375,7 +36375,6 @@ components: - user - host - service - - universal type: string Security_Entity_Analytics_API_HostEntity: type: object @@ -36451,7 +36450,6 @@ components: - host.name - user.name - service.name - - related.entity type: string Security_Entity_Analytics_API_IndexPattern: type: string diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts index 2c9cc0760f210..acae48846c82c 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.gen.ts @@ -17,7 +17,7 @@ import { z } from '@kbn/zod'; export type IdField = z.infer; -export const IdField = z.enum(['host.name', 'user.name', 'service.name', 'related.entity']); +export const IdField = z.enum(['host.name', 'user.name', 'service.name']); export type IdFieldEnum = typeof IdField.enum; export const IdFieldEnum = IdField.enum; diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml index 97485bb2c6605..32bbfc5122efb 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/asset_criticality/common.schema.yaml @@ -29,7 +29,6 @@ components: - 'host.name' - 'user.name' - 'service.name' - - 'related.entity' AssetCriticalityRecordIdParts: type: object properties: diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts index 628d0fb295a8e..f1cbc070792f8 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts @@ -17,7 +17,7 @@ import { z } from '@kbn/zod'; export type EntityType = z.infer; -export const EntityType = z.enum(['user', 'host', 'service', 'universal']); +export const EntityType = z.enum(['user', 'host', 'service']); export type EntityTypeEnum = typeof EntityType.enum; export const EntityTypeEnum = EntityType.enum; diff --git a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml index 4bcfba9fec891..82fc5b379a70c 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml @@ -12,7 +12,6 @@ components: - user - host - service - - universal EngineDescriptor: type: object diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/asset_criticality/utils.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/asset_criticality/utils.ts index 697ca1858ef23..ae3b7fe8fc075 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/asset_criticality/utils.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/asset_criticality/utils.ts @@ -7,17 +7,11 @@ import type { ExperimentalFeatures } from '../../experimental_features'; import { getAllEntityTypes, getDisabledEntityTypes } from '../utils'; -import { EntityType } from '../types'; - -const ASSET_CRITICALITY_UNAVAILABLE_TYPES = [EntityType.universal]; // TODO delete this function when the universal entity support is added export const getAssetCriticalityEntityTypes = (experimentalFeatures: ExperimentalFeatures) => { const allEntityTypes = getAllEntityTypes(); const disabledEntityTypes = getDisabledEntityTypes(experimentalFeatures); - return allEntityTypes.filter( - (value) => - !disabledEntityTypes.includes(value) && !ASSET_CRITICALITY_UNAVAILABLE_TYPES.includes(value) - ); + return allEntityTypes.filter((value) => !disabledEntityTypes.includes(value)); }; diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/entity_store/utils.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/entity_store/utils.ts index 7581c22f48a64..4f8bef1b64c94 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/entity_store/utils.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/entity_store/utils.ts @@ -6,18 +6,12 @@ */ import type { ExperimentalFeatures } from '../../experimental_features'; -import { EntityType } from '../types'; -import { getAllEntityTypes, getDisabledEntityTypes } from '../utils'; -const ENTITY_STORE_UNAVAILABLE_TYPES = [EntityType.universal]; +import { getAllEntityTypes, getDisabledEntityTypes } from '../utils'; -// TODO delete this function when the universal entity support is added export const getEnabledStoreEntityTypes = (experimentalFeatures: ExperimentalFeatures) => { const allEntityTypes = getAllEntityTypes(); const disabledEntityTypes = getDisabledEntityTypes(experimentalFeatures); - return allEntityTypes.filter( - (value) => - !disabledEntityTypes.includes(value) && !ENTITY_STORE_UNAVAILABLE_TYPES.includes(value) - ); + return allEntityTypes.filter((value) => !disabledEntityTypes.includes(value)); }; diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/risk_engine/utils.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/risk_engine/utils.ts index 005bfca6644cf..af38542da14f1 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/risk_engine/utils.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/risk_engine/utils.ts @@ -6,7 +6,6 @@ */ import * as t from 'io-ts'; -import { EntityType } from '../types'; import { getAllEntityTypes, getDisabledEntityTypes } from '../utils'; import type { ExperimentalFeatures } from '../../experimental_features'; @@ -28,15 +27,10 @@ export function fromEnum( ); } -const RISK_ENGINE_UNAVAILABLE_TYPES = [EntityType.universal]; - // TODO delete this function when the universal entity support is added export const getRiskEngineEntityTypes = (experimentalFeatures: ExperimentalFeatures) => { const allEntityTypes = getAllEntityTypes(); const disabledEntityTypes = getDisabledEntityTypes(experimentalFeatures); - return allEntityTypes.filter( - (value) => - !disabledEntityTypes.includes(value) && !RISK_ENGINE_UNAVAILABLE_TYPES.includes(value) - ); + return allEntityTypes.filter((value) => !disabledEntityTypes.includes(value)); }; diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/types.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/types.ts index ff8047da9877a..a47dd4dd18903 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/types.ts @@ -15,19 +15,16 @@ export enum EntityType { user = 'user', host = 'host', service = 'service', - universal = 'universal', } export enum EntityIdentifierFields { hostName = 'host.name', userName = 'user.name', serviceName = 'service.name', - universal = 'related.entity', } export const EntityTypeToIdentifierField: Record = { [EntityType.host]: EntityIdentifierFields.hostName, [EntityType.user]: EntityIdentifierFields.userName, [EntityType.service]: EntityIdentifierFields.serviceName, - [EntityType.universal]: EntityIdentifierFields.universal, }; diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.test.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.test.ts index 4a878669c6f61..205f43ca0dfda 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.test.ts @@ -4,13 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { getAllEntityTypes, getDisabledEntityTypes } from './utils'; +import { getAllEntityTypes } from './utils'; import { EntityType } from './types'; -import type { ExperimentalFeatures } from '../experimental_features'; -import { mockGlobalState } from '../../public/common/mock'; - -const mockedExperimentalFeatures = mockGlobalState.app.enableExperimental; describe('utils', () => { describe('getAllEntityTypes', () => { @@ -19,24 +14,4 @@ describe('utils', () => { expect(entityTypes).toEqual(Object.values(EntityType)); }); }); - - describe('getDisabledEntityTypes', () => { - it('should return disabled entity types when assetInventoryStoreEnabled is false', () => { - const experimentalFeatures: ExperimentalFeatures = { - ...mockedExperimentalFeatures, - assetInventoryStoreEnabled: false, - }; - const disabledEntityTypes = getDisabledEntityTypes(experimentalFeatures); - expect(disabledEntityTypes).toEqual([EntityType.universal]); - }); - - it('should return no disabled entity types when both features are true', () => { - const experimentalFeatures: ExperimentalFeatures = { - ...mockedExperimentalFeatures, - assetInventoryStoreEnabled: true, - }; - const disabledEntityTypes = getDisabledEntityTypes(experimentalFeatures); - expect(disabledEntityTypes).toEqual([]); - }); - }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.ts b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.ts index 062f0909b0231..26e116ec28bd8 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/entity_analytics/utils.ts @@ -13,11 +13,6 @@ export const getDisabledEntityTypes = ( experimentalFeatures: ExperimentalFeatures ): EntityType[] => { const disabledEntityTypes: EntityType[] = []; - const isUniversalEntityStoreEnabled = experimentalFeatures.assetInventoryStoreEnabled; - - if (!isUniversalEntityStoreEnabled) { - disabledEntityTypes.push(EntityType.universal); - } return disabledEntityTypes; }; diff --git a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts index 941196f62c441..efc30c0e3d126 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts @@ -262,12 +262,6 @@ export const allowedExperimentalValues = Object.freeze({ */ crowdstrikeRunScriptEnabled: true, - /** - * Enables the Asset Inventory Entity Store feature. - * Allows initializing the Universal Entity Store via the API. - */ - assetInventoryStoreEnabled: false, - /** * Enables the Asset Inventory feature */ diff --git a/x-pack/solutions/security/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts b/x-pack/solutions/security/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts index 9f31484a430ab..0062ed6c061df 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/search_strategy/security_solution/risk_score/all/index.ts @@ -93,12 +93,10 @@ export const EntityTypeToLevelField: Record = { [EntityType.host]: RiskScoreFields.hostRisk, [EntityType.user]: RiskScoreFields.userRisk, [EntityType.service]: RiskScoreFields.serviceRisk, - [EntityType.universal]: RiskScoreFields.unsupported, // We don't calculate risk for the universal entity }; export const EntityTypeToScoreField: Record = { [EntityType.host]: RiskScoreFields.hostRiskScore, [EntityType.user]: RiskScoreFields.userRiskScore, [EntityType.service]: RiskScoreFields.serviceRiskScore, - [EntityType.universal]: RiskScoreFields.unsupported, // We don't calculate risk for the universal entity }; diff --git a/x-pack/solutions/security/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index 4dc12c43d9a0b..16bf72c3fd6ef 100644 --- a/x-pack/solutions/security/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -1204,7 +1204,6 @@ components: - user - host - service - - universal type: string HostEntity: type: object @@ -1280,7 +1279,6 @@ components: - host.name - user.name - service.name - - related.entity type: string IndexPattern: type: string diff --git a/x-pack/solutions/security/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/solutions/security/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index 1e0ba8414a334..5690fe4ec329f 100644 --- a/x-pack/solutions/security/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/solutions/security/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -1204,7 +1204,6 @@ components: - user - host - service - - universal type: string HostEntity: type: object @@ -1280,7 +1279,6 @@ components: - host.name - user.name - service.name - - related.entity type: string IndexPattern: type: string diff --git a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_store/helpers.tsx b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_store/helpers.tsx index 3ae178b22ac5a..a8096fda7b09a 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_store/helpers.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/entity_store/helpers.tsx @@ -35,7 +35,6 @@ export const EntityIconByType: Record = { [EntityType.user]: 'user', [EntityType.host]: 'storage', [EntityType.service]: 'node', - [EntityType.universal]: 'globe', // random value since we don't support universal entity type }; export const sourceFieldToText = (source: string) => { diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/entity_details/shared/constants.ts b/x-pack/solutions/security/plugins/security_solution/public/flyout/entity_details/shared/constants.ts index ae123243aa04e..3002d187aae41 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/entity_details/shared/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/entity_details/shared/constants.ts @@ -32,7 +32,6 @@ export const EntityPanelKeyByType: Record = { [EntityType.host]: HostPanelKey, [EntityType.user]: UserPanelKey, [EntityType.service]: ServicePanelKey, - [EntityType.universal]: undefined, // TODO create universal flyout? }; // TODO rename all params and merged them as 'entityName' @@ -40,5 +39,4 @@ export const EntityPanelParamByType: Record = { [EntityType.host]: 'hostName', [EntityType.user]: 'userName', [EntityType.service]: 'serviceName', - [EntityType.universal]: undefined, // TODO create universal flyout? }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts index f3aa9fa5b0d09..5ae034fe5d86d 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/asset_criticality/helpers.ts @@ -82,7 +82,6 @@ const entityTypeByIdField = { 'host.name': 'host', 'user.name': 'user', 'service.name': 'service', - 'related.entity': 'universal', } as const; export const getImplicitEntityFields = (record: AssetCriticalityUpsertWithDeleted) => { diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/constants.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/constants.ts index c3665155c5ac7..a934b186f875e 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/constants.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/constants.ts @@ -8,7 +8,6 @@ import type { EntityType } from '../../../../../common/api/entity_analytics/entity_store'; import { HOST_DEFINITION_VERSION, - UNIVERSAL_DEFINITION_VERSION, USER_DEFINITION_VERSION, SERVICE_DEFINITION_VERSION, } from './entity_descriptions'; @@ -16,7 +15,6 @@ import { export const VERSIONS_BY_ENTITY_TYPE: Record = { host: HOST_DEFINITION_VERSION, user: USER_DEFINITION_VERSION, - universal: UNIVERSAL_DEFINITION_VERSION, service: SERVICE_DEFINITION_VERSION, }; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/index.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/index.ts index 8984c4aac0eca..58c9ce601094f 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/index.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/index.ts @@ -8,5 +8,4 @@ export * from './host'; export * from './user'; export * from './service'; -export * from './universal'; export { getCommonFieldDescriptions } from './common'; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/universal.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/universal.ts deleted file mode 100644 index e0dd82f0b330d..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/universal.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { IngestProcessorContainer } from '@elastic/elasticsearch/lib/api/types'; -import type { EntityDescription } from '../types'; -import { collectValues } from './field_utils'; - -export const UNIVERSAL_DEFINITION_VERSION = '1.0.0'; -export const UNIVERSAL_IDENTITY_FIELD = 'related.entity'; - -export const entityMetadataExtractorProcessor = { - script: { - tag: 'entity_metadata_extractor', - on_failure: [ - { - set: { - field: 'error.message', - value: - 'Processor {{ _ingest.on_failure_processor_type }} with tag {{ _ingest.on_failure_processor_tag }} in pipeline {{ _ingest.on_failure_pipeline }} failed with message {{ _ingest.on_failure_message }}', - }, - }, - ], - lang: 'painless', - source: /* java */ ` - // Array, boolean, integer, ip, bytes, anything that is not a map, is a leaf field - void overwriteLeafFields(Object toBeOverwritten, Object toOverwrite) { - if (!(toBeOverwritten instanceof Map)) { - // We can't override anything that isn't a map - return; - } - if (toOverwrite instanceof Map) { - Map mapToBeOverwritten = (Map) toBeOverwritten; - for (entryToOverwrite in ((Map) toOverwrite).entrySet()) { - String keyToOverwrite = entryToOverwrite.getKey(); - Object valueToOverwrite = entryToOverwrite.getValue(); - - if (valueToOverwrite instanceof Map) { - // If no initial value, we just put everything we have to overwrite - if (mapToBeOverwritten.get(keyToOverwrite) == null) { - mapToBeOverwritten.put(keyToOverwrite, valueToOverwrite) - } else { - overwriteLeafFields(mapToBeOverwritten.get(keyToOverwrite), valueToOverwrite); - } - } else { - mapToBeOverwritten.put(keyToOverwrite, valueToOverwrite) - } - } - } - } - - def id = ctx.entity.id; - Map merged = ctx; - for (meta in ctx.collected.metadata) { - Object json = Processors.json(meta); - if (((Map)json)[id] == null) { - continue; - } - - if (((Map)json)[id] != null) { - overwriteLeafFields(merged, ((Map)json)[id]); - } - } - - merged.entity.id = id; - ctx = merged; - `, - }, -}; - -export const universalEntityEngineDescription: EntityDescription = { - version: UNIVERSAL_DEFINITION_VERSION, - entityType: 'universal', - identityField: UNIVERSAL_IDENTITY_FIELD, - fields: [collectValues({ source: 'entities.keyword', destination: 'collected.metadata' })], - settings: { - timestampField: 'event.ingested', - }, - pipeline: (processors: IngestProcessorContainer[]) => { - const index = processors.findIndex((p) => Boolean(p.enrich)); - - if (index === -1) { - throw new Error('Enrich processor not found'); - } - - const init = processors.slice(0, index); - const tail = processors.slice(index); - const pipe = [...init, entityMetadataExtractorProcessor, ...tail]; - - return pipe; - }, - dynamic: true, -}; diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts index 9f6783ccc1df2..c085d857ba8cb 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.test.ts @@ -363,14 +363,5 @@ describe('EntityStoreDataClient', () => { expect(spyInit).toHaveBeenCalledWith(EntityType.host, expect.anything(), expect.anything()); }); - - it('does not enable engine when the given entity type is disabled', async () => { - await dataClient.enable({ - ...defaultOptions, - entityTypes: [EntityType.universal], - }); - - expect(spyInit).not.toHaveBeenCalled(); - }); }); }); diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index b7d42b533ed2c..f551d8b61e001 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -306,12 +306,6 @@ export class EntityStoreDataClient { requestBody: InitEntityEngineRequestBody, { pipelineDebugMode = false }: { pipelineDebugMode?: boolean } = {} ): Promise { - const { experimentalFeatures } = this.options; - - if (entityType === EntityType.universal && !experimentalFeatures.assetInventoryStoreEnabled) { - throw new Error('Universal entity store is not enabled'); - } - if (!this.options.taskManager) { throw new Error('Task Manager is not available'); } diff --git a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/installation/engine_description.ts b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/installation/engine_description.ts index 2b09bd41e5497..7face22fbf959 100644 --- a/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/installation/engine_description.ts +++ b/x-pack/solutions/security/plugins/security_solution/server/lib/entity_analytics/entity_store/installation/engine_description.ts @@ -14,7 +14,6 @@ import { generateIndexMappings } from '../elasticsearch_assets'; import { hostEntityEngineDescription, userEntityEngineDescription, - universalEntityEngineDescription, serviceEntityEngineDescription, } from '../entity_definitions/entity_descriptions'; import type { EntityStoreConfig } from '../types'; @@ -27,7 +26,6 @@ import { defaultOptions } from '../constants'; const engineDescriptionRegistry: Record = { host: hostEntityEngineDescription, user: userEntityEngineDescription, - universal: universalEntityEngineDescription, service: serviceEntityEngineDescription, }; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/asset_inventory_pipeline.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/asset_inventory_pipeline.ts deleted file mode 100644 index ca8d7b15cb81e..0000000000000 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/asset_inventory_pipeline.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { entityMetadataExtractorProcessor } from '@kbn/security-solution-plugin/server/lib/entity_analytics/entity_store/entity_definitions/entity_descriptions/universal'; -import { dynamicNewestRetentionSteps } from '@kbn/security-solution-plugin/server/lib/entity_analytics/entity_store/field_retention/dynamic_retention'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; -import { applyIngestProcessorToDoc } from '../utils/ingest'; - -export default ({ getService }: FtrProviderContext) => { - const es = getService('es'); - const log = getService('log'); - describe('@ess @serverless @skipInServerlessMKI Asset Inventory - universal entity engine pipeline ', () => { - describe('Entity metadata extractor processor step', () => { - it('should extract metadata from "collected.metadata" and add it to the document', async () => { - const metadata = { - test: { - cloud: { super: 123 }, - okta: { foo: { baz: { qux: 1 } } }, - }, - }; - const doc = { - collected: { - metadata: [JSON.stringify(metadata)], - }, - entity: { - id: 'test', - }, - }; - - const result = await applyIngestProcessorToDoc( - [entityMetadataExtractorProcessor], - doc, - es, - log - ); - - const processed = { - ...doc, - ...metadata.test, - }; - - return expect(result).to.eql(processed); - }); - }); - - describe('prefer newest value for dynamic entities', () => { - it('should return latest value if no history value', async () => { - const metadata = { - cloud: { super: 123 }, - }; - - const doc = metadata; - - const processor = dynamicNewestRetentionSteps([]); - const result = await applyIngestProcessorToDoc([processor], doc, es, log); - - return expect(result).to.eql(doc); - }); - - it('should return history value if no latest value is found', async () => { - const metadata = { - cloud: { super: 123 }, - }; - - const doc = { - historical: metadata, - }; - - const processor = dynamicNewestRetentionSteps([]); - const result = await applyIngestProcessorToDoc([processor], doc, es, log); - - return expect(result).to.eql({ - ...doc, - ...metadata, - }); - }); - - it('should return latest value if both historical and latest values exist', async () => { - const metadata = { - cloud: { super: 123 }, - }; - - const historical = { - cloud: { super: 456 }, - }; - - const doc = { - historical, - ...metadata, - }; - - const processor = dynamicNewestRetentionSteps([]); - const result = await applyIngestProcessorToDoc([processor], doc, es, log); - - return expect(result).to.eql(doc); - }); - - it('should merge nested object preserving historical values not found in latest', async () => { - const metadata = { - cloud: { host: 'test' }, - okta: { foo: { bar: { baz: 1 } } }, - }; - - const historical = { - cloud: { user: 'agent' }, - okta: { foo: { bar: { qux: 11 } } }, - }; - - const doc = { - historical, - ...metadata, - }; - - const processor = dynamicNewestRetentionSteps([]); - const result = await applyIngestProcessorToDoc([processor], doc, es, log); - - return expect(result).to.eql({ - historical, - cloud: { host: 'test', user: 'agent' }, - okta: { foo: { bar: { baz: 1, qux: 11 } } }, - }); - }); - - it('should ignore historical static fields', async () => { - const metadata = { - cloud: { host: 'test' }, - }; - - const historical = { - static: 'static', - cloud: { user: 'agent' }, - okta: { foo: { bar: { qux: 1 } } }, - }; - - const doc = { - historical, - ...metadata, - }; - - const staticFields = ['static']; - const processor = dynamicNewestRetentionSteps(staticFields); - const result = await applyIngestProcessorToDoc([processor], doc, es, log); - - return expect(result).to.eql({ - historical, - cloud: { host: 'test', user: 'agent' }, - okta: { foo: { bar: { qux: 1 } } }, - }); - }); - }); - }); -}; diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/index.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/index.ts index a6fb4cf805f2d..899dbc68102f3 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/index.ts @@ -13,6 +13,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./entity_store')); loadTestFile(require.resolve('./field_retention_operators')); loadTestFile(require.resolve('./entity_store_nondefault_spaces')); - loadTestFile(require.resolve('./asset_inventory_pipeline')); }); } From 689c733503c87b2613dd9fbd87968b9edaac8320 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 00:42:47 +1100 Subject: [PATCH 02/23] [8.x] [Security Solution] Change rule upgrade docs link (#211870) (#211891) # Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution] Change rule upgrade docs link (#211870)](https://github.com/elastic/kibana/pull/211870) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Nikita Indik --- .../packages/shared/kbn-doc-links/src/get_doc_links.ts | 3 +++ src/platform/packages/shared/kbn-doc-links/src/types.ts | 1 + .../three_way_diff/rule_upgrade/translations.tsx | 5 ++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts index d8b45612e2d70..0b791d77a7bd6 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/get_doc_links.ts @@ -512,6 +512,9 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D privileges: `${SECURITY_SOLUTION_DOCS}endpoint-management-req.html`, manageDetectionRules: `${SECURITY_SOLUTION_DOCS}rules-ui-management.html`, createDetectionRules: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html`, + updatePrebuiltDetectionRules: isServerless + ? `${SERVERLESS_DOCS}security-prebuilt-rules-management.html#update-prebuilt-rules` + : `${SECURITY_SOLUTION_DOCS}prebuilt-rules-management.html#update-prebuilt-rules`, createEsqlRuleType: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#create-esql-rule`, ruleUiAdvancedParams: `${SECURITY_SOLUTION_DOCS}rules-ui-create.html#rule-ui-advanced-params`, entityAnalytics: { diff --git a/src/platform/packages/shared/kbn-doc-links/src/types.ts b/src/platform/packages/shared/kbn-doc-links/src/types.ts index 376780fa516a2..36aecbf534f73 100644 --- a/src/platform/packages/shared/kbn-doc-links/src/types.ts +++ b/src/platform/packages/shared/kbn-doc-links/src/types.ts @@ -375,6 +375,7 @@ export interface DocLinks { readonly privileges: string; readonly manageDetectionRules: string; readonly createDetectionRules: string; + readonly updatePrebuiltDetectionRules: string; readonly createEsqlRuleType: string; readonly ruleUiAdvancedParams: string; readonly entityAnalytics: { diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx index 819e746739f39..812ec8c808730 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/rule_upgrade/translations.tsx @@ -55,11 +55,10 @@ export function RuleUpgradeHelper(): JSX.Element { const { docLinks: { links: { - securitySolution: { manageDetectionRules }, + securitySolution: { updatePrebuiltDetectionRules }, }, }, } = useKibana().services; - const manageDetectionRulesUpdateRulesSection = `${manageDetectionRules}#edit-rules-settings`; return ( + {UPGRADE_RULES_DOCS_LINK} ), From be0de8806b6a538f7dff4be5f78235c2ee5b34d1 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 00:44:12 +1100 Subject: [PATCH 03/23] [8.x] [ES|QL] Cleanup builtin and rename to operator (#211736) (#211865) # Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Cleanup builtin and rename to operator (#211736)](https://github.com/elastic/kibana/pull/211736) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Stratoula Kalafateli --- .../README.md | 2 +- .../scripts/generate_function_definitions.ts | 9 +- .../autocomplete.command.where.test.ts | 21 +- .../autocomplete.suggest.eval.test.ts | 17 +- .../src/autocomplete/__tests__/helpers.ts | 12 +- .../hidden_functions_and_commands.test.ts | 4 +- .../src/autocomplete/autocomplete.test.ts | 6 +- .../src/autocomplete/autocomplete.ts | 6 +- .../src/autocomplete/commands/where/index.ts | 2 +- .../src/autocomplete/complete_items.ts | 4 +- .../src/autocomplete/factories.ts | 8 +- .../src/autocomplete/helper.ts | 4 +- .../{builtin.ts => all_operators.ts} | 222 ++---------------- .../src/definitions/commands.ts | 2 +- .../src/definitions/generated/operators.ts | 40 ++-- .../src/definitions/types.ts | 2 +- .../src/shared/context.ts | 6 +- .../src/shared/helpers.ts | 6 +- .../validation/__tests__/functions.test.ts | 2 +- .../validation.command.inlinestats.ts | 20 +- .../test_suites/validation.command.stats.ts | 20 +- .../translations/translations/fr-FR.json | 5 - .../translations/translations/ja-JP.json | 5 - .../translations/translations/zh-CN.json | 5 - 24 files changed, 114 insertions(+), 316 deletions(-) rename src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/{builtin.ts => all_operators.ts} (59%) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/README.md b/src/platform/packages/shared/kbn-esql-validation-autocomplete/README.md index d67d4a3689468..eaa97898a8e89 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/README.md +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/README.md @@ -335,7 +335,7 @@ They look like this testSuggestions('from a | eval a = 1 year /', [ ',', '| ', - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ + ...getFunctionSignaturesByReturnType('eval', 'any', { operators: true, skipAssign: true }, [ 'time_interval', ]), ]); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index 088756339f288..1b4940cbc1218 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -759,8 +759,7 @@ const enrichOperators = ( // so we are overriding to add proper support supportedCommands, supportedOptions, - // @TODO: change to operator type - type: 'builtin' as const, + type: 'operator' as const, validate: validators[op.name], ...(isNotOperator ? { ignoreAsSuggestion: true } : {}), }; @@ -769,7 +768,7 @@ const enrichOperators = ( function printGeneratedFunctionsFile( functionDefinitions: FunctionDefinition[], - functionsType: 'aggregation' | 'scalar' | 'operators' | 'grouping' + functionsType: 'aggregation' | 'scalar' | 'operator' | 'grouping' ) { /** * Deals with asciidoc internal cross-references in the function descriptions @@ -864,7 +863,7 @@ ${ import { isLiteralItem } from '../../shared/helpers';` : '' } -${functionsType === 'operators' ? `import { isNumericType } from '../../shared/esql_types';` : ''} +${functionsType === 'operator' ? `import { isNumericType } from '../../shared/esql_types';` : ''} @@ -944,7 +943,7 @@ ${functionsType === 'operators' ? `import { isNumericType } from '../../shared/e ); await writeFile( join(__dirname, '../src/definitions/generated/operators.ts'), - printGeneratedFunctionsFile(enrichOperators(operatorDefinitions), 'operators') + printGeneratedFunctionsFile(enrichOperators(operatorDefinitions), 'operator') ); await writeFile( join(__dirname, '../src/definitions/generated/grouping_functions.ts'), diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts index 9945a66320f26..c7c026dde787e 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts @@ -60,7 +60,7 @@ describe('WHERE ', () => { 'where', 'boolean', { - builtin: true, + operators: true, }, undefined, ['and', 'or', 'not'] @@ -122,7 +122,7 @@ describe('WHERE ', () => { ...getFunctionSignaturesByReturnType('where', 'any', { scalar: true }), ]); await assertSuggestions(`from a | where keywordField >= keywordField ${op} doubleField /`, [ - ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), + ...getFunctionSignaturesByReturnType('where', 'boolean', { operators: true }, ['double']), ]); await assertSuggestions( `from a | where keywordField >= keywordField ${op} doubleField == /`, @@ -158,9 +158,12 @@ describe('WHERE ', () => { const { assertSuggestions } = await setup(); await assertSuggestions('from a | stats a=avg(doubleField) | where a /', [ - ...getFunctionSignaturesByReturnType('where', 'any', { builtin: true, skipAssign: true }, [ - 'double', - ]), + ...getFunctionSignaturesByReturnType( + 'where', + 'any', + { operators: true, skipAssign: true }, + ['double'] + ), ]); }); @@ -212,8 +215,8 @@ describe('WHERE ', () => { const { assertSuggestions } = await setup(); await assertSuggestions('from a | where log10(doubleField) /', [ - ...getFunctionSignaturesByReturnType('where', 'double', { builtin: true }, ['double']), - ...getFunctionSignaturesByReturnType('where', 'boolean', { builtin: true }, ['double']), + ...getFunctionSignaturesByReturnType('where', 'double', { operators: true }, ['double']), + ...getFunctionSignaturesByReturnType('where', 'boolean', { operators: true }, ['double']), ]); }); @@ -239,7 +242,7 @@ describe('WHERE ', () => { ...getFunctionSignaturesByReturnType( 'where', 'boolean', - { builtin: true }, + { operators: true }, ['boolean'], [':'] ), @@ -320,7 +323,7 @@ describe('WHERE ', () => { ...getFunctionSignaturesByReturnType( 'where', 'any', - { builtin: true, skipAssign: true }, + { operators: true, skipAssign: true }, ['double'], [':'] ), diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts index 506862138ae8f..706893a3b42b5 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts @@ -59,7 +59,7 @@ describe('autocomplete.suggest', () => { ]); await assertSuggestions('from a | eval doubleField /', [ - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ + ...getFunctionSignaturesByReturnType('eval', 'any', { operators: true, skipAssign: true }, [ 'double', ]), ',', @@ -145,7 +145,7 @@ describe('autocomplete.suggest', () => { await assertSuggestions('from a | eval a=round(doubleField) /', [ ',', '| ', - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ + ...getFunctionSignaturesByReturnType('eval', 'any', { operators: true, skipAssign: true }, [ 'double', 'long', ]), @@ -362,7 +362,7 @@ describe('autocomplete.suggest', () => { await assertSuggestions('from a | eval var0 = abs(doubleField) / | eval abs(var0)', [ ',', '| ', - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ + ...getFunctionSignaturesByReturnType('eval', 'any', { operators: true, skipAssign: true }, [ 'double', ]), ]); @@ -454,7 +454,7 @@ describe('autocomplete.suggest', () => { // Wehther to prepend comma to suggestion string // E.g. if true, "fieldName" -> "fieldName, " - const shouldAddComma = hasMoreMandatoryArgs && fn.type !== 'builtin'; + const shouldAddComma = hasMoreMandatoryArgs && fn.type !== 'operator'; const constantOnlyParamDefs = typesToSuggestNext.filter( (p) => p.constantOnly || /_literal/.test(p.type as string) @@ -551,9 +551,12 @@ describe('autocomplete.suggest', () => { ...dateSuggestions, ',', '| ', - ...getFunctionSignaturesByReturnType('eval', 'any', { builtin: true, skipAssign: true }, [ - 'integer', - ]), + ...getFunctionSignaturesByReturnType( + 'eval', + 'any', + { operators: true, skipAssign: true }, + ['integer'] + ), ], { triggerCharacter: ' ' } ); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index edaec2db13374..36c2163604fb7 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -10,7 +10,7 @@ import { camelCase } from 'lodash'; import { parse } from '@kbn/esql-ast'; import { scalarFunctionDefinitions } from '../../definitions/generated/scalar_functions'; -import { builtinFunctions } from '../../definitions/builtin'; +import { operatorsDefinitions } from '../../definitions/all_operators'; import { NOT_SUGGESTED_TYPES } from '../../shared/resources_helpers'; import { aggregationFunctionDefinitions } from '../../definitions/generated/aggregation_functions'; import { timeUnitsToSuggest } from '../../definitions/literals'; @@ -137,7 +137,7 @@ export function getFunctionSignaturesByReturnType( agg, grouping, scalar, - builtin, + operators, // skipAssign here is used to communicate to not propose an assignment if it's not possible // within the current context (the actual logic has it, but here we want a shortcut) skipAssign, @@ -145,7 +145,7 @@ export function getFunctionSignaturesByReturnType( agg?: boolean; grouping?: boolean; scalar?: boolean; - builtin?: boolean; + operators?: boolean; skipAssign?: boolean; } = {}, paramsTypes?: Readonly, @@ -167,8 +167,8 @@ export function getFunctionSignaturesByReturnType( if (scalar) { list.push(...scalarFunctionDefinitions); } - if (builtin) { - list.push(...builtinFunctions.filter(({ name }) => (skipAssign ? name !== '=' : true))); + if (operators) { + list.push(...operatorsDefinitions.filter(({ name }) => (skipAssign ? name !== '=' : true))); } const deduped = Array.from(new Set(list)); @@ -217,7 +217,7 @@ export function getFunctionSignaturesByReturnType( .map((definition) => { const { type, name, signatures } = definition; - if (type === 'builtin') { + if (type === 'operator') { return { text: signatures.some(({ params }) => params.length > 1) ? `${name.toUpperCase()} $0` diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts index 584a11ac3cb62..51bb5c7ba165a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts @@ -80,7 +80,7 @@ describe('hidden functions', () => { it('does not suggest hidden operators', async () => { setTestFunctions([ { - type: 'builtin', + type: 'operator', name: 'HIDDEN_OPERATOR', description: 'This is a hidden function', supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -97,7 +97,7 @@ describe('hidden functions', () => { ], }, { - type: 'builtin', + type: 'operator', name: 'VISIBLE_OPERATOR', description: 'This is a visible function', supportedCommands: ['eval', 'where', 'row', 'sort'], diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts index fce7aa8ae9e44..d5c0620be0999 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.test.ts @@ -536,7 +536,7 @@ describe('autocomplete', () => { 'where', 'boolean', { - builtin: true, + operators: true, }, undefined, ['and', 'or', 'not'] @@ -550,7 +550,7 @@ describe('autocomplete', () => { 'where', 'any', { - builtin: true, + operators: true, skipAssign: true, }, ['integer'], @@ -924,7 +924,7 @@ describe('autocomplete', () => { 'where', 'boolean', { - builtin: true, + operators: true, }, ['keyword'] ).map((s) => (s.text.toLowerCase().includes('null') ? s : attachTriggerCommand(s))) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index ba23575931c8b..5212f20827326 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -104,7 +104,7 @@ import { checkFunctionInvocationComplete, } from './helper'; import { FunctionParameter, isParameterType } from '../definitions/types'; -import { comparisonFunctions } from '../definitions/builtin'; +import { comparisonFunctions } from '../definitions/all_operators'; import { getRecommendedQueriesSuggestions } from './recommended_queries/suggestions'; type GetFieldsMapFn = () => Promise>; @@ -992,11 +992,11 @@ async function getFunctionArgsSuggestions( const shouldAddComma = hasMoreMandatoryArgs && - fnDefinition.type !== 'builtin' && + fnDefinition.type !== 'operator' && !isCursorFollowedByComma && !canBeBooleanCondition; const shouldAdvanceCursor = - hasMoreMandatoryArgs && fnDefinition.type !== 'builtin' && !isCursorFollowedByComma; + hasMoreMandatoryArgs && fnDefinition.type !== 'operator' && !isCursorFollowedByComma; const suggestedConstants = uniq( typesToSuggestNext diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts index 3e63ef9bfe46c..b022a73ed6fa0 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts @@ -8,7 +8,7 @@ */ import { Walker, type ESQLSingleAstItem, type ESQLFunction } from '@kbn/esql-ast'; -import { logicalOperators } from '../../../definitions/builtin'; +import { logicalOperators } from '../../../definitions/all_operators'; import { CommandSuggestParams, isParameterType } from '../../../definitions/types'; import { isFunctionItem } from '../../../shared/helpers'; import type { SuggestionRawDefinition } from '../../types'; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts index eef398ae4db0f..565aae969469a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/complete_items.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import type { ItemKind, SuggestionRawDefinition } from './types'; -import { builtinFunctions } from '../definitions/builtin'; +import { operatorsDefinitions } from '../definitions/all_operators'; import { getOperatorSuggestion, TRIGGER_SUGGESTION_COMMAND } from './factories'; import { CommandDefinition, CommandTypeDefinition } from '../definitions/types'; import { getCommandDefinition } from '../shared/helpers'; @@ -24,7 +24,7 @@ const techPreviewLabel = i18n.translate( ); export function getAssignmentDefinitionCompletitionItem() { - const assignFn = builtinFunctions.find(({ name }) => name === '=')!; + const assignFn = operatorsDefinitions.find(({ name }) => name === '=')!; return getOperatorSuggestion(assignFn); } diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index b4ef8a84cb341..9325ef50a785e 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -27,7 +27,7 @@ import { DOUBLE_BACKTICK, SINGLE_TICK_REGEX } from '../shared/constants'; import { ESQLRealField } from '../validation/types'; import { isNumericType } from '../shared/esql_types'; import { getTestFunctions } from '../shared/test_functions'; -import { builtinFunctions } from '../definitions/builtin'; +import { operatorsDefinitions } from '../definitions/all_operators'; import { ESQLVariableType, ESQLControlVariable } from '../shared/types'; const techPreviewLabel = i18n.translate( @@ -168,7 +168,9 @@ export const getOperatorSuggestions = ( predicates?: FunctionFilterPredicates & { leftParamType?: FunctionParameterType } ): SuggestionRawDefinition[] => { const filteredDefinitions = filterFunctionDefinitions( - getTestFunctions().length ? [...builtinFunctions, ...getTestFunctions()] : builtinFunctions, + getTestFunctions().length + ? [...operatorsDefinitions, ...getTestFunctions()] + : operatorsDefinitions, predicates ); @@ -188,7 +190,7 @@ export const getOperatorSuggestions = ( }; export const getSuggestionsAfterNot = (): SuggestionRawDefinition[] => { - return builtinFunctions + return operatorsDefinitions .filter(({ name }) => name === 'like' || name === 'rlike' || name === 'in') .map(getOperatorSuggestion); }; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts index 5f54c1bfb5367..0cc2d4c8f565a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts @@ -291,7 +291,7 @@ export function getValidSignaturesAndTypesToSuggestNext( // E.g. if true, "fieldName" -> "fieldName, " const alreadyHasComma = fullText ? fullText[offset] === ',' : false; const shouldAddComma = - hasMoreMandatoryArgs && fnDefinition.type !== 'builtin' && !alreadyHasComma; + hasMoreMandatoryArgs && fnDefinition.type !== 'operator' && !alreadyHasComma; const currentArg = enrichedArgs[argIndex]; return { shouldAddComma, @@ -610,7 +610,7 @@ export async function getSuggestionsToRightOfOperatorExpression({ // technically another boolean value should be suggested, but it is a better experience // to actually suggest a wider set of fields/functions const typeToUse = - finalType === 'boolean' && getFunctionDefinition(operator.name)?.type === 'builtin' + finalType === 'boolean' && getFunctionDefinition(operator.name)?.type === 'operator' ? ['any'] : (supportedTypes as string[]); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/builtin.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts similarity index 59% rename from src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/builtin.ts rename to src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts index eacad51ee7b59..78cfaee709d4b 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/builtin.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts @@ -8,37 +8,10 @@ */ import { i18n } from '@kbn/i18n'; -import { isNumericType } from '../shared/esql_types'; import type { FunctionDefinition, FunctionParameterType, FunctionReturnType } from './types'; -import { operatorsFunctionDefinitions } from './generated/operators'; +import { operatorFunctionDefinitions } from './generated/operators'; type MathFunctionSignature = [FunctionParameterType, FunctionParameterType, FunctionReturnType]; -function createMathDefinition( - name: string, - functionSignatures: MathFunctionSignature[], - description: string, - validate?: FunctionDefinition['validate'] -): FunctionDefinition { - return { - type: 'builtin', - name, - description, - supportedCommands: ['eval', 'where', 'row', 'stats', 'metrics', 'sort'], - supportedOptions: ['by'], - signatures: functionSignatures.map((functionSignature) => { - const [lhs, rhs, result] = functionSignature; - return { - params: [ - { name: 'left', type: lhs }, - { name: 'right', type: rhs }, - ], - returnType: result, - }; - }), - validate, - }; -} - // https://www.elastic.co/guide/en/elasticsearch/reference/master/esql-functions-operators.html#_less_than const baseComparisonTypeTable: MathFunctionSignature[] = [ ['date', 'date', 'boolean'], @@ -84,7 +57,7 @@ function createComparisonDefinition( }); return { - type: 'builtin' as const, + type: 'operator' as const, name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -121,176 +94,9 @@ function createComparisonDefinition( }; } -const addTypeTable: MathFunctionSignature[] = [ - ['date_period', 'date_period', 'date_period'], - ['date_period', 'date', 'date'], - ['date', 'date_period', 'date'], - ['date', 'time_duration', 'date'], - ['date', 'time_literal', 'date'], - ['double', 'double', 'double'], - ['double', 'integer', 'double'], - ['double', 'long', 'double'], - ['integer', 'double', 'double'], - ['integer', 'integer', 'integer'], - ['integer', 'long', 'long'], - ['long', 'double', 'double'], - ['long', 'integer', 'long'], - ['long', 'long', 'long'], - ['time_duration', 'date', 'date'], - ['time_duration', 'time_duration', 'time_duration'], - ['unsigned_long', 'unsigned_long', 'unsigned_long'], - ['time_literal', 'date', 'date'], -]; - -const subtractTypeTable: MathFunctionSignature[] = [ - ['date_period', 'date_period', 'date_period'], - ['date', 'date_period', 'date'], - ['date', 'time_duration', 'date'], - ['date', 'time_literal', 'date'], - ['double', 'double', 'double'], - ['double', 'integer', 'double'], - ['double', 'long', 'double'], - ['integer', 'double', 'double'], - ['integer', 'integer', 'integer'], - ['integer', 'long', 'long'], - ['long', 'double', 'double'], - ['long', 'integer', 'long'], - ['long', 'long', 'long'], - ['time_duration', 'date', 'date'], - ['time_duration', 'time_duration', 'time_duration'], - ['unsigned_long', 'unsigned_long', 'unsigned_long'], - ['time_literal', 'date', 'date'], -]; - -const multiplyTypeTable: MathFunctionSignature[] = [ - ['double', 'double', 'double'], - ['double', 'integer', 'double'], - ['double', 'long', 'double'], - ['integer', 'double', 'double'], - ['integer', 'integer', 'integer'], - ['integer', 'long', 'long'], - ['long', 'double', 'double'], - ['long', 'integer', 'long'], - ['long', 'long', 'long'], - ['unsigned_long', 'unsigned_long', 'unsigned_long'], -]; - -const divideTypeTable: MathFunctionSignature[] = [ - ['double', 'double', 'double'], - ['double', 'integer', 'double'], - ['double', 'long', 'double'], - ['integer', 'double', 'double'], - ['integer', 'integer', 'integer'], - ['integer', 'long', 'long'], - ['long', 'double', 'double'], - ['long', 'integer', 'long'], - ['long', 'long', 'long'], - ['unsigned_long', 'unsigned_long', 'unsigned_long'], -]; - -const modulusTypeTable: MathFunctionSignature[] = [ - ['double', 'double', 'double'], - ['double', 'integer', 'double'], - ['double', 'long', 'double'], - ['integer', 'double', 'double'], - ['integer', 'integer', 'integer'], - ['integer', 'long', 'long'], - ['long', 'double', 'double'], - ['long', 'integer', 'long'], - ['long', 'long', 'long'], - ['unsigned_long', 'unsigned_long', 'unsigned_long'], -]; - -export const mathFunctions: FunctionDefinition[] = [ - createMathDefinition( - '+', - addTypeTable, - i18n.translate('kbn-esql-validation-autocomplete.esql.definition.addDoc', { - defaultMessage: 'Add (+)', - }) - ), - createMathDefinition( - '-', - subtractTypeTable, - i18n.translate('kbn-esql-validation-autocomplete.esql.definition.subtractDoc', { - defaultMessage: 'Subtract (-)', - }) - ), - createMathDefinition( - '*', - multiplyTypeTable, - i18n.translate('kbn-esql-validation-autocomplete.esql.definition.multiplyDoc', { - defaultMessage: 'Multiply (*)', - }) - ), - createMathDefinition( - '/', - divideTypeTable, - i18n.translate('kbn-esql-validation-autocomplete.esql.definition.divideDoc', { - defaultMessage: 'Divide (/)', - }), - (fnDef) => { - const [left, right] = fnDef.args; - const messages = []; - if (!Array.isArray(left) && !Array.isArray(right)) { - if (right.type === 'literal' && isNumericType(right.literalType)) { - if (right.value === 0) { - messages.push({ - type: 'warning' as const, - code: 'divideByZero', - text: i18n.translate( - 'kbn-esql-validation-autocomplete.esql.divide.warning.divideByZero', - { - defaultMessage: 'Cannot divide by zero: {left}/{right}', - values: { - left: left.text, - right: right.value, - }, - } - ), - location: fnDef.location, - }); - } - } - } - return messages; - } - ), - createMathDefinition( - '%', - modulusTypeTable, - i18n.translate('kbn-esql-validation-autocomplete.esql.definition.moduleDoc', { - defaultMessage: 'Module (%)', - }), - (fnDef) => { - const [left, right] = fnDef.args; - const messages = []; - if (!Array.isArray(left) && !Array.isArray(right)) { - if (right.type === 'literal' && isNumericType(right.literalType)) { - if (right.value === 0) { - messages.push({ - type: 'warning' as const, - code: 'moduleByZero', - text: i18n.translate( - 'kbn-esql-validation-autocomplete.esql.divide.warning.zeroModule', - { - defaultMessage: 'Module by zero can return null value: {left}%{right}', - values: { - left: left.text, - right: right.value, - }, - } - ), - location: fnDef.location, - }); - } - } - } - return messages; - } - ), -]; - +// these functions are also in the operatorFunctionDefinitions. There is no way to extract them from there +// because the operatorFunctionDefinitions are generated from ES definitions. This is why we need to +// duplicate them here export const comparisonFunctions: FunctionDefinition[] = [ { name: '==', @@ -398,7 +204,7 @@ export const logicalOperators: FunctionDefinition[] = [ }), }, ].map(({ name, description }) => ({ - type: 'builtin' as const, + type: 'operator' as const, name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -428,7 +234,7 @@ const nullFunctions: FunctionDefinition[] = [ }), }, ].map(({ name, description }) => ({ - type: 'builtin', + type: 'operator', name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -442,7 +248,7 @@ const nullFunctions: FunctionDefinition[] = [ const otherDefinitions: FunctionDefinition[] = [ { - type: 'builtin' as const, + type: 'operator' as const, name: 'not', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.notDoc', { defaultMessage: 'Not', @@ -457,7 +263,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'builtin' as const, + type: 'operator' as const, name: '=', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.assignDoc', { defaultMessage: 'Assign (=)', @@ -484,7 +290,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'builtin' as const, + type: 'operator' as const, name: 'as', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.asDoc', { defaultMessage: 'Rename as (AS)', @@ -502,7 +308,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'builtin' as const, + type: 'operator' as const, name: 'where', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.whereDoc', { defaultMessage: 'WHERE operator', @@ -522,7 +328,7 @@ const otherDefinitions: FunctionDefinition[] = [ { // TODO — this shouldn't be a function or an operator... name: 'info', - type: 'builtin', + type: 'operator', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.infoDoc', { defaultMessage: 'Show information about the current ES node', }), @@ -536,8 +342,8 @@ const otherDefinitions: FunctionDefinition[] = [ }, ]; -export const builtinFunctions: FunctionDefinition[] = [ - ...operatorsFunctionDefinitions, +export const operatorsDefinitions: FunctionDefinition[] = [ + ...operatorFunctionDefinitions, ...logicalOperators, ...nullFunctions, ...otherDefinitions, diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts index 2c421c90fb53d..497ea79f71e42 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts @@ -143,7 +143,7 @@ const statsValidator = (command: ESQLCommand) => { } // now check that: // * the agg function is at root level - // * or if it's a builtin function, then all operands are agg functions or literals + // * or if it's a operators function, then all operands are agg functions or literals // * or if it's a eval function then all arguments are agg functions or literals function checkFunctionContent(arg: ESQLFunction) { // TODO the grouping function check may not diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts index 385ed5836486e..8501775b9c53a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts @@ -33,7 +33,7 @@ import { isNumericType } from '../../shared/esql_types'; // Do not edit this manually... generated by scripts/generate_function_definitions.ts const addDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '+', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.add', { defaultMessage: @@ -377,7 +377,7 @@ const addDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const divDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '/', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.div', { defaultMessage: @@ -570,7 +570,7 @@ const divDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const equalsDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '==', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.equals', { defaultMessage: @@ -1060,7 +1060,7 @@ const equalsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const greaterThanDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '>', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.greater_than', { defaultMessage: @@ -1434,7 +1434,7 @@ const greaterThanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const greaterThanOrEqualDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '>=', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.greater_than_or_equal', @@ -1811,7 +1811,7 @@ const greaterThanOrEqualDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const inDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'in', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.in', { defaultMessage: @@ -2053,7 +2053,7 @@ const inDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const lessThanDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '<', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.less_than', { defaultMessage: @@ -2427,7 +2427,7 @@ const lessThanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const lessThanOrEqualDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '<=', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.less_than_or_equal', @@ -2748,7 +2748,7 @@ const lessThanOrEqualDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const likeDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'like', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.like', { defaultMessage: @@ -2830,7 +2830,7 @@ const likeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const matchOperatorDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: ':', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.match_operator', { defaultMessage: @@ -3343,7 +3343,7 @@ const matchOperatorDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const modDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '%', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mod', { defaultMessage: @@ -3536,7 +3536,7 @@ const modDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mulDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '*', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mul', { defaultMessage: @@ -3704,7 +3704,7 @@ const mulDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const negDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '-', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.neg', { defaultMessage: 'Returns the negation of the argument.', @@ -3771,7 +3771,7 @@ const negDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notEqualsDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '!=', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_equals', { defaultMessage: @@ -4261,7 +4261,7 @@ const notEqualsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notInDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'not_in', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_in', { defaultMessage: @@ -4505,7 +4505,7 @@ const notInDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notLikeDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'not_like', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_like', { defaultMessage: @@ -4555,7 +4555,7 @@ const notLikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notRlikeDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'not_rlike', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_rlike', { defaultMessage: @@ -4605,7 +4605,7 @@ const notRlikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const rlikeDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: 'rlike', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rlike', { defaultMessage: @@ -4689,7 +4689,7 @@ const rlikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const subDefinition: FunctionDefinition = { - type: 'builtin', + type: 'operator', name: '-', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sub', { defaultMessage: @@ -5000,7 +5000,7 @@ const subDefinition: FunctionDefinition = { validate: undefined, examples: [], }; -export const operatorsFunctionDefinitions = [ +export const operatorFunctionDefinitions = [ addDefinition, divDefinition, equalsDefinition, diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts index d3db0195d172d..11e215aa75714 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -175,7 +175,7 @@ export interface Signature { } export interface FunctionDefinition { - type: 'builtin' | 'agg' | 'scalar' | 'operator' | 'grouping'; + type: 'agg' | 'scalar' | 'operator' | 'grouping'; preview?: boolean; ignoreAsSuggestion?: boolean; name: string; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts index 2441db077af8a..8bc59fad94ff8 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts @@ -138,8 +138,8 @@ function isNotEnrichClauseAssigment(node: ESQLFunction, command: ESQLCommand) { return node.name !== '=' && command.name !== 'enrich'; } -function isBuiltinFunction(node: ESQLFunction) { - return getFunctionDefinition(node.name)?.type === 'builtin'; +function isOperator(node: ESQLFunction) { + return getFunctionDefinition(node.name)?.type === 'operator'; } /** @@ -187,7 +187,7 @@ export function getAstContext(queryString: string, ast: ESQLAst, offset: number) // be handled as functions for the stats command. // I expect this to simplify once https://github.com/elastic/kibana/issues/195418 // is complete - !(isBuiltinFunction(node) && command.name !== 'stats') + !(isOperator(node) && command.name !== 'stats') ) { // command ... fn( ) return { type: 'function' as const, command, node, option, setting }; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts index 200dee245a4cc..d58d5681422ee 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -26,7 +26,7 @@ import { ESQLProperNode, } from '@kbn/esql-ast/src/types'; import { aggregationFunctionDefinitions } from '../definitions/generated/aggregation_functions'; -import { builtinFunctions } from '../definitions/builtin'; +import { operatorsDefinitions } from '../definitions/all_operators'; import { commandDefinitions } from '../definitions/commands'; import { scalarFunctionDefinitions } from '../definitions/generated/scalar_functions'; import { groupingFunctionDefinitions } from '../definitions/generated/grouping_functions'; @@ -116,7 +116,7 @@ export function isMathFunction(query: string, offset: number) { const [opString] = queryTrimmed.split(' ').reverse(); // compare last char for all math functions // limit only to 2 chars operators - const fns = builtinFunctions.filter(({ name }) => name.length < 3).map(({ name }) => name); + const fns = operatorsDefinitions.filter(({ name }) => name.length < 3).map(({ name }) => name); const tokenMatch = fns.some((op) => opString === op); // there's a match, that's good if (tokenMatch) { @@ -143,7 +143,7 @@ let commandLookups: Map> | undefined; function buildFunctionLookup() { // we always refresh if we have test functions if (!fnLookups || getTestFunctions().length) { - fnLookups = builtinFunctions + fnLookups = operatorsDefinitions .concat( scalarFunctionDefinitions, aggregationFunctionDefinitions, diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts index c16f97c5f0353..df1a8b2e5314d 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts @@ -170,7 +170,7 @@ describe('function validation', () => { it('list type', async () => { const testFn: FunctionDefinition = { name: 'in', - type: 'builtin', + type: 'operator', description: '', supportedCommands: ['row'], signatures: [ diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts index a8fa55128251c..a1019dcb0715f 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.inlinestats.ts @@ -278,18 +278,18 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { for (const nesting of NESTED_DEPTHS) { describe(`depth = ${nesting}`, () => { - describe('builtin', () => { - const builtinWrapping = Array(nesting).fill('+1').join(''); + describe('operators', () => { + const operatorsWrapping = Array(nesting).fill('+1').join(''); test('no errors', async () => { const { expectErrors } = await setup(); await expectErrors( - `from a_index | INLINESTATS 5 + avg(doubleField) ${builtinWrapping}`, + `from a_index | INLINESTATS 5 + avg(doubleField) ${operatorsWrapping}`, [] ); await expectErrors( - `from a_index | INLINESTATS 5 ${builtinWrapping} + avg(doubleField)`, + `from a_index | INLINESTATS 5 ${operatorsWrapping} + avg(doubleField)`, [] ); }); @@ -298,21 +298,21 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { const { expectErrors } = await setup(); await expectErrors( - `from a_index | INLINESTATS 5 ${builtinWrapping} + doubleField`, + `from a_index | INLINESTATS 5 ${operatorsWrapping} + doubleField`, [ - `At least one aggregation function required in [INLINESTATS], found [5${builtinWrapping}+doubleField]`, + `At least one aggregation function required in [INLINESTATS], found [5${operatorsWrapping}+doubleField]`, ] ); await expectErrors( - `from a_index | INLINESTATS 5 + doubleField ${builtinWrapping}`, + `from a_index | INLINESTATS 5 + doubleField ${operatorsWrapping}`, [ - `At least one aggregation function required in [INLINESTATS], found [5+doubleField${builtinWrapping}]`, + `At least one aggregation function required in [INLINESTATS], found [5+doubleField${operatorsWrapping}]`, ] ); await expectErrors( - `from a_index | INLINESTATS 5 + doubleField ${builtinWrapping}, var0 = sum(doubleField)`, + `from a_index | INLINESTATS 5 + doubleField ${operatorsWrapping}, var0 = sum(doubleField)`, [ - `At least one aggregation function required in [INLINESTATS], found [5+doubleField${builtinWrapping}]`, + `At least one aggregation function required in [INLINESTATS], found [5+doubleField${operatorsWrapping}]`, ] ); }); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts index 5aed8c952c948..ae8f1e6fdd9a0 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/test_suites/validation.command.stats.ts @@ -272,18 +272,18 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { for (const nesting of NESTED_DEPTHS) { describe(`depth = ${nesting}`, () => { - describe('builtin', () => { - const builtinWrapping = Array(nesting).fill('+1').join(''); + describe('operators', () => { + const operatorsWrapping = Array(nesting).fill('+1').join(''); test('no errors', async () => { const { expectErrors } = await setup(); await expectErrors( - `from a_index | stats 5 + avg(doubleField) ${builtinWrapping}`, + `from a_index | stats 5 + avg(doubleField) ${operatorsWrapping}`, [] ); await expectErrors( - `from a_index | stats 5 ${builtinWrapping} + avg(doubleField)`, + `from a_index | stats 5 ${operatorsWrapping} + avg(doubleField)`, [] ); }); @@ -291,16 +291,16 @@ export const validationStatsCommandTestSuite = (setup: helpers.Setup) => { test('errors', async () => { const { expectErrors } = await setup(); - await expectErrors(`from a_index | stats 5 ${builtinWrapping} + doubleField`, [ - `At least one aggregation function required in [STATS], found [5${builtinWrapping}+doubleField]`, + await expectErrors(`from a_index | stats 5 ${operatorsWrapping} + doubleField`, [ + `At least one aggregation function required in [STATS], found [5${operatorsWrapping}+doubleField]`, ]); - await expectErrors(`from a_index | stats 5 + doubleField ${builtinWrapping}`, [ - `At least one aggregation function required in [STATS], found [5+doubleField${builtinWrapping}]`, + await expectErrors(`from a_index | stats 5 + doubleField ${operatorsWrapping}`, [ + `At least one aggregation function required in [STATS], found [5+doubleField${operatorsWrapping}]`, ]); await expectErrors( - `from a_index | stats 5 + doubleField ${builtinWrapping}, var0 = sum(doubleField)`, + `from a_index | stats 5 + doubleField ${operatorsWrapping}, var0 = sum(doubleField)`, [ - `At least one aggregation function required in [STATS], found [5+doubleField${builtinWrapping}]`, + `At least one aggregation function required in [STATS], found [5+doubleField${operatorsWrapping}]`, ] ); }); diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index e303d7bcbafda..6655ed8407ebb 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -5363,10 +5363,8 @@ "kbn-esql-validation-autocomplete.esql.autocomplete.timeSystemParamStart": "L'heure de début à partir du sélecteur de date", "kbn-esql-validation-autocomplete.esql.autocomplete.valueDefinition": "Valeur littérale", "kbn-esql-validation-autocomplete.esql.autocomplete.variableDefinition": "Variable spécifiée par l'utilisateur dans la requête ES|QL", - "kbn-esql-validation-autocomplete.esql.definition.addDoc": "Ajouter (+)", "kbn-esql-validation-autocomplete.esql.definition.andDoc": "et", "kbn-esql-validation-autocomplete.esql.definition.assignDoc": "Affecter (=)", - "kbn-esql-validation-autocomplete.esql.definition.divideDoc": "Diviser (/)", "kbn-esql-validation-autocomplete.esql.definition.equalToDoc": "Égal à", "kbn-esql-validation-autocomplete.esql.definition.greaterThanDoc": "Supérieur à", "kbn-esql-validation-autocomplete.esql.definition.greaterThanOrEqualToDoc": "Supérieur ou égal à", @@ -5375,12 +5373,9 @@ "kbn-esql-validation-autocomplete.esql.definition.isNullDoc": "Prédicat pour la comparaison NULL : renvoie \"true\" si la valeur est NULL", "kbn-esql-validation-autocomplete.esql.definition.lessThanDoc": "Inférieur à", "kbn-esql-validation-autocomplete.esql.definition.lessThanOrEqualToDoc": "Inférieur ou égal à", - "kbn-esql-validation-autocomplete.esql.definition.moduleDoc": "Module (%)", - "kbn-esql-validation-autocomplete.esql.definition.multiplyDoc": "Multiplier (*)", "kbn-esql-validation-autocomplete.esql.definition.notDoc": "Non", "kbn-esql-validation-autocomplete.esql.definition.notEqualToDoc": "Différent de", "kbn-esql-validation-autocomplete.esql.definition.orDoc": "ou", - "kbn-esql-validation-autocomplete.esql.definition.subtractDoc": "Subtract (-)", "kbn-esql-validation-autocomplete.esql.definitions.abs": "Renvoie la valeur absolue.", "kbn-esql-validation-autocomplete.esql.definitions.acos": "Renvoie l'arc cosinus de `n` sous forme d'angle, exprimé en radians.", "kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc": "Le ou les caractères qui séparent les champs ajoutés. A pour valeur par défaut une chaîne vide (\"\").", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index cd0a6bc2c7311..72e94ddc729af 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -5357,10 +5357,8 @@ "kbn-esql-validation-autocomplete.esql.autocomplete.timeSystemParamStart": "日付ピッカーの開始日時", "kbn-esql-validation-autocomplete.esql.autocomplete.valueDefinition": "リテラル値", "kbn-esql-validation-autocomplete.esql.autocomplete.variableDefinition": "ES|QLクエリーでユーザーが指定した変数", - "kbn-esql-validation-autocomplete.esql.definition.addDoc": "加算(+)", "kbn-esql-validation-autocomplete.esql.definition.andDoc": "AND", "kbn-esql-validation-autocomplete.esql.definition.assignDoc": "割り当て(=)", - "kbn-esql-validation-autocomplete.esql.definition.divideDoc": "除算(/)", "kbn-esql-validation-autocomplete.esql.definition.equalToDoc": "等しい", "kbn-esql-validation-autocomplete.esql.definition.greaterThanDoc": "より大きい", "kbn-esql-validation-autocomplete.esql.definition.greaterThanOrEqualToDoc": "よりも大きいまたは等しい", @@ -5369,12 +5367,9 @@ "kbn-esql-validation-autocomplete.esql.definition.isNullDoc": "NULL比較の述部:値がNULLである場合にTrueを返します", "kbn-esql-validation-autocomplete.esql.definition.lessThanDoc": "より小さい", "kbn-esql-validation-autocomplete.esql.definition.lessThanOrEqualToDoc": "以下", - "kbn-esql-validation-autocomplete.esql.definition.moduleDoc": "モジュール(%)", - "kbn-esql-validation-autocomplete.esql.definition.multiplyDoc": "乗算(*)", "kbn-esql-validation-autocomplete.esql.definition.notDoc": "NOT", "kbn-esql-validation-autocomplete.esql.definition.notEqualToDoc": "Not equal to", "kbn-esql-validation-autocomplete.esql.definition.orDoc": "または", - "kbn-esql-validation-autocomplete.esql.definition.subtractDoc": "減算(-)", "kbn-esql-validation-autocomplete.esql.definitions.abs": "絶対値を返します。", "kbn-esql-validation-autocomplete.esql.definitions.acos": "nのアークコサインをラジアンで表記された角度として返します。", "kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc": "追加されたフィールドを区切る文字。デフォルトは空の文字列(\"\")です。", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 9d10e358cd5af..86757243ecddb 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -5398,10 +5398,8 @@ "kbn-esql-validation-autocomplete.esql.autocomplete.timeSystemParamStart": "日期选取器中的开始时间", "kbn-esql-validation-autocomplete.esql.autocomplete.valueDefinition": "文本值", "kbn-esql-validation-autocomplete.esql.autocomplete.variableDefinition": "用户在 ES|QL 查询中指定的变量", - "kbn-esql-validation-autocomplete.esql.definition.addDoc": "添加 (+)", "kbn-esql-validation-autocomplete.esql.definition.andDoc": "且", "kbn-esql-validation-autocomplete.esql.definition.assignDoc": "分配 (=)", - "kbn-esql-validation-autocomplete.esql.definition.divideDoc": "除 (/)", "kbn-esql-validation-autocomplete.esql.definition.equalToDoc": "等于", "kbn-esql-validation-autocomplete.esql.definition.greaterThanDoc": "大于", "kbn-esql-validation-autocomplete.esql.definition.greaterThanOrEqualToDoc": "大于或等于", @@ -5410,12 +5408,9 @@ "kbn-esql-validation-autocomplete.esql.definition.isNullDoc": "用于 NULL 比较的谓词:如果值为 NULL,则返回 true", "kbn-esql-validation-autocomplete.esql.definition.lessThanDoc": "小于", "kbn-esql-validation-autocomplete.esql.definition.lessThanOrEqualToDoc": "小于或等于", - "kbn-esql-validation-autocomplete.esql.definition.moduleDoc": "取余数 (%)", - "kbn-esql-validation-autocomplete.esql.definition.multiplyDoc": "乘 (*)", "kbn-esql-validation-autocomplete.esql.definition.notDoc": "非", "kbn-esql-validation-autocomplete.esql.definition.notEqualToDoc": "不等于", "kbn-esql-validation-autocomplete.esql.definition.orDoc": "或", - "kbn-esql-validation-autocomplete.esql.definition.subtractDoc": "减 (-)", "kbn-esql-validation-autocomplete.esql.definitions.abs": "返回绝对值。", "kbn-esql-validation-autocomplete.esql.definitions.acos": "返回 `n` 的反余弦作为角度,以弧度表示。", "kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc": "分隔已追加字段的字符。默认为空字符串 (\"\")。", From 0dfefe59de5759f1cd0135f4d4e5f8fbfa85c83d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 00:58:59 +1100 Subject: [PATCH 04/23] [8.x] [ResponseOps][Observability][Alerts] Fix missing alert grouping controls in o11y alerts page (#211160) (#211545) # Backport This will backport the following commits from `main` to `8.x`: - [[ResponseOps][Observability][Alerts] Fix missing alert grouping controls in o11y alerts page (#211160)](https://github.com/elastic/kibana/pull/211160) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Umberto Pepato --- .../components/error_fallback.tsx | 2 + .../response-ops/alerts-table/constants.ts | 1 + .../grouping_toolbar_controls.ts} | 34 ++--- .../components/related_alerts.test.tsx | 69 ++++++++++ .../components/related_alerts.tsx | 7 + .../public/pages/alerts/alerts.tsx | 7 + .../services/observability/alerts/common.ts | 6 + .../apps/observability/index.ts | 2 +- .../pages/alerts/table_configuration.ts | 120 ++++++++++++++++++ .../pages/alerts/table_storage.ts | 53 -------- 10 files changed, 223 insertions(+), 78 deletions(-) rename x-pack/solutions/observability/plugins/observability/public/components/alerts_table/{alerts/get_persistent_controls.ts => grouping/grouping_toolbar_controls.ts} (64%) create mode 100644 x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.test.tsx create mode 100644 x-pack/test/observability_functional/apps/observability/pages/alerts/table_configuration.ts delete mode 100644 x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts diff --git a/src/platform/packages/shared/response-ops/alerts-table/components/error_fallback.tsx b/src/platform/packages/shared/response-ops/alerts-table/components/error_fallback.tsx index 3f00851610b1b..20d7cb655ce37 100644 --- a/src/platform/packages/shared/response-ops/alerts-table/components/error_fallback.tsx +++ b/src/platform/packages/shared/response-ops/alerts-table/components/error_fallback.tsx @@ -9,6 +9,7 @@ import React from 'react'; import { EuiButton, EuiCode, EuiCopy, EuiEmptyPrompt } from '@elastic/eui'; +import { ERROR_PROMPT_TEST_ID } from '../constants'; import { FallbackComponent } from './error_boundary'; import { ALERTS_TABLE_UNKNOWN_ERROR_COPY_TO_CLIPBOARD_LABEL, @@ -37,6 +38,7 @@ export const ErrorFallback: FallbackComponent = ({ error }) => { )} } + data-test-subj={ERROR_PROMPT_TEST_ID} /> ); }; diff --git a/src/platform/packages/shared/response-ops/alerts-table/constants.ts b/src/platform/packages/shared/response-ops/alerts-table/constants.ts index d6b89eb64d5a6..35892e9563a9d 100644 --- a/src/platform/packages/shared/response-ops/alerts-table/constants.ts +++ b/src/platform/packages/shared/response-ops/alerts-table/constants.ts @@ -137,3 +137,4 @@ export const CELL_ACTIONS_EXPAND_TEST_ID = 'euiDataGridCellExpandButton'; export const FIELD_BROWSER_TEST_ID = 'fields-browser-container'; export const FIELD_BROWSER_BTN_TEST_ID = 'show-field-browser'; export const FIELD_BROWSER_CUSTOM_CREATE_BTN_TEST_ID = 'field-browser-custom-create-btn'; +export const ERROR_PROMPT_TEST_ID = 'alertsTableErrorPrompt'; diff --git a/x-pack/solutions/observability/plugins/observability/public/components/alerts_table/alerts/get_persistent_controls.ts b/x-pack/solutions/observability/plugins/observability/public/components/alerts_table/grouping/grouping_toolbar_controls.ts similarity index 64% rename from x-pack/solutions/observability/plugins/observability/public/components/alerts_table/alerts/get_persistent_controls.ts rename to x-pack/solutions/observability/plugins/observability/public/components/alerts_table/grouping/grouping_toolbar_controls.ts index 6e0f697e831a9..a386e0c6d222b 100644 --- a/x-pack/solutions/observability/plugins/observability/public/components/alerts_table/alerts/get_persistent_controls.ts +++ b/x-pack/solutions/observability/plugins/observability/public/components/alerts_table/grouping/grouping_toolbar_controls.ts @@ -5,30 +5,21 @@ * 2.0. */ -import { useMemo, useCallback } from 'react'; -import { type AlertsGroupingProps, useAlertsGroupingState } from '@kbn/alerts-grouping'; +import React, { useCallback } from 'react'; +import { useAlertsGroupingState } from '@kbn/alerts-grouping'; import { useAlertsDataView } from '@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view'; import { useGetGroupSelectorStateless } from '@kbn/grouping/src/hooks/use_get_group_selector'; -import { AlertsByGroupingAgg } from '../types'; +import { useKibana } from '../../../utils/kibana_react'; -interface GetPersistentControlsParams { +interface GroupingToolbarControlsProps { groupingId: string; ruleTypeIds: string[]; maxGroupingLevels?: number; - services: Pick< - AlertsGroupingProps['services'], - 'dataViews' | 'http' | 'notifications' - >; } -export const getPersistentControlsHook = - ({ - groupingId, - ruleTypeIds, - maxGroupingLevels = 3, - services: { dataViews, http, notifications }, - }: GetPersistentControlsParams) => - () => { +export const GroupingToolbarControls = React.memo( + ({ groupingId, ruleTypeIds, maxGroupingLevels = 3 }) => { + const { dataViews, http, notifications } = useKibana().services; const { grouping, updateGrouping } = useAlertsGroupingState(groupingId); const onGroupChange = useCallback( @@ -48,7 +39,7 @@ export const getPersistentControlsHook = toasts: notifications.toasts, }); - const groupSelector = useGetGroupSelectorStateless({ + return useGetGroupSelectorStateless({ groupingId, onGroupChange, fields: dataView?.fields ?? [], @@ -56,10 +47,5 @@ export const getPersistentControlsHook = grouping.options?.filter((option) => !grouping.activeGroups.includes(option.key)) ?? [], maxGroupingLevels, }); - - return useMemo(() => { - return { - right: groupSelector, - }; - }, [groupSelector]); - }; + } +); diff --git a/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.test.tsx b/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.test.tsx new file mode 100644 index 0000000000000..d51513240ac23 --- /dev/null +++ b/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.test.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '../../../utils/test_helper'; +import { alertWithGroupsAndTags } from '../mock/alert'; +import { useKibana } from '../../../utils/kibana_react'; +import { kibanaStartMock } from '../../../utils/kibana_react.mock'; +import { RelatedAlerts } from './related_alerts'; +import { ObservabilityAlertsTable } from '../../../components/alerts_table/alerts_table_lazy'; +import { + OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + observabilityAlertFeatureIds, +} from '../../../../common/constants'; + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useParams: jest.fn(), +})); + +jest.mock('../../../utils/kibana_react'); + +jest.mock('../../../components/alerts_table/alerts_table_lazy'); +const mockAlertsTable = jest.mocked(ObservabilityAlertsTable).mockReturnValue(
); + +jest.mock('@kbn/alerts-grouping', () => ({ + AlertsGrouping: jest.fn().mockImplementation(({ children }) =>
{children([])}
), +})); + +const useKibanaMock = useKibana as jest.Mock; +const mockKibana = () => { + useKibanaMock.mockReturnValue({ + services: { + ...kibanaStartMock.startContract().services, + http: { + basePath: { + prepend: jest.fn(), + }, + }, + }, + }); +}; + +describe('Related alerts', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockKibana(); + }); + + it('should pass the correct configuration options to the alerts table', async () => { + render(); + + expect(mockAlertsTable).toHaveBeenLastCalledWith( + expect.objectContaining({ + id: 'xpack.observability.related.alerts.table', + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + consumers: observabilityAlertFeatureIds, + initialPageSize: 50, + renderAdditionalToolbarControls: expect.any(Function), + showInspectButton: true, + }), + expect.anything() + ); + }); +}); diff --git a/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.tsx b/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.tsx index 50883729be74d..82f558ec28e46 100644 --- a/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.tsx +++ b/x-pack/solutions/observability/plugins/observability/public/pages/alert_details/components/related_alerts.tsx @@ -27,6 +27,7 @@ import { } from '@kbn/rule-data-utils'; import { BoolQuery, Filter, type Query } from '@kbn/es-query'; import { AlertsGrouping } from '@kbn/alerts-grouping'; +import { GroupingToolbarControls } from '../../../components/alerts_table/grouping/grouping_toolbar_controls'; import { ObservabilityFields } from '../../../../common/utils/alerting/types'; import { @@ -150,6 +151,12 @@ export function InternalRelatedAlerts({ alert }: Props) { consumers={observabilityAlertFeatureIds} query={mergeBoolQueries(esQuery, groupQuery)} initialPageSize={ALERTS_PER_PAGE} + renderAdditionalToolbarControls={() => ( + + )} showInspectButton /> ); diff --git a/x-pack/solutions/observability/plugins/observability/public/pages/alerts/alerts.tsx b/x-pack/solutions/observability/plugins/observability/public/pages/alerts/alerts.tsx index d2eae85660a32..24556488d553c 100644 --- a/x-pack/solutions/observability/plugins/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/solutions/observability/plugins/observability/public/pages/alerts/alerts.tsx @@ -54,6 +54,7 @@ import { HeaderMenu } from '../overview/components/header_menu/header_menu'; import { buildEsQuery } from '../../utils/build_es_query'; import { renderRuleStats, RuleStatsState } from './components/rule_stats'; import { mergeBoolQueries } from './helpers/merge_bool_queries'; +import { GroupingToolbarControls } from '../../components/alerts_table/grouping/grouping_toolbar_controls'; const ALERTS_SEARCH_BAR_ID = 'alerts-search-bar-o11y'; const ALERTS_PER_PAGE = 50; @@ -319,6 +320,12 @@ function InternalAlertsPage() { initialPageSize={ALERTS_PER_PAGE} onUpdate={onUpdate} columns={tableColumns} + renderAdditionalToolbarControls={() => ( + + )} showInspectButton /> ); diff --git a/x-pack/test/functional/services/observability/alerts/common.ts b/x-pack/test/functional/services/observability/alerts/common.ts index 4124f97df74a4..adde416503afc 100644 --- a/x-pack/test/functional/services/observability/alerts/common.ts +++ b/x-pack/test/functional/services/observability/alerts/common.ts @@ -22,6 +22,7 @@ const DATE_WITH_DATA = { const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; const FILTER_FOR_VALUE_BUTTON_SELECTOR = 'filterForValue'; const ALERTS_TABLE_CONTAINER_SELECTOR = 'alertsTable'; +const ALERTS_TABLE_ERROR_PROMPT_SELECTOR = 'alertsTableErrorPrompt'; const ALERTS_TABLE_ACTIONS_MENU_SELECTOR = 'alertsTableActionsMenu'; const VIEW_RULE_DETAILS_SELECTOR = 'viewRuleDetails'; const VIEW_RULE_DETAILS_FLYOUT_SELECTOR = 'viewRuleDetailsFlyout'; @@ -134,6 +135,10 @@ export function ObservabilityAlertsCommonProvider({ return await testSubjects.existOrFail(ALERTS_TABLE_CONTAINER_SELECTOR); }; + const ensureNoTableErrorPrompt = async () => { + return await testSubjects.missingOrFail(ALERTS_TABLE_ERROR_PROMPT_SELECTOR); + }; + const getNoDataPageOrFail = async () => { return await testSubjects.existOrFail('noDataPage'); }; @@ -404,6 +409,7 @@ export function ObservabilityAlertsCommonProvider({ getTableCellsInRows, getTableColumnHeaders, getTableOrFail, + ensureNoTableErrorPrompt, navigateToTimeWithData, setKibanaTimeZoneToUTC, openAlertsFlyout, diff --git a/x-pack/test/observability_functional/apps/observability/index.ts b/x-pack/test/observability_functional/apps/observability/index.ts index dce84cee32dfa..39b288363b350 100644 --- a/x-pack/test/observability_functional/apps/observability/index.ts +++ b/x-pack/test/observability_functional/apps/observability/index.ts @@ -16,7 +16,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./pages/alerts/pagination')); loadTestFile(require.resolve('./pages/alerts/rule_stats')); loadTestFile(require.resolve('./pages/alerts/state_synchronization')); - loadTestFile(require.resolve('./pages/alerts/table_storage')); + loadTestFile(require.resolve('./pages/alerts/table_configuration')); loadTestFile(require.resolve('./pages/alerts/custom_threshold_preview_chart')); loadTestFile(require.resolve('./pages/alerts/custom_threshold')); loadTestFile(require.resolve('./pages/cases/case_details')); diff --git a/x-pack/test/observability_functional/apps/observability/pages/alerts/table_configuration.ts b/x-pack/test/observability_functional/apps/observability/pages/alerts/table_configuration.ts new file mode 100644 index 0000000000000..39a14ec9c2566 --- /dev/null +++ b/x-pack/test/observability_functional/apps/observability/pages/alerts/table_configuration.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; + +import { + ALERT_EVALUATION_VALUE, + ALERT_EVALUATION_THRESHOLD, + ALERT_DURATION, + ALERT_REASON, + ALERT_RULE_NAME, + ALERT_START, + ALERT_STATUS, + ALERT_INSTANCE_ID, + TAGS, + ALERT_STATUS_ACTIVE, +} from '@kbn/rule-data-utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService, getPageObject }: FtrProviderContext) => { + describe('Observability alerts table configuration', function () { + this.tags('includeFirefox'); + + const observability = getService('observability'); + const esArchiver = getService('esArchiver'); + const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); + const browser = getService('browser'); + const retry = getService('retry'); + + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); + await esArchiver.load('x-pack/test/functional/es_archives/infra/simple_logs'); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/infra/simple_logs'); + await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); + }); + + it('renders correctly with a pre-existing persisted configuration', async () => { + await observability.alerts.common.navigateWithoutFilter(); + const LOCAL_STORAGE_KEY = 'xpack.observability.alerts.alert.table'; + await browser.setLocalStorageItem( + LOCAL_STORAGE_KEY, + `{"columns":[{"displayAsText":"Alert Status","id":"kibana.alert.status","initialWidth":120,"schema":"string"},{"displayAsText":"Triggered","id":"kibana.alert.start","initialWidth":190,"schema":"datetime"},{"displayAsText":"Duration","id":"kibana.alert.duration.us","initialWidth":70,"schema":"numeric"},{"displayAsText":"Rule name","id":"kibana.alert.rule.name","initialWidth":150,"schema":"string"},{"displayAsText":"Group","id":"kibana.alert.instance.id","initialWidth":100,"schema":"string"},{"displayAsText":"Observed value","id":"kibana.alert.evaluation.value","initialWidth":100,"schema":"conflict"},{"displayAsText":"Threshold","id":"kibana.alert.evaluation.threshold","initialWidth":100,"schema":"numeric"},{"displayAsText":"Tags","id":"tags","initialWidth":150,"schema":"string"},{"displayAsText":"Reason","id":"kibana.alert.reason","schema":"string"}],"sort":[{"kibana.alert.start":{"order":"desc"}}],"visibleColumns":["kibana.alert.status","kibana.alert.start","kibana.alert.duration.us","kibana.alert.rule.name","kibana.alert.instance.id","kibana.alert.evaluation.value","kibana.alert.evaluation.threshold","tags","kibana.alert.reason"]}` + ); + await observability.alerts.common.navigateWithoutFilter(); + await observability.alerts.common.ensureNoTableErrorPrompt(); + await browser.removeLocalStorageItem(LOCAL_STORAGE_KEY); + }); + + it('renders the correct columns', async () => { + await observability.alerts.common.navigateToTimeWithData(); + for (const colId of [ + ALERT_STATUS, + ALERT_START, + ALERT_DURATION, + ALERT_RULE_NAME, + ALERT_INSTANCE_ID, + ALERT_EVALUATION_VALUE, + ALERT_EVALUATION_THRESHOLD, + TAGS, + ALERT_REASON, + ]) { + expect(await testSubjects.exists(`dataGridHeaderCell-${colId}`)).to.be(true); + } + }); + + it('renders the group selector', async () => { + await observability.alerts.common.navigateToTimeWithData(); + expect(await testSubjects.exists('group-selector-dropdown')).to.be(true); + }); + + it('renders the correct alert actions', async () => { + await observability.alerts.common.navigateToTimeWithData(); + await observability.alerts.common.setAlertStatusFilter(ALERT_STATUS_ACTIVE); + await testSubjects.click('alertsTableRowActionMore'); + await retry.waitFor('alert actions popover visible', () => + testSubjects.exists('alertsTableActionsMenu') + ); + for (const action of [ + 'add-to-existing-case-action', + 'add-to-new-case-action', + 'viewRuleDetails', + 'viewAlertDetailsPage', + 'untrackAlert', + 'toggle-alert', + ]) { + expect(await testSubjects.exists(action, { allowHidden: true })).to.be(true); + } + }); + + it('remembers column changes', async () => { + await observability.alerts.common.navigateToTimeWithData(); + await dataGrid.clickHideColumn('kibana.alert.duration.us'); + + await observability.alerts.common.navigateToTimeWithData(); + + const durationColumnExists = await testSubjects.exists( + 'dataGridHeaderCell-kibana.alert.duration.us' + ); + expect(durationColumnExists).to.be(false); + }); + + it('remembers sorting changes', async () => { + await observability.alerts.common.navigateToTimeWithData(); + await dataGrid.clickDocSortAsc('kibana.alert.start'); + + await observability.alerts.common.navigateToTimeWithData(); + + const triggeredColumnHeading = await dataGrid.getHeaderElement('kibana.alert.start'); + expect(await triggeredColumnHeading.getAttribute('aria-sort')).to.be('ascending'); + }); + }); +}; diff --git a/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts b/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts deleted file mode 100644 index c39472715a353..0000000000000 --- a/x-pack/test/observability_functional/apps/observability/pages/alerts/table_storage.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../../../../ftr_provider_context'; - -export default ({ getService, getPageObject }: FtrProviderContext) => { - describe('Observability alert table state storage', function () { - this.tags('includeFirefox'); - - const observability = getService('observability'); - const esArchiver = getService('esArchiver'); - const testSubjects = getService('testSubjects'); - const dataGrid = getService('dataGrid'); - - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); - await esArchiver.load('x-pack/test/functional/es_archives/infra/simple_logs'); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/simple_logs'); - await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); - }); - - it('remembers column changes', async () => { - await observability.alerts.common.navigateToTimeWithData(); - await dataGrid.clickHideColumn('kibana.alert.duration.us'); - - await observability.alerts.common.navigateToTimeWithData(); - - const durationColumnExists = await testSubjects.exists( - 'dataGridHeaderCell-kibana.alert.duration.us' - ); - expect(durationColumnExists).to.be(false); - }); - - it('remembers sorting changes', async () => { - await observability.alerts.common.navigateToTimeWithData(); - await dataGrid.clickDocSortAsc('kibana.alert.start'); - - await observability.alerts.common.navigateToTimeWithData(); - - const triggeredColumnHeading = await dataGrid.getHeaderElement('kibana.alert.start'); - expect(await triggeredColumnHeading.getAttribute('aria-sort')).to.be('ascending'); - }); - }); -}; From 88aed407ff2bc275affd1e17dc374d3ce1133573 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 20 Feb 2025 09:35:55 -0500 Subject: [PATCH 05/23] [8.x] [Fleet] Fix flaky agent status field (#211453) (#211764) # Backport This will backport the following commits from `main` to `8.x`: - [[Fleet] Fix flaky agent status field (#211453)](https://github.com/elastic/kibana/pull/211453) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Elastic Machine --- .../agents/build_status_runtime_field.test.ts | 6 +++--- .../agents/build_status_runtime_field.ts | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts index 2c54d7d50c57c..c1b5b92ea9239 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts @@ -56,7 +56,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc['policy_id'].size() > 0 && ['policy-1'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, @@ -76,7 +76,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, @@ -124,7 +124,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L || ['policy-3'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567490123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L || ['policy-3'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567490123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts index 12314cb30ac68..6de1ae1359879 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts @@ -26,9 +26,17 @@ const _buildInactiveCondition = (opts: { inactivityTimeouts: InactivityTimeouts; maxAgentPoliciesWithInactivityTimeout: number; field: (path: string) => string; + fieldPath: (path: string) => string; logger?: Logger; }): string | null => { - const { now, inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, field, logger } = opts; + const { + now, + inactivityTimeouts, + maxAgentPoliciesWithInactivityTimeout, + field, + fieldPath, + logger, + } = opts; // if there are no policies with inactivity timeouts, then no agents are inactive if (inactivityTimeouts.length === 0) { return null; @@ -70,7 +78,9 @@ const _buildInactiveCondition = (opts: { }) .join(' || '); - return `lastCheckinMillis > 0 && ${field('policy_id')}.size() > 0 && ${policyClauses}`; + return `lastCheckinMillis > 0 && doc.containsKey(${fieldPath('policy_id')}) && ${field( + 'policy_id' + )}.size() > 0 && ${policyClauses}`; }; function _buildSource( @@ -81,12 +91,14 @@ function _buildSource( ) { const normalizedPrefix = pathPrefix ? `${pathPrefix}${pathPrefix.endsWith('.') ? '' : '.'}` : ''; const field = (path: string) => `doc['${normalizedPrefix + path}']`; + const fieldPath = (path: string) => `'${normalizedPrefix + path}'`; const now = Date.now(); const agentIsInactiveCondition = _buildInactiveCondition({ now, inactivityTimeouts, maxAgentPoliciesWithInactivityTimeout, field, + fieldPath, logger, }); From 17eae59e2bb3e1883dd17045a132c29dcb7e0582 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 01:53:43 +1100 Subject: [PATCH 06/23] [8.x] Update XState5 (main) (#211784) (#211897) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [Update XState5 (main) (#211784)](https://github.com/elastic/kibana/pull/211784) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: elastic-renovate-prod[bot] <174716857+elastic-renovate-prod[bot]@users.noreply.github.com> --- package.json | 6 +++--- .../kbn-xstate-utils/src/console_inspector.ts | 2 +- yarn.lock | 16 ++++++++-------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 1016e135fbde9..68ed9da5053ea 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.cd77847.0", "@types/react": "~18.2.0", "@types/react-dom": "~18.2.0", - "@xstate5/react/**/xstate": "^5.18.1", + "@xstate5/react/**/xstate": "^5.19.2", "globby/fast-glob": "^3.3.2" }, "dependencies": { @@ -1077,7 +1077,7 @@ "@turf/helpers": "6.0.1", "@turf/length": "^6.0.2", "@xstate/react": "^3.2.2", - "@xstate5/react": "npm:@xstate/react@^4.1.2", + "@xstate5/react": "npm:@xstate/react@^5.0.2", "@xyflow/react": "^12.4.1", "adm-zip": "^0.5.9", "ai": "^4.0.18", @@ -1305,7 +1305,7 @@ "whatwg-fetch": "^3.0.0", "xml2js": "^0.5.0", "xstate": "^4.38.2", - "xstate5": "npm:xstate@^5.18.1", + "xstate5": "npm:xstate@^5.19.2", "xterm": "^5.3.0", "yaml": "^2.5.1", "yauzl": "^2.10.0", diff --git a/src/platform/packages/shared/kbn-xstate-utils/src/console_inspector.ts b/src/platform/packages/shared/kbn-xstate-utils/src/console_inspector.ts index 8792ab44f3c28..7c5e2331b556c 100644 --- a/src/platform/packages/shared/kbn-xstate-utils/src/console_inspector.ts +++ b/src/platform/packages/shared/kbn-xstate-utils/src/console_inspector.ts @@ -44,7 +44,7 @@ export const createConsoleInspector = () => { '🔔 %c%s%c received event %c%s%c from %c%s%c:', ...styleAsActor(eventEvent.actorRef.id), ...styleAsKeyword(eventEvent.event.type), - ...styleAsKeyword(eventEvent.sourceRef?.id), + ...styleAsKeyword(eventEvent.sourceRef?.sessionId), eventEvent ); } else { diff --git a/yarn.lock b/yarn.lock index 6ee15e6a71b74..585b1c82d2f7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13322,10 +13322,10 @@ use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.0.0" -"@xstate5/react@npm:@xstate/react@^4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@xstate/react/-/react-4.1.2.tgz#4bfcdf2d9e9ef1eaea7388d1896649345e6679cd" - integrity sha512-orAidFrKCrU0ZwN5l/ABPlBfW2ziRDT2RrYoktRlZ0WRoLvA2E/uAC1JpZt43mCLtc8jrdwYCgJiqx1V8NvGTw== +"@xstate5/react@npm:@xstate/react@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@xstate/react/-/react-5.0.2.tgz#92185d20efedac97350c996cda29749c2e3fdbf1" + integrity sha512-x5GOrE0ZYjU2ba986u0CCp7SaPwzElSn1SW0mZ9MuBgsZ+BW7vTLVOvGmURynwojdso8d6nVbK3c2+MRVqGVgA== dependencies: use-isomorphic-layout-effect "^1.1.2" use-sync-external-store "^1.2.0" @@ -33951,10 +33951,10 @@ xpath@^0.0.33: resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.33.tgz#5136b6094227c5df92002e7c3a13516a5074eb07" integrity sha512-NNXnzrkDrAzalLhIUc01jO2mOzXGXh1JwPgkihcLLzw98c0WgYDmmjSh1Kl3wzaxSVWMuA+fe0WTWOBDWCBmNA== -"xstate5@npm:xstate@^5.18.1", xstate@^5.18.1: - version "5.18.1" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.18.1.tgz#c4d43ceaba6e6c31705d36bd96e285de4be4f7f4" - integrity sha512-m02IqcCQbaE/kBQLunwub/5i8epvkD2mFutnL17Oeg1eXTShe1sRF4D5mhv1dlaFO4vbW5gRGRhraeAD5c938g== +"xstate5@npm:xstate@^5.19.2", xstate@^5.19.2: + version "5.19.2" + resolved "https://registry.yarnpkg.com/xstate/-/xstate-5.19.2.tgz#db3f1ee614bbb6a49ad3f0c96ddbf98562d456ba" + integrity sha512-B8fL2aP0ogn5aviAXFzI5oZseAMqN00fg/TeDa3ZtatyDcViYLIfuQl4y8qmHCiKZgGEzmnTyNtNQL9oeJE2gw== xstate@^4.38.2: version "4.38.2" From b846cc90309465e6e15f42d028e8653a9052597f Mon Sep 17 00:00:00 2001 From: Kevin Lacabane Date: Thu, 20 Feb 2025 16:06:34 +0100 Subject: [PATCH 07/23] [8.x] [streams] lifecycle - ingestion and total docs metadata (#210301) (#211875) # Backport This will backport the following commits from `main` to `8.x`: - [[streams] lifecycle - ingestion and total docs metadata (#210301)](https://github.com/elastic/kibana/pull/210301) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) --- .../dataset_quality/common/api_types.ts | 1 + .../shared/dataset_quality/public/index.ts | 4 + .../data_streams_stats_client.ts | 7 +- .../get_data_streams_creation_date.ts | 45 +++++ .../server/routes/data_streams/routes.ts | 37 ++-- .../server/services/data_stream.ts | 2 +- .../get_mock_streams_app_context.tsx | 3 +- .../plugins/streams_app/kibana.jsonc | 1 + .../helpers/format_bytes.ts | 10 ++ .../helpers/ingestion_rate_query.ts | 55 ++++++ .../hooks/use_data_stream_stats.tsx | 58 ++++++ .../stream_detail_lifecycle/index.tsx | 57 ++++-- .../ingestion_rate.tsx | 169 ++++++++++++++++++ .../stream_detail_lifecycle/metadata.tsx | 48 ++++- .../stream_detail_lifecycle/summary.tsx | 2 +- .../plugins/streams_app/public/plugin.ts | 7 +- .../streams_app/public/services/types.ts | 7 +- .../plugins/streams_app/tsconfig.json | 3 + .../tests/data_streams/stats.spec.ts | 16 +- 19 files changed, 492 insertions(+), 40 deletions(-) create mode 100644 x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/get_data_streams_creation_date.ts create mode 100644 x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/format_bytes.ts create mode 100644 x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/ingestion_rate_query.ts create mode 100644 x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/hooks/use_data_stream_stats.tsx create mode 100644 x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/ingestion_rate.tsx diff --git a/x-pack/platform/plugins/shared/dataset_quality/common/api_types.ts b/x-pack/platform/plugins/shared/dataset_quality/common/api_types.ts index 7c64375e43fd5..b156368f9d15b 100644 --- a/x-pack/platform/plugins/shared/dataset_quality/common/api_types.ts +++ b/x-pack/platform/plugins/shared/dataset_quality/common/api_types.ts @@ -32,6 +32,7 @@ export const dataStreamStatRt = rt.intersection([ lastActivity: rt.number, integration: rt.string, totalDocs: rt.number, + creationDate: rt.number, }), ]); diff --git a/x-pack/platform/plugins/shared/dataset_quality/public/index.ts b/x-pack/platform/plugins/shared/dataset_quality/public/index.ts index 339be1ec1de9b..943707b252ce0 100644 --- a/x-pack/platform/plugins/shared/dataset_quality/public/index.ts +++ b/x-pack/platform/plugins/shared/dataset_quality/public/index.ts @@ -9,8 +9,12 @@ import type { PluginInitializerContext } from '@kbn/core/public'; import { DatasetQualityConfig } from '../common/plugin_config'; import { DatasetQualityPlugin } from './plugin'; +export type { DataStreamStatServiceResponse } from '../common/data_streams_stats'; export type { DatasetQualityPluginSetup, DatasetQualityPluginStart } from './types'; +export { DataStreamsStatsService } from './services/data_streams_stats/data_streams_stats_service'; +export type { IDataStreamsStatsClient } from './services/data_streams_stats/types'; + export function plugin(context: PluginInitializerContext) { return new DatasetQualityPlugin(context); } diff --git a/x-pack/platform/plugins/shared/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts b/x-pack/platform/plugins/shared/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts index deb97678b65ac..f389bbe80c8b2 100644 --- a/x-pack/platform/plugins/shared/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts +++ b/x-pack/platform/plugins/shared/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts @@ -41,12 +41,15 @@ export class DataStreamsStatsClient implements IDataStreamsStatsClient { public async getDataStreamsStats( params: GetDataStreamsStatsQuery ): Promise { - const types = params.types.length === 0 ? KNOWN_TYPES : params.types; + const types = + 'types' in params + ? rison.encodeArray(params.types.length === 0 ? KNOWN_TYPES : params.types) + : undefined; const response = await this.http .get('/internal/dataset_quality/data_streams/stats', { query: { ...params, - types: rison.encodeArray(types), + types, }, }) .catch((error) => { diff --git a/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/get_data_streams_creation_date.ts b/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/get_data_streams_creation_date.ts new file mode 100644 index 0000000000000..c86b7ffad02fb --- /dev/null +++ b/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/get_data_streams_creation_date.ts @@ -0,0 +1,45 @@ +/* + * 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 { ElasticsearchClient } from '@kbn/core/server'; +import { dataStreamService } from '../../services'; + +export async function getDataStreamsCreationDate({ + esClient, + dataStreams, +}: { + esClient: ElasticsearchClient; + dataStreams: string[]; +}) { + const matchingStreams = await dataStreamService.getMatchingDataStreams(esClient, dataStreams); + const streamByIndex = matchingStreams.reduce((acc, { name, indices }) => { + if (indices[0]) acc[indices[0].index_name] = name; + return acc; + }, {} as Record); + + const indices = Object.keys(streamByIndex); + if (indices.length === 0) { + return {}; + } + // While _cat api is not recommended for application use this is the only way + // to retrieve the creation date in serverless for now. We should change this + // once a proper approach exists (see elastic/elasticsearch-serverless#3010) + const catIndices = await esClient.cat.indices({ + index: indices, + h: ['creation.date', 'index'], + format: 'json', + }); + + return catIndices.reduce((acc, index) => { + const creationDate = index['creation.date']; + const indexName = index.index!; + const stream = streamByIndex[indexName]; + + acc[stream] = creationDate ? Number(creationDate) : undefined; + return acc; + }, {} as Record); +} diff --git a/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/routes.ts b/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/routes.ts index a12048d9235d8..a986321125980 100644 --- a/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/routes.ts +++ b/x-pack/platform/plugins/shared/dataset_quality/server/routes/data_streams/routes.ts @@ -6,6 +6,7 @@ */ import * as t from 'io-ts'; +import { toBooleanRt } from '@kbn/io-ts-utils'; import { CheckAndLoadIntegrationResponse, DataStreamDetails, @@ -38,15 +39,14 @@ import { getDegradedFieldValues } from './get_degraded_field_values'; import { getDegradedFields } from './get_degraded_fields'; import { getNonAggregatableDataStreams } from './get_non_aggregatable_data_streams'; import { updateFieldLimit } from './update_field_limit'; +import { getDataStreamsCreationDate } from './get_data_streams_creation_date'; const statsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/stats', params: t.type({ query: t.intersection([ - t.type({ types: typesRt }), - t.partial({ - datasetQuery: t.string, - }), + t.union([t.type({ types: typesRt }), t.type({ datasetQuery: t.string })]), + t.partial({ includeCreationDate: toBooleanRt }), ]), }), options: { @@ -81,15 +81,25 @@ const statsRoute = createDatasetQualityServerRoute({ return dataStream.userPrivileges.canMonitor; }); - const dataStreamsStats = isServerless - ? await getDataStreamsMeteringStats({ - esClient: esClientAsSecondaryAuthUser, - dataStreams: privilegedDataStreams.map((stream) => stream.name), - }) - : await getDataStreamsStats({ - esClient, - dataStreams: privilegedDataStreams.map((stream) => stream.name), - }); + const dataStreamsNames = privilegedDataStreams.map((stream) => stream.name); + const [dataStreamsStats, dataStreamsCreationDate] = await Promise.all([ + isServerless + ? getDataStreamsMeteringStats({ + esClient: esClientAsSecondaryAuthUser, + dataStreams: dataStreamsNames, + }) + : getDataStreamsStats({ + esClient, + dataStreams: dataStreamsNames, + }), + + params.query.includeCreationDate + ? getDataStreamsCreationDate({ + esClient: esClientAsSecondaryAuthUser, + dataStreams: dataStreamsNames, + }) + : ({} as Record), + ]); return { datasetUserPrivileges, @@ -97,6 +107,7 @@ const statsRoute = createDatasetQualityServerRoute({ dataStream.size = dataStreamsStats[dataStream.name]?.size; dataStream.sizeBytes = dataStreamsStats[dataStream.name]?.sizeBytes; dataStream.totalDocs = dataStreamsStats[dataStream.name]?.totalDocs; + dataStream.creationDate = dataStreamsCreationDate[dataStream.name]; return dataStream; }), diff --git a/x-pack/platform/plugins/shared/dataset_quality/server/services/data_stream.ts b/x-pack/platform/plugins/shared/dataset_quality/server/services/data_stream.ts index e54f0f33f375a..857768853b4cd 100644 --- a/x-pack/platform/plugins/shared/dataset_quality/server/services/data_stream.ts +++ b/x-pack/platform/plugins/shared/dataset_quality/server/services/data_stream.ts @@ -15,7 +15,7 @@ import { reduceAsyncChunks } from '../utils/reduce_async_chunks'; class DataStreamService { public async getMatchingDataStreams( esClient: ElasticsearchClient, - datasetName: string + datasetName: string | string[] ): Promise { try { const { data_streams: dataStreamsInfo } = await esClient.indices.getDataStream({ diff --git a/x-pack/solutions/observability/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx b/x-pack/solutions/observability/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx index d86c0723e038a..5e57ea3250907 100644 --- a/x-pack/solutions/observability/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx @@ -15,6 +15,7 @@ import type { SharePublicStart } from '@kbn/share-plugin/public/plugin'; import { NavigationPublicStart } from '@kbn/navigation-plugin/public/types'; import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public'; import { fieldsMetadataPluginPublicMock } from '@kbn/fields-metadata-plugin/public/mocks'; +import { DataStreamsStatsClient } from '@kbn/dataset-quality-plugin/public/services/data_streams_stats/data_streams_stats_client'; import type { StreamsAppKibanaContext } from '../public/hooks/use_kibana'; export function getMockStreamsAppContext(): StreamsAppKibanaContext { @@ -38,7 +39,7 @@ export function getMockStreamsAppContext(): StreamsAppKibanaContext { }, }, services: { - query: jest.fn(), + dataStreamsClient: Promise.resolve({} as unknown as DataStreamsStatsClient), }, isServerless: false, }; diff --git a/x-pack/solutions/observability/plugins/streams_app/kibana.jsonc b/x-pack/solutions/observability/plugins/streams_app/kibana.jsonc index 8967a468aa81a..716376423337c 100644 --- a/x-pack/solutions/observability/plugins/streams_app/kibana.jsonc +++ b/x-pack/solutions/observability/plugins/streams_app/kibana.jsonc @@ -19,6 +19,7 @@ "savedObjectsTagging", "navigation", "fieldsMetadata", + "datasetQuality" ], "requiredBundles": [ "kibanaReact" diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/format_bytes.ts b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/format_bytes.ts new file mode 100644 index 0000000000000..4cc666058b677 --- /dev/null +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/format_bytes.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { formatNumber } from '@elastic/eui'; + +export const formatBytes = (value: number) => formatNumber(value, '0.0 b'); diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/ingestion_rate_query.ts b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/ingestion_rate_query.ts new file mode 100644 index 0000000000000..3e752562be7f7 --- /dev/null +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/helpers/ingestion_rate_query.ts @@ -0,0 +1,55 @@ +/* + * 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 datemath from '@kbn/datemath'; + +export const ingestionRateQuery = ({ + index, + start, + end, + timestampField = '@timestamp', + bucketCount = 10, +}: { + index: string; + start: string; + end: string; + timestampField?: string; + bucketCount?: number; +}) => { + const startDate = datemath.parse(start); + const endDate = datemath.parse(end); + if (!startDate || !endDate) { + throw new Error(`Expected a valid start and end date but got [start: ${start} | end: ${end}]`); + } + + const intervalInSeconds = Math.max( + Math.round(endDate.diff(startDate, 'seconds') / bucketCount), + 1 + ); + + return { + index, + track_total_hits: false, + body: { + size: 0, + query: { + bool: { + filter: [{ range: { [timestampField]: { gte: start, lte: end } } }], + }, + }, + aggs: { + docs_count: { + date_histogram: { + field: timestampField, + fixed_interval: `${intervalInSeconds}s`, + min_doc_count: 0, + }, + }, + }, + }, + }; +}; diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/hooks/use_data_stream_stats.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/hooks/use_data_stream_stats.tsx new file mode 100644 index 0000000000000..9125aba411d93 --- /dev/null +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/hooks/use_data_stream_stats.tsx @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; +import { IngestStreamGetResponse } from '@kbn/streams-schema'; +import { DataStreamStatServiceResponse } from '@kbn/dataset-quality-plugin/public'; +import { useKibana } from '../../../hooks/use_kibana'; +import { useStreamsAppFetch } from '../../../hooks/use_streams_app_fetch'; + +export type DataStreamStats = DataStreamStatServiceResponse['dataStreamsStats'][number] & { + bytesPerDoc: number; + bytesPerDay: number; +}; + +export const useDataStreamStats = ({ definition }: { definition?: IngestStreamGetResponse }) => { + const { + services: { dataStreamsClient }, + } = useKibana(); + + const statsFetch = useStreamsAppFetch(async () => { + if (!definition) { + return; + } + + const client = await dataStreamsClient; + const { + dataStreamsStats: [dsStats], + } = await client.getDataStreamsStats({ + datasetQuery: definition.stream.name, + includeCreationDate: true, + }); + + if (!dsStats || !dsStats.creationDate || !dsStats.sizeBytes) { + return undefined; + } + const daysSinceCreation = Math.max( + 1, + Math.round(moment().diff(moment(dsStats.creationDate), 'days')) + ); + + return { + ...dsStats, + bytesPerDay: dsStats.sizeBytes / daysSinceCreation, + bytesPerDoc: dsStats.totalDocs ? dsStats.sizeBytes / dsStats.totalDocs : 0, + }; + }, [dataStreamsClient, definition]); + + return { + stats: statsFetch.value, + isLoading: statsFetch.loading, + refresh: statsFetch.refresh, + error: statsFetch.error, + }; +}; diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/index.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/index.tsx index fd6801e456ab6..372f130c24253 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/index.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiSpacer } from '@elastic/eui'; import React, { useMemo, useState } from 'react'; import { IngestStreamGetResponse, @@ -27,6 +27,8 @@ import { useKibana } from '../../hooks/use_kibana'; import { EditLifecycleModal, LifecycleEditAction } from './modal'; import { RetentionSummary } from './summary'; import { RetentionMetadata } from './metadata'; +import { IngestionRate } from './ingestion_rate'; +import { useDataStreamStats } from './hooks/use_data_stream_stats'; import { getFormattedError } from '../../util/errors'; function useLifecycleState({ @@ -112,6 +114,13 @@ export function StreamDetailLifecycle({ setUpdateInProgress, } = useLifecycleState({ definition, isServerless }); + const { + stats, + isLoading: isLoadingStats, + refresh: refreshStats, + error: statsError, + } = useDataStreamStats({ definition }); + const { signal } = useAbortController(); if (!definition) { @@ -176,24 +185,38 @@ export function StreamDetailLifecycle({ ilmLocator={ilmLocator} /> - + + + + + + + + setOpenEditModal(action)} + isLoadingStats={isLoadingStats} + stats={stats} + statsError={statsError} + /> + + + + + + + - - - - - - - setOpenEditModal(action)} - /> - - + - + ); } diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/ingestion_rate.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/ingestion_rate.tsx new file mode 100644 index 0000000000000..3ffda07c2be46 --- /dev/null +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/ingestion_rate.tsx @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import moment from 'moment'; +import React from 'react'; +import { lastValueFrom } from 'rxjs'; +import { IKibanaSearchRequest, IKibanaSearchResponse } from '@kbn/search-types'; +import { i18n } from '@kbn/i18n'; +import { IngestStreamGetResponse } from '@kbn/streams-schema'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiLoadingChart, + EuiPanel, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { AreaSeries, Axis, Chart, Settings } from '@elastic/charts'; +import { useDateRange } from '@kbn/observability-utils-browser/hooks/use_date_range'; +import { useKibana } from '../../hooks/use_kibana'; +import { DataStreamStats } from './hooks/use_data_stream_stats'; +import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch'; +import { ingestionRateQuery } from './helpers/ingestion_rate_query'; +import { formatBytes } from './helpers/format_bytes'; +import { StreamsAppSearchBar } from '../streams_app_search_bar'; + +export function IngestionRate({ + definition, + stats, + isLoadingStats, + refreshStats, +}: { + definition?: IngestStreamGetResponse; + stats?: DataStreamStats; + isLoadingStats: boolean; + refreshStats: () => void; +}) { + const { + dependencies: { + start: { data }, + }, + } = useKibana(); + const { timeRange, setTimeRange } = useDateRange({ data }); + + const { + loading: isLoadingIngestionRate, + value: ingestionRate, + error: ingestionRateError, + } = useStreamsAppFetch( + async ({ signal }) => { + if (!definition || isLoadingStats || !stats?.bytesPerDay) { + return; + } + + const { rawResponse } = await lastValueFrom( + data.search.search< + IKibanaSearchRequest, + IKibanaSearchResponse<{ + aggregations: { docs_count: { buckets: Array<{ key: string; doc_count: number }> } }; + }> + >( + { + params: ingestionRateQuery({ + start: timeRange.from, + end: timeRange.to, + index: definition.stream.name, + }), + }, + { abortSignal: signal } + ) + ); + + return rawResponse.aggregations.docs_count.buckets.map(({ key, doc_count: docCount }) => ({ + key, + value: docCount * stats.bytesPerDoc, + })); + }, + [data.search, definition, stats, isLoadingStats, timeRange] + ); + + return ( + <> + + + + +
+ {i18n.translate('xpack.streams.streamDetailLifecycle.ingestionRatePanel', { + defaultMessage: 'Ingestion rate', + })} +
+
+
+ + + { + if (!isUpdate) { + refreshStats(); + return; + } + + if (dateRange) { + setTimeRange({ + from: dateRange.from, + to: dateRange?.to, + mode: dateRange.mode, + }); + } + }} + /> + +
+
+ + + + {ingestionRateError ? ( + + Failed to load ingestion rate + + ) : isLoadingIngestionRate || isLoadingStats || !ingestionRate ? ( + + + + ) : ( + + + + + moment(value).format('YYYY-MM-DD')} + gridLine={{ visible: false }} + /> + formatBytes(value)} + gridLine={{ visible: true }} + /> + + )} + + ); +} diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/metadata.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/metadata.tsx index 3de494f070d5e..67e6b2f4acc7c 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/metadata.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/metadata.tsx @@ -26,6 +26,7 @@ import { EuiFlexItem, EuiHorizontalRule, EuiLink, + EuiLoadingSpinner, EuiPanel, EuiPopover, EuiText, @@ -33,21 +34,28 @@ import { import { i18n } from '@kbn/i18n'; import { LifecycleEditAction } from './modal'; import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; +import { DataStreamStats } from './hooks/use_data_stream_stats'; +import { formatBytes } from './helpers/format_bytes'; export function RetentionMetadata({ definition, ilmLocator, lifecycleActions, openEditModal, + stats, + isLoadingStats, + statsError, }: { definition: IngestStreamGetResponse; ilmLocator?: LocatorPublic; lifecycleActions: Array<{ name: string; action: LifecycleEditAction }>; openEditModal: (action: LifecycleEditAction) => void; + stats?: DataStreamStats; + isLoadingStats: boolean; + statsError?: Error; }) { const [isMenuOpen, { toggle: toggleMenu, off: closeMenu }] = useBoolean(false); const router = useStreamsAppRouter(); - const lifecycle = definition.effective_lifecycle; const contextualMenu = @@ -171,6 +179,38 @@ export function RetentionMetadata({ } /> + + + ) : stats.bytesPerDay ? ( + formatIngestionRate(stats.bytesPerDay) + ) : ( + '-' + ) + } + /> + + + ) : ( + stats.totalDocs + ) + } + /> ); } @@ -197,3 +237,9 @@ function MetadataRow({ ); } + +const formatIngestionRate = (bytesPerDay: number) => { + const perDay = formatBytes(bytesPerDay); + const perMonth = formatBytes(bytesPerDay * 30); + return `${perDay} / Day - ${perMonth} / Month`; +}; diff --git a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/summary.tsx b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/summary.tsx index 7b3c37649dacb..c867e317d239c 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/summary.tsx +++ b/x-pack/solutions/observability/plugins/streams_app/public/components/stream_detail_lifecycle/summary.tsx @@ -21,7 +21,7 @@ export function RetentionSummary({ definition }: { definition: IngestStreamGetRe const summary = useMemo(() => summaryText(definition), [definition]); return ( - +
{i18n.translate('xpack.streams.streamDetailLifecycle.retentionSummaryLabel', { diff --git a/x-pack/solutions/observability/plugins/streams_app/public/plugin.ts b/x-pack/solutions/observability/plugins/streams_app/public/plugin.ts index c6aec1005cc09..dbe50f39b6308 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/streams_app/public/plugin.ts @@ -18,6 +18,7 @@ import { } from '@kbn/core/public'; import type { Logger } from '@kbn/logging'; import { STREAMS_APP_ID } from '@kbn/deeplinks-observability/constants'; +import { DataStreamsStatsService } from '@kbn/dataset-quality-plugin/public'; import type { ConfigSchema, StreamsAppPublicSetup, @@ -119,7 +120,11 @@ export class StreamsAppPlugin coreSetup.getStartServices(), ]); - const services: StreamsAppServices = {}; + const services: StreamsAppServices = { + dataStreamsClient: new DataStreamsStatsService() + .start({ http: coreStart.http }) + .getClient(), + }; return renderApp({ coreStart, diff --git a/x-pack/solutions/observability/plugins/streams_app/public/services/types.ts b/x-pack/solutions/observability/plugins/streams_app/public/services/types.ts index 7f75493d2525c..69f51c04df1e6 100644 --- a/x-pack/solutions/observability/plugins/streams_app/public/services/types.ts +++ b/x-pack/solutions/observability/plugins/streams_app/public/services/types.ts @@ -5,5 +5,8 @@ * 2.0. */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface StreamsAppServices {} +import { IDataStreamsStatsClient } from '@kbn/dataset-quality-plugin/public'; + +export interface StreamsAppServices { + dataStreamsClient: Promise; +} diff --git a/x-pack/solutions/observability/plugins/streams_app/tsconfig.json b/x-pack/solutions/observability/plugins/streams_app/tsconfig.json index f43409d674c59..3f33c3ddc109c 100644 --- a/x-pack/solutions/observability/plugins/streams_app/tsconfig.json +++ b/x-pack/solutions/observability/plugins/streams_app/tsconfig.json @@ -57,5 +57,8 @@ "@kbn/actions-plugin", "@kbn/object-utils", "@kbn/traced-es-client", + "@kbn/datemath", + "@kbn/dataset-quality-plugin", + "@kbn/search-types" ] } diff --git a/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts b/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts index c7d44c26b230b..c4f183e0dc8e5 100644 --- a/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts +++ b/x-pack/test/dataset_quality_api_integration/tests/data_streams/stats.spec.ts @@ -21,13 +21,15 @@ export default function ApiTest({ getService }: FtrProviderContext) { async function callApiAs( user: DatasetQualityApiClientKey, - types: Array<'logs' | 'metrics' | 'traces' | 'synthetics'> = ['logs'] + types: Array<'logs' | 'metrics' | 'traces' | 'synthetics'> = ['logs'], + includeCreationDate = false ) { return await datasetQualityApiClient[user]({ endpoint: 'GET /internal/dataset_quality/data_streams/stats', params: { query: { types: rison.encodeArray(types), + includeCreationDate, }, }, }); @@ -152,6 +154,18 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(stats.body.dataStreamsStats[0].totalDocs).greaterThan(0); }); + it('does not return creation date by default', async () => { + const stats = await callApiAs('datasetQualityMonitorUser'); + expect(stats.body.dataStreamsStats[0].size).not.empty(); + expect(stats.body.dataStreamsStats[0].creationDate).to.be(undefined); + }); + + it('returns creation date when specified', async () => { + const stats = await callApiAs('datasetQualityMonitorUser', ['logs'], true); + expect(stats.body.dataStreamsStats[0].size).not.empty(); + expect(stats.body.dataStreamsStats[0].creationDate).greaterThan(0); + }); + after(async () => { await logsSynthtrace.clean(); await cleanLogIndexTemplate({ esClient: es }); From 83aa968c52e3f6f2ed41a485af202be600f87834 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 02:39:57 +1100 Subject: [PATCH 08/23] [8.x] [Streams] Small type changes for advanced mapping parameters (#211817) (#211906) # Backport This will backport the following commits from `main` to `8.x`: - [[Streams] Small type changes for advanced mapping parameters (#211817)](https://github.com/elastic/kibana/pull/211817) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Kerry Gallagher --- .../kbn-streams-schema/src/models/core.ts | 28 --------------- .../kbn-streams-schema/src/models/index.ts | 1 + .../src/models/ingest/fields/index.ts | 3 +- .../src/models/record_types.ts | 36 +++++++++++++++++++ 4 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 x-pack/platform/packages/shared/kbn-streams-schema/src/models/record_types.ts diff --git a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/core.ts b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/core.ts index 1da12cde4c9af..b77ed58d4c4d1 100644 --- a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/core.ts +++ b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/core.ts @@ -18,31 +18,3 @@ export const streamDefinitionSchema: z.Schema = z.union([ ]); export const isStreamDefinition = createIsNarrowSchema(z.unknown(), streamDefinitionSchema); - -export type Primitive = string | number | boolean | null | undefined; - -export const primitive: z.ZodType = z.union([ - z.string(), - z.number(), - z.boolean(), - z.null(), - z.undefined(), -]); - -export interface RecursiveRecord { - [key: PropertyKey]: Primitive | Primitive[] | RecursiveRecord; -} - -export const recursiveRecord: z.ZodType = z.lazy(() => - z.record(z.union([primitive, z.array(primitive), recursiveRecord])) -); - -export type FlattenRecord = Record; - -export const flattenRecord: z.ZodType = z.record( - z.union([primitive, z.array(primitive)]) -); - -export const sampleDocument = recursiveRecord; - -export type SampleDocument = RecursiveRecord; diff --git a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/index.ts b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/index.ts index be9dafc266b3a..06f5be3ffc383 100644 --- a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/index.ts +++ b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/index.ts @@ -11,3 +11,4 @@ export * from './api'; export * from './core'; export * from './helpers'; export * from './group'; +export * from './record_types'; diff --git a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/ingest/fields/index.ts b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/ingest/fields/index.ts index 7f9f7121d52f5..482e956f8ef95 100644 --- a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/ingest/fields/index.ts +++ b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/ingest/fields/index.ts @@ -8,6 +8,7 @@ import { MappingProperty } from '@elastic/elasticsearch/lib/api/types'; import { z } from '@kbn/zod'; import { NonEmptyString } from '@kbn/zod-helpers'; +import { recursiveRecord } from '../../record_types'; export const FIELD_DEFINITION_TYPES = [ 'keyword', @@ -34,7 +35,7 @@ export type FieldDefinitionConfigAdvancedParameters = Omit< >; export const fieldDefinitionConfigSchema: z.Schema = z.intersection( - z.record(z.string(), z.unknown()), + recursiveRecord, z.object({ type: z.enum(FIELD_DEFINITION_TYPES), format: z.optional(NonEmptyString), diff --git a/x-pack/platform/packages/shared/kbn-streams-schema/src/models/record_types.ts b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/record_types.ts new file mode 100644 index 0000000000000..58a409b370c4b --- /dev/null +++ b/x-pack/platform/packages/shared/kbn-streams-schema/src/models/record_types.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from '@kbn/zod'; + +export type Primitive = string | number | boolean | null | undefined; + +export const primitive: z.ZodType = z.union([ + z.string(), + z.number(), + z.boolean(), + z.null(), + z.undefined(), +]); + +export interface RecursiveRecord { + [key: PropertyKey]: Primitive | Primitive[] | RecursiveRecord; +} + +export const recursiveRecord: z.ZodType = z.lazy(() => + z.record(z.union([primitive, z.array(primitive), recursiveRecord])) +); + +export type FlattenRecord = Record; + +export const flattenRecord: z.ZodType = z.record( + z.union([primitive, z.array(primitive)]) +); + +export const sampleDocument = recursiveRecord; + +export type SampleDocument = RecursiveRecord; From 270873e18e558ec924539a37e2892cd523965d78 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 20 Feb 2025 13:00:25 -0500 Subject: [PATCH 09/23] [8.x] [Fleet] Fix wrong condition in status runtime (#211779) (#211830) --- .../services/agents/build_status_runtime_field.test.ts | 6 +++--- .../server/services/agents/build_status_runtime_field.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts index c1b5b92ea9239..e52a36c061d29 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.test.ts @@ -56,7 +56,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && (['policy-1'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L)) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, @@ -76,7 +76,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && (['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L)) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, @@ -124,7 +124,7 @@ describe('buildStatusRuntimeField', () => { "status": Object { "script": Object { "lang": "painless", - "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && ['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L || ['policy-3'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567490123L) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", + "source": " long lastCheckinMillis = doc['last_checkin'].size() > 0 ? doc['last_checkin'].value.toInstant().toEpochMilli() : ( doc['enrolled_at'].size() > 0 ? doc['enrolled_at'].value.toInstant().toEpochMilli() : -1 ); if (doc['active'].size() > 0 && doc['active'].value == false) { emit('unenrolled'); } else if (lastCheckinMillis > 0 && doc.containsKey('policy_id') && doc['policy_id'].size() > 0 && (['policy-1','policy-2'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567590123L || ['policy-3'].contains(doc['policy_id'].value) && lastCheckinMillis < 1234567490123L)) {emit('inactive');} else if ( lastCheckinMillis > 0 && lastCheckinMillis < 1234567590123L ) { emit('offline'); } else if ( doc['policy_revision_idx'].size() == 0 || ( doc['upgrade_started_at'].size() > 0 && doc['upgraded_at'].size() == 0 ) ) { emit('updating'); } else if (doc['last_checkin'].size() == 0) { emit('enrolling'); } else if (doc['unenrollment_started_at'].size() > 0) { emit('unenrolling'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'error' ) { emit('error'); } else if ( doc['last_checkin_status'].size() > 0 && doc['last_checkin_status'].value.toLowerCase() == 'degraded' ) { emit('degraded'); } else { emit('online'); }", }, "type": "keyword", }, diff --git a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts index 6de1ae1359879..f95cff9514700 100644 --- a/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts +++ b/x-pack/platform/plugins/shared/fleet/server/services/agents/build_status_runtime_field.ts @@ -80,7 +80,7 @@ const _buildInactiveCondition = (opts: { return `lastCheckinMillis > 0 && doc.containsKey(${fieldPath('policy_id')}) && ${field( 'policy_id' - )}.size() > 0 && ${policyClauses}`; + )}.size() > 0 && (${policyClauses})`; }; function _buildSource( From 879f72b9d76feac3bd8f7436977a273f42b5a716 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 05:40:25 +1100 Subject: [PATCH 10/23] [8.x] [Synthetics] modify use overview status hook to mimic use_monitor_list (#210936) (#211931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [[Synthetics] modify use overview status hook to mimic use_monitor_list (#210936)](https://github.com/elastic/kibana/pull/210936) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Bailey Cash --- .../hooks/use_overview_status.ts | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts b/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts index da86b130af692..b6999fcc3a0b3 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts @@ -5,8 +5,9 @@ * 2.0. */ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import useDebounce from 'react-use/lib/useDebounce'; import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context'; import { selectOverviewPageState } from '../../../state'; import { @@ -17,22 +18,51 @@ import { export function useOverviewStatus({ scopeStatusByLocation }: { scopeStatusByLocation: boolean }) { const pageState = useSelector(selectOverviewPageState); - const { status, error, loaded, loading, allConfigs } = useSelector(selectOverviewStatus); + const isInitialMount = useRef(true); const { lastRefresh } = useSyntheticsRefreshContext(); const dispatch = useDispatch(); + // Periodically refresh useEffect(() => { - if (loaded) { + if (!isInitialMount.current) { dispatch(quietFetchOverviewStatusAction.get({ pageState, scopeStatusByLocation })); - } else { - dispatch(fetchOverviewStatusAction.get({ pageState, scopeStatusByLocation })); } - // loaded is omitted from the dependency array because it is not used in the callback + // specifically only want to run this on refreshInterval change // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dispatch, lastRefresh, pageState, scopeStatusByLocation]); + }, [lastRefresh]); + + // On initial mount, load the page + useDebounce( + () => { + if (isInitialMount.current) { + if (loaded) { + dispatch(quietFetchOverviewStatusAction.get({ pageState, scopeStatusByLocation })); + } else { + dispatch(fetchOverviewStatusAction.get({ pageState, scopeStatusByLocation })); + } + } + }, + 100, + // we don't use pageState or scopeStatus here, for pageState, useDebounce will handle it + [dispatch] + ); + + useDebounce( + () => { + // Don't load on initial mount, only meant to handle pageState changes + if (isInitialMount.current || !loaded) { + // setting false here to account for debounce timing + isInitialMount.current = false; + return; + } + dispatch(fetchOverviewStatusAction.get({ pageState, scopeStatusByLocation })); + }, + 100, + [pageState, scopeStatusByLocation] + ); return { status, From ae86aa61da66c3fa5dbabf08cbebda15087dc6cb Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 05:59:17 +1100 Subject: [PATCH 11/23] =?UTF-8?q?[8.x]=20[Streams=20=F0=9F=8C=8A]=20Ensure?= =?UTF-8?q?=20the=20members=20array=20is=20unique=20for=20GroupStreamDefin?= =?UTF-8?q?itions=20(#210089)=20(#211798)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [[Streams 🌊] Ensure the members array is unique for GroupStreamDefinitions (#210089)](https://github.com/elastic/kibana/pull/210089) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Chris Cowan --- .../streams/server/routes/streams/crud/route.ts | 15 ++++++++++++++- .../apis/observability/streams/group_streams.ts | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/x-pack/solutions/observability/plugins/streams/server/routes/streams/crud/route.ts b/x-pack/solutions/observability/plugins/streams/server/routes/streams/crud/route.ts index 2c9faae8d6606..7a643fe1ef51e 100644 --- a/x-pack/solutions/observability/plugins/streams/server/routes/streams/crud/route.ts +++ b/x-pack/solutions/observability/plugins/streams/server/routes/streams/crud/route.ts @@ -12,6 +12,7 @@ import { StreamGetResponse, isWiredStreamDefinition, streamUpsertRequestSchema, + isGroupStreamDefinitionBase, } from '@kbn/streams-schema'; import { z } from '@kbn/zod'; import { badData, badRequest } from '@hapi/boom'; @@ -163,8 +164,20 @@ export const editStreamRoute = createServerRoute({ throw badRequest('Cannot create wired stream due to unsupported root stream'); } + const body = isGroupStreamDefinitionBase(params.body.stream) + ? { + ...params.body, + stream: { + group: { + ...params.body.stream.group, + members: Array.from(new Set(params.body.stream.group.members)), + }, + }, + } + : params.body; + return await streamsClient.upsertStream({ - request: params.body, + request: body, name: params.path.name, }); }, diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/group_streams.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/group_streams.ts index 0c6897a62726d..6527b69170511 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/group_streams.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/streams/group_streams.ts @@ -40,7 +40,7 @@ export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { body: { stream: { group: { - members: ['logs', 'logs.test2'], + members: ['logs', 'logs.test2', 'logs'], }, }, dashboards: [], From 9bf41f2541e034932923ae7461ef86c8ef9d86d6 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 06:02:08 +1100 Subject: [PATCH 12/23] [8.x] [Security Solution] Fix flyout history flickering (#211662) (#211936) # Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution] Fix flyout history flickering (#211662)](https://github.com/elastic/kibana/pull/211662) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: christineweng <18648970+christineweng@users.noreply.github.com> --- .../components/flyout_history_row.test.tsx | 30 +++++++++++++++++++ .../shared/components/flyout_history_row.tsx | 22 ++++++++++++-- .../flyout/shared/components/test_ids.ts | 1 + 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.test.tsx index 471cbae65427b..5ba5301e56d38 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.test.tsx @@ -22,6 +22,7 @@ import { } from '@kbn/expandable-flyout'; import { useRuleDetails } from '../../rule_details/hooks/use_rule_details'; import { useBasicDataFromDetailsData } from '../../document_details/shared/hooks/use_basic_data_from_details_data'; +import { useEventDetails } from '../../document_details/shared/hooks/use_event_details'; import { DocumentDetailsRightPanelKey } from '../../document_details/shared/constants/panel_keys'; import { RulePanelKey } from '../../rule_details/right'; import { NetworkPanelKey } from '../../network_details'; @@ -32,6 +33,7 @@ import { NETWORK_HISTORY_ROW_TEST_ID, RULE_HISTORY_ROW_TEST_ID, USER_HISTORY_ROW_TEST_ID, + HISTORY_ROW_LOADING_TEST_ID, } from './test_ids'; import { HostPanelKey, UserPanelKey } from '../../entity_details/shared/constants'; @@ -45,6 +47,7 @@ jest.mock('@kbn/expandable-flyout', () => ({ jest.mock('../../../detection_engine/rule_management/logic/use_rule_with_fallback'); jest.mock('../../document_details/shared/hooks/use_basic_data_from_details_data'); jest.mock('../../rule_details/hooks/use_rule_details'); +jest.mock('../../document_details/shared/hooks/use_event_details'); const flyoutContextValue = { openFlyout: jest.fn(), @@ -112,6 +115,12 @@ describe('FlyoutHistoryRow', () => { jest.mocked(useRuleDetails).mockReturnValue({ ...mockedRuleResponse, rule: { name: 'rule name' } as RuleResponse, + loading: false, + }); + (useEventDetails as jest.Mock).mockReturnValue({ + dataFormattedForFieldBrowser: {}, + getFieldsData: jest.fn(), + loading: false, }); (useBasicDataFromDetailsData as jest.Mock).mockReturnValue({ isAlert: false }); }); @@ -182,6 +191,11 @@ describe('FlyoutHistoryRow', () => { describe('DocumentDetailsHistoryRow', () => { beforeEach(() => { jest.mocked(useExpandableFlyoutApi).mockReturnValue(flyoutContextValue); + (useEventDetails as jest.Mock).mockReturnValue({ + dataFormattedForFieldBrowser: {}, + getFieldsData: jest.fn(), + loading: false, + }); }); it('should render alert title when isAlert is true and rule name is defined', () => { @@ -291,6 +305,22 @@ describe('GenericHistoryRow', () => { fireEvent.click(getByTestId(`${0}-${GENERIC_HISTORY_ROW_TEST_ID}`)); }); + it('should render empty context menu item when isLoading is true', () => { + const { getByTestId } = render( + + + + ); + expect(getByTestId(HISTORY_ROW_LOADING_TEST_ID)).toBeInTheDocument(); + }); + it('should open the flyout when clicked', () => { const { getByTestId } = render( diff --git a/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.tsx b/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.tsx index ed36c14326555..92ac1b6821781 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/flyout/shared/components/flyout_history_row.tsx @@ -14,6 +14,7 @@ import { EuiFlexItem, type EuiIconProps, useEuiTheme, + EuiSkeletonText, } from '@elastic/eui'; import type { FlyoutPanelHistory } from '@kbn/expandable-flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; @@ -32,6 +33,7 @@ import { NETWORK_HISTORY_ROW_TEST_ID, RULE_HISTORY_ROW_TEST_ID, USER_HISTORY_ROW_TEST_ID, + HISTORY_ROW_LOADING_TEST_ID, } from './test_ids'; import { HostPanelKey, UserPanelKey } from '../../entity_details/shared/constants'; @@ -99,7 +101,7 @@ export const FlyoutHistoryRow: FC = memo(({ item, index } * Row item for a document details */ export const DocumentDetailsHistoryRow: FC = memo(({ item, index }) => { - const { dataFormattedForFieldBrowser, getFieldsData } = useEventDetails({ + const { dataFormattedForFieldBrowser, getFieldsData, loading } = useEventDetails({ eventId: String(item?.panel?.params?.id), indexName: String(item?.panel?.params?.indexName), }); @@ -122,6 +124,7 @@ export const DocumentDetailsHistoryRow: FC = memo(({ item title={title} icon={isAlert ? 'warning' : 'analyzeEvent'} name={isAlert ? 'Alert' : 'Event'} + isLoading={loading} dataTestSubj={DOCUMENT_DETAILS_HISTORY_ROW_TEST_ID} /> ); @@ -171,7 +174,7 @@ const RowTitle: FC = memo(({ type, value }) => { */ export const RuleHistoryRow: FC = memo(({ item, index }) => { const ruleId = String(item?.panel?.params?.ruleId); - const { rule } = useRuleDetails({ ruleId }); + const { rule, loading } = useRuleDetails({ ruleId }); return ( = memo(({ item, index }) title={rule?.name ?? ''} icon={'indexSettings'} name={'Rule'} + isLoading={loading} dataTestSubj={RULE_HISTORY_ROW_TEST_ID} /> ); @@ -202,6 +206,10 @@ interface GenericHistoryRowProps extends FlyoutHistoryRowProps { * Name to display */ name: string; + /** + * Whether the row is loading + */ + isLoading?: boolean; /** * Data test subject */ @@ -212,13 +220,21 @@ interface GenericHistoryRowProps extends FlyoutHistoryRowProps { * Row item for a generic history row where the title is accessible in flyout params */ export const GenericHistoryRow: FC = memo( - ({ item, index, title, icon, name, dataTestSubj }) => { + ({ item, index, title, icon, name, isLoading, dataTestSubj }) => { const { euiTheme } = useEuiTheme(); const { openFlyout } = useExpandableFlyoutApi(); const onClick = useCallback(() => { openFlyout({ right: item.panel }); }, [openFlyout, item.panel]); + if (isLoading) { + return ( + + + + ); + } + return ( `${dataTestSubj /* History */ export const FLYOUT_HISTORY_TEST_ID = `${PREFIX}History` as const; +export const HISTORY_ROW_LOADING_TEST_ID = `${FLYOUT_HISTORY_TEST_ID}RowLoading` as const; export const FLYOUT_HISTORY_BUTTON_TEST_ID = `${FLYOUT_HISTORY_TEST_ID}Button` as const; export const FLYOUT_HISTORY_CONTEXT_PANEL_TEST_ID = `${FLYOUT_HISTORY_TEST_ID}ContextPanel` as const; From 9b062e2ce7d5fb3e96f1b0095b00cb43c4b79f3b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 06:32:02 +1100 Subject: [PATCH 13/23] [8.x] [ResponseOps][Security][Rules] Fix fields missing from Cases action in Security Solution rule form (#210547) (#211943) # Backport This will backport the following commits from `main` to `8.x`: - [[ResponseOps][Security][Rules] Fix fields missing from Cases action in Security Solution rule form (#210547)](https://github.com/elastic/kibana/pull/210547) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Umberto Pepato --- .../components/rule_actions_field/index.tsx | 10 +++++--- .../components/step_rule_actions/index.tsx | 5 +++- .../pages/rule_creation/index.tsx | 3 +++ .../pages/rule_editing/index.tsx | 3 +++ .../rule_actions/rule_actions.cy.ts | 23 +++++++++++++++++++ .../cypress/screens/common/rule_actions.ts | 6 +++++ .../cypress/tasks/create_new_rule.ts | 5 ++++ 7 files changed, 51 insertions(+), 4 deletions(-) diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/rule_actions_field/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/rule_actions_field/index.tsx index ff85f82c54f67..a142f06aa3c7b 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/rule_actions_field/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/rule_actions_field/index.tsx @@ -78,6 +78,7 @@ const NOTIFY_WHEN_OPTIONS: NotifyWhenSelectOptions[] = [ ]; interface Props { + ruleTypeId?: string; field: FieldHook; messageVariables: ActionVariables; summaryMessageVariables: ActionVariables; @@ -113,6 +114,7 @@ const ContainerActions = styled.div.attrs( `; export const RuleActionsField: React.FC = ({ + ruleTypeId, field, messageVariables, summaryMessageVariables, @@ -246,6 +248,7 @@ export const RuleActionsField: React.FC = ({ setActionAlertsFilterProperty, featureId: SecurityConnectorFeatureId, producerId: AlertConsumers.SIEM, + ruleTypeId, defaultActionMessage: FORM_FOR_EACH_ALERT_BODY_MESSAGE, defaultSummaryMessage: FORM_SUMMARY_BODY_MESSAGE, hideActionHeader: true, @@ -255,15 +258,16 @@ export const RuleActionsField: React.FC = ({ disableErrorMessages: !isFormValidated, }), [ - actions, getActionForm, + actions, messageVariables, summaryMessageVariables, - setActionFrequency, setActionIdByIndex, - setActionParamsProperty, setAlertActionsProperty, + setActionParamsProperty, + setActionFrequency, setActionAlertsFilterProperty, + ruleTypeId, isFormValidated, ] ); diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx index ca79d429e43ad..271c28acf736c 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation/components/step_rule_actions/index.tsx @@ -35,6 +35,7 @@ import { ResponseAction } from './response_action'; interface StepRuleActionsProps extends RuleStepProps { ruleId?: RuleObjectId; // Rule SO's id (not ruleId) + ruleTypeId?: string; actionMessageParams: ActionVariables; summaryActionMessageParams: ActionVariables; form: FormHook; @@ -72,6 +73,7 @@ const DisplayActionsHeader = () => { const StepRuleActionsComponent: FC = ({ ruleId, + ruleTypeId, isUpdateView = false, actionMessageParams, summaryActionMessageParams, @@ -90,11 +92,12 @@ const StepRuleActionsComponent: FC = ({ componentProps={{ messageVariables: actionMessageParams, summaryMessageVariables: summaryActionMessageParams, + ruleTypeId, }} /> ), - [actionMessageParams, summaryActionMessageParams] + [actionMessageParams, ruleTypeId, summaryActionMessageParams] ); const displayResponseActionsOptions = useMemo(() => { return ( diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx index e145edd29c9e0..05fbad5ecdeea 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx @@ -19,6 +19,7 @@ import { import React, { memo, useCallback, useRef, useState, useMemo, useEffect } from 'react'; import styled from 'styled-components'; +import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { isMlRule, @@ -731,6 +732,7 @@ const CreateRulePageComponent: React.FC = () => { }} > { isCreateRuleLoading, isStartingJobs, loading, + ruleType, submitRuleDisabled, submitRuleEnabled, ] diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index b0b134a0bed1e..6643ad2328168 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -22,6 +22,7 @@ import type { FC } from 'react'; import React, { memo, useCallback, useMemo, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; +import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import { useConfirmValidationErrorsModal } from '../../../../common/hooks/use_confirm_validation_errors_modal'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { isEsqlRule } from '../../../../../common/detection_engine/utils'; @@ -338,6 +339,7 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { {actionsStepData != null && ( = ({ rule }) => { esqlQueryForAboutStep, rule.rule_source, rule?.id, + rule?.type, scheduleStepData, scheduleStepForm, actionsStepData, diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_actions/rule_actions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_actions/rule_actions.cy.ts index 050b10e1c85a9..57c36b0ccdc99 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_actions/rule_actions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_actions/rule_actions.cy.ts @@ -5,6 +5,10 @@ * 2.0. */ +import { + CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST, + CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR, +} from '../../../../screens/common/rule_actions'; import { RULE_NAME_HEADER } from '../../../../screens/rule_details'; import { getIndexConnector } from '../../../../objects/connector'; import { getSimpleCustomQueryRule } from '../../../../objects/rule'; @@ -21,6 +25,7 @@ import { } from '../../../../tasks/api_calls/common'; import { createAndEnableRule, + createCasesAction, fillAboutRuleAndContinue, fillDefineCustomRuleAndContinue, fillRuleAction, @@ -106,5 +111,23 @@ describe( // UI redirects to rule creation page of a created rule cy.get(RULE_NAME_HEADER).should('contain', rule.name); }); + + it('Forwards the correct rule type id to the Cases system action', () => { + visit(CREATE_RULE_URL); + fillDefineCustomRuleAndContinue(rule); + fillAboutRuleAndContinue(rule); + fillScheduleRuleAndContinue(rule); + createCasesAction(); + + cy.get(CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR).click(); + cy.get(CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST).should('be.visible'); + cy.waitUntil(() => { + return cy + .get(`${CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST} button[role=option]`) + .then(($items) => { + return $items.length > 0; + }); + }); + }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts b/x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts index 32caf47e43034..63b9928bb38ef 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/common/rule_actions.ts @@ -48,6 +48,12 @@ export const EMAIL_CONNECTOR_PASSWORD_INPUT = '[data-test-subj="emailPasswordInp export const EMAIL_CONNECTOR_SERVICE_SELECTOR = '[data-test-subj="emailServiceSelectInput"]'; +export const CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_SELECTOR = + '[data-test-subj=group-by-alert-field-combobox]'; + +export const CASES_CONNECTOR_GROUP_BY_ALERT_FIELD_OPTIONS_LIST = + '[data-test-subj~=group-by-alert-field-combobox-optionsList]'; + export const FORM_VALIDATION_ERROR = '.euiFormErrorText'; export const JSON_EDITOR = "[data-test-subj='documentToIndex']"; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts index cbb0882c5f6fc..23b480562ad0b 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/create_new_rule.ts @@ -147,6 +147,7 @@ import { ACTIONS_ALERTS_TIMEFRAME_START_INPUT, ACTIONS_ALERTS_TIMEFRAME_END_INPUT, ACTIONS_ALERTS_TIMEFRAME_TIMEZONE_INPUT, + CASES_SYSTEM_ACTION_BTN, } from '../screens/common/rule_actions'; import { fillIndexConnectorForm, fillEmailConnectorForm } from './common/rule_actions'; import { TOAST_ERROR } from '../screens/shared'; @@ -540,6 +541,10 @@ export const fillRuleAction = (actions: Actions) => { }); }; +export const createCasesAction = () => { + cy.get(CASES_SYSTEM_ACTION_BTN).click(); +}; + export const fillRuleActionFilters = (alertsFilter: AlertsFilter) => { cy.get(ACTIONS_ALERTS_QUERY_FILTER_BUTTON).click(); cy.get(ACTIONS_ALERTS_QUERY_FILTER_INPUT()).type(alertsFilter.query.kql); From 26841d07f043894fb831c6b957d9e690c839cf0b Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 06:37:37 +1100 Subject: [PATCH 14/23] [8.x] [scout] validate config has tests before starting servers (#211918) (#211940) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [[scout] validate config has tests before starting servers (#211918)](https://github.com/elastic/kibana/pull/211918) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Dzmitry Lemechko --- .../src/playwright/runner/run_tests.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/kbn-scout/src/playwright/runner/run_tests.ts b/packages/kbn-scout/src/playwright/runner/run_tests.ts index 766209f169963..f4b4dedc6033d 100644 --- a/packages/kbn-scout/src/playwright/runner/run_tests.ts +++ b/packages/kbn-scout/src/playwright/runner/run_tests.ts @@ -8,6 +8,9 @@ */ import { resolve } from 'path'; +import { exec } from 'child_process'; +import { promisify } from 'util'; +const execPromise = promisify(exec); import { ToolingLog } from '@kbn/tooling-log'; import { withProcRunner } from '@kbn/dev-proc-runner'; @@ -28,7 +31,21 @@ export async function runTests(log: ToolingLog, options: RunTestsOptions) { const playwrightGrepTag = getPlaywrightGrepTag(config); const playwrightConfigPath = options.configPath; + const cmd = resolve(REPO_ROOT, './node_modules/.bin/playwright'); + const cmdArgs = ['test', `--config=${playwrightConfigPath}`, `--grep=${playwrightGrepTag}`]; + await withProcRunner(log, async (procs) => { + log.info(`scout: Validate Playwright config has tests`); + try { + // '--list' flag tells Playwright to collect all the tests, but do not run it + const result = await execPromise(`${cmd} ${cmdArgs.join(' ')} --list`); + const lastLine = result.stdout.trim().split('\n').pop(); + log.info(`scout: ${lastLine}`); + } catch (err) { + log.error(`scout: No tests found in [${playwrightConfigPath}]`); + process.exit(2); // code "2" means no tests found + } + const abortCtrl = new AbortController(); const onEarlyExit = (msg: string) => { @@ -60,13 +77,8 @@ export async function runTests(log: ToolingLog, options: RunTestsOptions) { // Running 'npx playwright test --config=${playwrightConfigPath}' await procs.run(`playwright`, { - cmd: resolve(REPO_ROOT, './node_modules/.bin/playwright'), - args: [ - 'test', - `--config=${playwrightConfigPath}`, - `--grep=${playwrightGrepTag}`, - ...(options.headed ? ['--headed'] : []), - ], + cmd, + args: [...cmdArgs, ...(options.headed ? ['--headed'] : [])], cwd: resolve(REPO_ROOT), env: { ...process.env, From 69900c61db6c4f8e6e6f5e7f03ce58c002384269 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 06:54:04 +1100 Subject: [PATCH 15/23] [8.x] [ES|QL] Removes deprecated setImmediate (#211922) (#211948) # Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Removes deprecated setImmediate (#211922)](https://github.com/elastic/kibana/pull/211922) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Stratoula Kalafateli --- .../packages/private/kbn-esql-editor/src/esql_editor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx index ede51c3052f81..43b40458902ee 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx +++ b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx @@ -249,9 +249,9 @@ export const ESQLEditor = memo(function ESQLEditor({ const showSuggestionsIfEmptyQuery = useCallback(() => { if (editorModel.current?.getValueLength() === 0) { - setImmediate(() => { + setTimeout(() => { editor1.current?.trigger(undefined, 'editor.action.triggerSuggest', {}); - }); + }, 0); } }, []); From d0498a95461af6d04aaa7c17c149e5c297782981 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 08:18:36 +1100 Subject: [PATCH 16/23] [8.x] [ES|QL] Suggest triple quotes when the user selects the `KQL` / `QSTR` (#211457) (#211962) # Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Suggest triple quotes when the user selects the `KQL` / `QSTR` (#211457)](https://github.com/elastic/kibana/pull/211457) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Dima Arnautov --- .../scripts/generate_function_definitions.ts | 17 ++++++++++++++--- .../autocomplete.command.where.test.ts | 5 +++-- .../src/autocomplete/__tests__/helpers.ts | 6 ++++-- .../src/autocomplete/commands/where/index.ts | 4 ++-- .../src/autocomplete/factories.ts | 7 ++++++- .../definitions/generated/scalar_functions.ts | 10 ++++++---- .../src/definitions/types.ts | 1 + 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index 1b4940cbc1218..369bf3f581386 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -286,6 +286,12 @@ const functionEnrichments: Record> count: { signatures: [{ params: [{ supportsWildcard: true }] }], }, + qstr: { + customParametersSnippet: `"""$0"""`, + }, + kql: { + customParametersSnippet: `"""$0"""`, + }, }; const convertDateTime = (s: string) => (s === 'datetime' ? 'date' : s); @@ -330,7 +336,7 @@ function getFunctionDefinition(ESFunctionDefinition: Record): Funct description: undefined, ...(FULL_TEXT_SEARCH_FUNCTIONS.includes(ESFunctionDefinition.name) ? // Default to false. If set to true, this parameter does not accept a function or literal, only fields. - idx === 0 + param.name === 'field' ? { fieldsOnly: true } : { constantOnly: true } : {}), @@ -810,7 +816,8 @@ function printGeneratedFunctionsFile( functionDefinition: FunctionDefinition, functionNames: string[] ) => { - const { type, name, description, alias, signatures, operator } = functionDefinition; + const { type, name, description, alias, signatures, operator, customParametersSnippet } = + functionDefinition; let functionName = operator?.toLowerCase() ?? name.toLowerCase(); if (functionName.includes('not')) { @@ -832,7 +839,11 @@ function printGeneratedFunctionsFile( supportedCommands: ${JSON.stringify(functionDefinition.supportedCommands)}, supportedOptions: ${JSON.stringify(functionDefinition.supportedOptions)}, validate: ${functionDefinition.validate || 'undefined'}, - examples: ${JSON.stringify(functionDefinition.examples || [])}, + examples: ${JSON.stringify(functionDefinition.examples || [])},${ + customParametersSnippet + ? `\ncustomParametersSnippet: ${JSON.stringify(customParametersSnippet)},` + : '' + } }`; }; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts index c7c026dde787e..da071122d08f6 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts @@ -19,6 +19,7 @@ import { getFunctionSignaturesByReturnType, setup, } from './helpers'; +import { FULL_TEXT_SEARCH_FUNCTIONS } from '../../shared/constants'; describe('WHERE ', () => { const allEvalFns = getFunctionSignaturesByReturnType('where', 'any', { @@ -40,7 +41,7 @@ describe('WHERE ', () => { .map((name) => `${name} `) .map(attachTriggerCommand), attachTriggerCommand('var0 '), - ...allEvalFns.filter((fn) => fn.label !== 'QSTR'), + ...allEvalFns.filter((fn) => fn.label !== 'QSTR' && fn.label !== 'KQL'), ], { callbacks: { @@ -150,7 +151,7 @@ describe('WHERE ', () => { ...getFieldNamesByType('any') .map((field) => `${field} `) .map(attachTriggerCommand), - ...allEvalFns.filter((fn) => fn.label !== 'QSTR' && fn.label !== 'MATCH'), + ...allEvalFns.filter((fn) => !FULL_TEXT_SEARCH_FUNCTIONS.includes(fn.label!.toLowerCase())), ]); }); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index 36c2163604fb7..bd02f12df30d5 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -215,7 +215,7 @@ export function getFunctionSignaturesByReturnType( }) .sort(({ name: a }, { name: b }) => a.localeCompare(b)) .map((definition) => { - const { type, name, signatures } = definition; + const { type, name, signatures, customParametersSnippet } = definition; if (type === 'operator') { return { @@ -226,7 +226,9 @@ export function getFunctionSignaturesByReturnType( }; } return { - text: `${name.toUpperCase()}($0)`, + text: customParametersSnippet + ? `${name.toUpperCase()}(${customParametersSnippet})` + : `${name.toUpperCase()}($0)`, label: name.toUpperCase(), }; }); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts index b022a73ed6fa0..85265dc353b4a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/where/index.ts @@ -152,14 +152,14 @@ export async function suggest({ break; case 'empty_expression': - // Don't suggest MATCH or QSTR after unsupported commands + // Don't suggest MATCH, QSTR or KQL after unsupported commands const priorCommands = previousCommands?.map((a) => a.name) ?? []; const ignored = []; if (priorCommands.some((c) => UNSUPPORTED_COMMANDS_BEFORE_MATCH.has(c))) { ignored.push('match'); } if (priorCommands.some((c) => UNSUPPORTED_COMMANDS_BEFORE_QSTR.has(c))) { - ignored.push('qstr'); + ignored.push('kql', 'qstr'); } const last = previousCommands?.[previousCommands.length - 1]; let columnSuggestions: SuggestionRawDefinition[] = []; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 9325ef50a785e..af8f677dcd727 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -72,9 +72,14 @@ export function getFunctionSuggestion(fn: FunctionDefinition): SuggestionRawDefi detail = `[${techPreviewLabel}] ${detail}`; } const fullSignatures = getFunctionSignatures(fn, { capitalize: true, withTypes: true }); + + let text = `${fn.name.toUpperCase()}($0)`; + if (fn.customParametersSnippet) { + text = `${fn.name.toUpperCase()}(${fn.customParametersSnippet})`; + } return { label: fn.name.toUpperCase(), - text: `${fn.name.toUpperCase()}($0)`, + text, asSnippet: true, kind: 'Function', detail, diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts index 7973b6e54abfa..b933992243b9b 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts @@ -2734,7 +2734,7 @@ const kqlDefinition: FunctionDefinition = { name: 'query', type: 'keyword', optional: false, - fieldsOnly: true, + constantOnly: true, }, ], returnType: 'boolean', @@ -2745,7 +2745,7 @@ const kqlDefinition: FunctionDefinition = { name: 'query', type: 'text', optional: false, - fieldsOnly: true, + constantOnly: true, }, ], returnType: 'boolean', @@ -2757,6 +2757,7 @@ const kqlDefinition: FunctionDefinition = { examples: [ 'FROM books \n| WHERE KQL("author: Faulkner")\n| KEEP book_no, author \n| SORT book_no \n| LIMIT 5', ], + customParametersSnippet: '"""$0"""', }; // Do not edit this manually... generated by scripts/generate_function_definitions.ts @@ -7244,7 +7245,7 @@ const qstrDefinition: FunctionDefinition = { name: 'query', type: 'keyword', optional: false, - fieldsOnly: true, + constantOnly: true, }, ], returnType: 'boolean', @@ -7255,7 +7256,7 @@ const qstrDefinition: FunctionDefinition = { name: 'query', type: 'text', optional: false, - fieldsOnly: true, + constantOnly: true, }, ], returnType: 'boolean', @@ -7267,6 +7268,7 @@ const qstrDefinition: FunctionDefinition = { examples: [ 'FROM books \n| WHERE QSTR("author: Faulkner")\n| KEEP book_no, author \n| SORT book_no \n| LIMIT 5', ], + customParametersSnippet: '"""$0"""', }; // Do not edit this manually... generated by scripts/generate_function_definitions.ts diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts index 11e215aa75714..0de269191d744 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -187,6 +187,7 @@ export interface FunctionDefinition { examples?: string[]; validate?: (fnDef: ESQLFunction) => ESQLMessage[]; operator?: string; + customParametersSnippet?: string; } export interface CommandSuggestParams { From 48d9161e539a2ef407012a099a0356642336a840 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 08:40:22 +1100 Subject: [PATCH 17/23] [8.x] [Security Solution][Expandable flyout] add ability for user to resize the flyout and the left/right section even if preview is rendered (#211938) (#211964) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution][Expandable flyout] add ability for user to resize the flyout and the left/right section even if preview is rendered (#211938)](https://github.com/elastic/kibana/pull/211938) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Philippe Oberti --- .../src/components/container.tsx | 1 - .../src/components/preview_section.tsx | 5 ++-- .../components/resizable_container.test.tsx | 30 ------------------- .../src/components/resizable_container.tsx | 11 ++----- 4 files changed, 5 insertions(+), 42 deletions(-) diff --git a/x-pack/solutions/security/packages/expandable-flyout/src/components/container.tsx b/x-pack/solutions/security/packages/expandable-flyout/src/components/container.tsx index c121454b6d083..d7c3f9bf51a44 100644 --- a/x-pack/solutions/security/packages/expandable-flyout/src/components/container.tsx +++ b/x-pack/solutions/security/packages/expandable-flyout/src/components/container.tsx @@ -218,7 +218,6 @@ export const Container: React.FC = memo( leftComponent={leftComponent as React.ReactElement} rightComponent={rightComponent as React.ReactElement} showLeft={showExpanded} - showPreview={showPreview} /> {showPreview && ( diff --git a/x-pack/solutions/security/packages/expandable-flyout/src/components/preview_section.tsx b/x-pack/solutions/security/packages/expandable-flyout/src/components/preview_section.tsx index f8f7be38c5f48..6fb9f4de448a6 100644 --- a/x-pack/solutions/security/packages/expandable-flyout/src/components/preview_section.tsx +++ b/x-pack/solutions/security/packages/expandable-flyout/src/components/preview_section.tsx @@ -12,8 +12,8 @@ import { EuiFlexItem, EuiSplitPanel, EuiText, - useEuiTheme, transparentize, + useEuiTheme, } from '@elastic/eui'; import React, { memo, useMemo } from 'react'; import { css } from '@emotion/react'; @@ -100,7 +100,8 @@ export const PreviewSection: React.FC = memo( const percentage = rightPercentage ? rightPercentage : defaultPercentages[type].rightPercentage; - return showExpanded ? `calc(${percentage}% - 8px)` : `calc(100% - 8px)`; + // we need to keep 1px here to make sure users can click on the EuiResizableButton and resize the flyout with preview opened + return showExpanded ? `calc(${percentage}% - 1px)` : `calc(100% - 1px)`; }, [defaultPercentages, rightPercentage, showExpanded, type]); const closeButton = ( diff --git a/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.test.tsx b/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.test.tsx index 1cf939572e1a1..07d11e651cd49 100644 --- a/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.test.tsx +++ b/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.test.tsx @@ -38,7 +38,6 @@ describe('ResizableContainer', () => { leftComponent={leftComponent} rightComponent={rightComponent} showLeft={false} - showPreview={false} /> ); @@ -74,7 +73,6 @@ describe('ResizableContainer', () => { leftComponent={leftComponent} rightComponent={rightComponent} showLeft={true} - showPreview={false} /> ); @@ -91,32 +89,4 @@ describe('ResizableContainer', () => { expect(leftSection).toBeInTheDocument(); expect(leftSection.parentElement).toHaveStyle('inline-size: 50%; block-size: auto;'); }); - - it('should disable the resize button if preview is rendered', () => { - const state = { - ...initialState, - ui: { - ...initialState.ui, - userSectionWidths: { - leftPercentage: 50, - rightPercentage: 50, - }, - }, - }; - - const { getByTestId } = render( - - - - ); - - const resizeButton = getByTestId(RESIZABLE_BUTTON_TEST_ID); - expect(resizeButton).toBeInTheDocument(); - expect(resizeButton).toBeDisabled(); - }); }); diff --git a/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.tsx b/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.tsx index 879552973e9ab..658fbbaef3194 100644 --- a/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.tsx +++ b/x-pack/solutions/security/packages/expandable-flyout/src/components/resizable_container.tsx @@ -41,10 +41,6 @@ interface ResizableContainerProps { * If the left section is not shown we disable the resize button and hide the left size of the resizable panel */ showLeft: boolean; - /** - * If the preview section is shown we disable the resize button - */ - showPreview: boolean; } /** @@ -52,7 +48,7 @@ interface ResizableContainerProps { * It allows the resizing of the sections, saving the percentages in local storage. */ export const ResizableContainer: React.FC = memo( - ({ leftComponent, rightComponent, showLeft, showPreview }: ResizableContainerProps) => { + ({ leftComponent, rightComponent, showLeft }: ResizableContainerProps) => { const dispatch = useDispatch(); const { leftPercentage, rightPercentage } = useSelector(selectUserSectionWidths); @@ -97,10 +93,7 @@ export const ResizableContainer: React.FC = memo( > - + Date: Fri, 21 Feb 2025 08:50:35 +1100 Subject: [PATCH 18/23] [8.x] [ES|QL] Changes function definition type to enum (#211782) (#211965) # Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Changes function definition type to enum (#211782)](https://github.com/elastic/kibana/pull/211782) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Stratoula Kalafateli --- .../kbn-esql-validation-autocomplete/index.ts | 2 +- .../scripts/generate_function_definitions.ts | 48 ++-- .../autocomplete.suggest.eval.test.ts | 4 +- .../src/autocomplete/__tests__/helpers.ts | 7 +- .../hidden_functions_and_commands.test.ts | 13 +- .../src/autocomplete/autocomplete.ts | 12 +- .../src/autocomplete/factories.ts | 7 +- .../src/autocomplete/helper.ts | 13 +- .../src/code_actions/actions.test.ts | 8 +- .../src/code_actions/actions.ts | 8 +- .../src/definitions/all_operators.ts | 23 +- .../src/definitions/commands.ts | 10 +- .../generated/aggregation_functions.ts | 34 +-- .../generated/grouping_functions.ts | 6 +- .../src/definitions/generated/operators.ts | 40 +-- .../definitions/generated/scalar_functions.ts | 230 +++++++++--------- .../src/definitions/types.ts | 9 +- .../src/shared/context.ts | 3 +- .../src/shared/helpers.test.ts | 10 +- .../src/shared/helpers.ts | 7 +- .../__tests__/fields_and_variables.test.ts | 6 +- .../validation/__tests__/functions.test.ts | 62 ++--- .../src/validation/validation.test.ts | 4 +- .../src/validation/validation.ts | 5 +- .../identifier_control_form.tsx | 4 +- 25 files changed, 312 insertions(+), 263 deletions(-) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/index.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/index.ts index 93db9103b9957..4e0f6b3962ae3 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/index.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/index.ts @@ -68,7 +68,7 @@ export { } from './src/shared/helpers'; export { ENRICH_MODES } from './src/definitions/settings'; export { timeUnits } from './src/definitions/literals'; -export { aggregationFunctionDefinitions } from './src/definitions/generated/aggregation_functions'; +export { aggFunctionDefinitions } from './src/definitions/generated/aggregation_functions'; export { getFunctionSignatures } from './src/definitions/helpers'; export { diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts index 369bf3f581386..7da1915c00fd3 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/scripts/generate_function_definitions.ts @@ -17,6 +17,7 @@ import { FunctionParameterType, FunctionReturnType, Signature, + FunctionDefinitionTypes, } from '../src/definitions/types'; import { FULL_TEXT_SEARCH_FUNCTIONS } from '../src/shared/constants'; const aliasTable: Record = { @@ -91,7 +92,7 @@ const excludedFunctions = new Set(['case']); const extraFunctions: FunctionDefinition[] = [ { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'case', description: 'Accepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to `true`. If the number of arguments is odd, the last argument is the default value which is returned when no condition matches.', @@ -307,7 +308,7 @@ function getFunctionDefinition(ESFunctionDefinition: Record): Funct FunctionDefinition, 'supportedCommands' | 'supportedOptions' > = - ESFunctionDefinition.type === 'scalar' + ESFunctionDefinition.type === FunctionDefinitionTypes.SCALAR ? scalarSupportedCommandsAndOptions : aggregationSupportedCommandsAndOptions; @@ -765,7 +766,7 @@ const enrichOperators = ( // so we are overriding to add proper support supportedCommands, supportedOptions, - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, validate: validators[op.name], ...(isNotOperator ? { ignoreAsSuggestion: true } : {}), }; @@ -774,7 +775,7 @@ const enrichOperators = ( function printGeneratedFunctionsFile( functionDefinitions: FunctionDefinition[], - functionsType: 'aggregation' | 'scalar' | 'operator' | 'grouping' + functionsType: FunctionDefinitionTypes ) { /** * Deals with asciidoc internal cross-references in the function descriptions @@ -828,7 +829,7 @@ function printGeneratedFunctionsFile( } return `// Do not edit this manually... generated by scripts/generate_function_definitions.ts const ${getDefinitionName(name)}: FunctionDefinition = { - type: '${type}', + type: FunctionDefinitionTypes.${type.toUpperCase()}, name: '${functionName}', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.${name}', { defaultMessage: ${JSON.stringify( removeAsciiDocInternalCrossReferences(removeInlineAsciiDocLinks(description), functionNames) @@ -867,14 +868,18 @@ function printGeneratedFunctionsFile( */ import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition } from '../types'; +import { type FunctionDefinition, FunctionDefinitionTypes } from '../types'; ${ - functionsType === 'scalar' + functionsType === FunctionDefinitionTypes.SCALAR ? `import type { ESQLFunction } from '@kbn/esql-ast'; import { isLiteralItem } from '../../shared/helpers';` : '' } -${functionsType === 'operator' ? `import { isNumericType } from '../../shared/esql_types';` : ''} +${ + functionsType === FunctionDefinitionTypes.OPERATOR + ? `import { isNumericType } from '../../shared/esql_types';` + : '' +} @@ -927,17 +932,20 @@ ${functionsType === 'operator' ? `import { isNumericType } from '../../shared/es const isLikeOperator = functionDefinition.name.toLowerCase().includes('like'); if (functionDefinition.name.toLowerCase() === 'match') { - scalarFunctionDefinitions.push({ ...functionDefinition, type: 'scalar' }); + scalarFunctionDefinitions.push({ + ...functionDefinition, + type: FunctionDefinitionTypes.SCALAR, + }); continue; } - if (functionDefinition.type === 'operator' || isLikeOperator) { + if (functionDefinition.type === FunctionDefinitionTypes.OPERATOR || isLikeOperator) { operatorDefinitions.push(functionDefinition); } - if (functionDefinition.type === 'scalar' && !isLikeOperator) { + if (functionDefinition.type === FunctionDefinitionTypes.SCALAR && !isLikeOperator) { scalarFunctionDefinitions.push(functionDefinition); - } else if (functionDefinition.type === 'agg') { + } else if (functionDefinition.type === FunctionDefinitionTypes.AGG) { aggFunctionDefinitions.push(functionDefinition); - } else if (functionDefinition.type === 'grouping') { + } else if (functionDefinition.type === FunctionDefinitionTypes.GROUPING) { groupingFunctionDefinitions.push(functionDefinition); } } @@ -946,18 +954,24 @@ ${functionsType === 'operator' ? `import { isNumericType } from '../../shared/es await writeFile( join(__dirname, '../src/definitions/generated/scalar_functions.ts'), - printGeneratedFunctionsFile(scalarFunctionDefinitions, 'scalar') + printGeneratedFunctionsFile(scalarFunctionDefinitions, FunctionDefinitionTypes.SCALAR) ); await writeFile( join(__dirname, '../src/definitions/generated/aggregation_functions.ts'), - printGeneratedFunctionsFile(aggFunctionDefinitions, 'aggregation') + printGeneratedFunctionsFile(aggFunctionDefinitions, FunctionDefinitionTypes.AGG) ); await writeFile( join(__dirname, '../src/definitions/generated/operators.ts'), - printGeneratedFunctionsFile(enrichOperators(operatorDefinitions), 'operator') + printGeneratedFunctionsFile( + enrichOperators(operatorDefinitions), + FunctionDefinitionTypes.OPERATOR + ) ); await writeFile( join(__dirname, '../src/definitions/generated/grouping_functions.ts'), - printGeneratedFunctionsFile(enrichGrouping(groupingFunctionDefinitions), 'grouping') + printGeneratedFunctionsFile( + enrichGrouping(groupingFunctionDefinitions), + FunctionDefinitionTypes.GROUPING + ) ); })(); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts index 706893a3b42b5..39c1142d1deed 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.suggest.eval.test.ts @@ -19,6 +19,7 @@ import { import { ESQL_COMMON_NUMERIC_TYPES } from '../../shared/esql_types'; import { scalarFunctionDefinitions } from '../../definitions/generated/scalar_functions'; import { timeUnitsToSuggest } from '../../definitions/literals'; +import { FunctionDefinitionTypes } from '../../definitions/types'; import { getCompatibleTypesToSuggestNext, getValidFunctionSignaturesForPreviousArgs, @@ -454,7 +455,8 @@ describe('autocomplete.suggest', () => { // Wehther to prepend comma to suggestion string // E.g. if true, "fieldName" -> "fieldName, " - const shouldAddComma = hasMoreMandatoryArgs && fn.type !== 'operator'; + const shouldAddComma = + hasMoreMandatoryArgs && fn.type !== FunctionDefinitionTypes.OPERATOR; const constantOnlyParamDefs = typesToSuggestNext.filter( (p) => p.constantOnly || /_literal/.test(p.type as string) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts index bd02f12df30d5..c24728f853ba4 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/helpers.ts @@ -12,8 +12,9 @@ import { parse } from '@kbn/esql-ast'; import { scalarFunctionDefinitions } from '../../definitions/generated/scalar_functions'; import { operatorsDefinitions } from '../../definitions/all_operators'; import { NOT_SUGGESTED_TYPES } from '../../shared/resources_helpers'; -import { aggregationFunctionDefinitions } from '../../definitions/generated/aggregation_functions'; +import { aggFunctionDefinitions } from '../../definitions/generated/aggregation_functions'; import { timeUnitsToSuggest } from '../../definitions/literals'; +import { FunctionDefinitionTypes } from '../../definitions/types'; import { groupingFunctionDefinitions } from '../../definitions/generated/grouping_functions'; import * as autocomplete from '../autocomplete'; import type { ESQLCallbacks } from '../../shared/types'; @@ -158,7 +159,7 @@ export function getFunctionSignaturesByReturnType( const list = []; if (agg) { - list.push(...aggregationFunctionDefinitions); + list.push(...aggFunctionDefinitions); } if (grouping) { list.push(...groupingFunctionDefinitions); @@ -217,7 +218,7 @@ export function getFunctionSignaturesByReturnType( .map((definition) => { const { type, name, signatures, customParametersSnippet } = definition; - if (type === 'operator') { + if (type === FunctionDefinitionTypes.OPERATOR) { return { text: signatures.some(({ params }) => params.length > 1) ? `${name.toUpperCase()} $0` diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts index 51bb5c7ba165a..011d318195e2b 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/hidden_functions_and_commands.test.ts @@ -8,6 +8,7 @@ */ import { setTestFunctions } from '../../shared/test_functions'; +import { FunctionDefinitionTypes } from '../../definitions/types'; import { setup } from './helpers'; describe('hidden commands', () => { @@ -28,7 +29,7 @@ describe('hidden functions', () => { it('does not suggest hidden scalar functions', async () => { setTestFunctions([ { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'HIDDEN_FUNCTION', description: 'This is a hidden function', signatures: [{ params: [], returnType: 'text' }], @@ -36,7 +37,7 @@ describe('hidden functions', () => { ignoreAsSuggestion: true, }, { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'VISIBLE_FUNCTION', description: 'This is a visible function', signatures: [{ params: [], returnType: 'text' }], @@ -54,7 +55,7 @@ describe('hidden functions', () => { it('does not suggest hidden agg functions', async () => { setTestFunctions([ { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'HIDDEN_FUNCTION', description: 'This is a hidden function', signatures: [{ params: [], returnType: 'text' }], @@ -62,7 +63,7 @@ describe('hidden functions', () => { ignoreAsSuggestion: true, }, { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'VISIBLE_FUNCTION', description: 'This is a visible function', signatures: [{ params: [], returnType: 'text' }], @@ -80,7 +81,7 @@ describe('hidden functions', () => { it('does not suggest hidden operators', async () => { setTestFunctions([ { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'HIDDEN_OPERATOR', description: 'This is a hidden function', supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -97,7 +98,7 @@ describe('hidden functions', () => { ], }, { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'VISIBLE_OPERATOR', description: 'This is a visible function', supportedCommands: ['eval', 'where', 'row', 'sort'], diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 5212f20827326..68c835d74de5a 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -103,7 +103,7 @@ import { getSuggestionsToRightOfOperatorExpression, checkFunctionInvocationComplete, } from './helper'; -import { FunctionParameter, isParameterType } from '../definitions/types'; +import { FunctionParameter, isParameterType, FunctionDefinitionTypes } from '../definitions/types'; import { comparisonFunctions } from '../definitions/all_operators'; import { getRecommendedQueriesSuggestions } from './recommended_queries/suggestions'; @@ -992,11 +992,13 @@ async function getFunctionArgsSuggestions( const shouldAddComma = hasMoreMandatoryArgs && - fnDefinition.type !== 'operator' && + fnDefinition.type !== FunctionDefinitionTypes.OPERATOR && !isCursorFollowedByComma && !canBeBooleanCondition; const shouldAdvanceCursor = - hasMoreMandatoryArgs && fnDefinition.type !== 'operator' && !isCursorFollowedByComma; + hasMoreMandatoryArgs && + fnDefinition.type !== FunctionDefinitionTypes.OPERATOR && + !isCursorFollowedByComma; const suggestedConstants = uniq( typesToSuggestNext @@ -1048,9 +1050,9 @@ async function getFunctionArgsSuggestions( fnToIgnore.push( ...getFunctionsToIgnoreForStats(command, finalCommandArgIndex), // ignore grouping functions, they are only used for grouping - ...getAllFunctions({ type: 'grouping' }).map(({ name }) => name), + ...getAllFunctions({ type: FunctionDefinitionTypes.GROUPING }).map(({ name }) => name), ...(isAggFunctionUsedAlready(command, finalCommandArgIndex) - ? getAllFunctions({ type: 'agg' }).map(({ name }) => name) + ? getAllFunctions({ type: FunctionDefinitionTypes.AGG }).map(({ name }) => name) : []) ); } diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index af8f677dcd727..2938757064655 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { memoize } from 'lodash'; import { SuggestionRawDefinition } from './types'; import { groupingFunctionDefinitions } from '../definitions/generated/grouping_functions'; -import { aggregationFunctionDefinitions } from '../definitions/generated/aggregation_functions'; +import { aggFunctionDefinitions } from '../definitions/generated/aggregation_functions'; import { scalarFunctionDefinitions } from '../definitions/generated/scalar_functions'; import { getFunctionSignatures } from '../definitions/helpers'; import { timeUnitsToSuggest } from '../definitions/literals'; @@ -20,6 +20,7 @@ import { CommandOptionsDefinition, CommandModeDefinition, FunctionParameterType, + FunctionDefinitionTypes, } from '../definitions/types'; import { shouldBeQuotedSource, shouldBeQuotedText } from '../shared/helpers'; import { buildFunctionDocumentation } from './documentation_util'; @@ -39,7 +40,7 @@ const techPreviewLabel = i18n.translate( const allFunctions = memoize( () => - aggregationFunctionDefinitions + aggFunctionDefinitions .concat(scalarFunctionDefinitions) .concat(groupingFunctionDefinitions) .concat(getTestFunctions()), @@ -87,7 +88,7 @@ export function getFunctionSuggestion(fn: FunctionDefinition): SuggestionRawDefi value: buildFunctionDocumentation(fullSignatures, fn.examples), }, // agg functgions have priority over everything else - sortText: fn.type === 'agg' ? '1A' : 'C', + sortText: fn.type === FunctionDefinitionTypes.AGG ? '1A' : 'C', // trigger a suggestion follow up on selection command: TRIGGER_SUGGESTION_COMMAND, }; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts index 0cc2d4c8f565a..e635aaa92dc01 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/helper.ts @@ -22,6 +22,7 @@ import { type FunctionReturnType, type SupportedDataType, isReturnType, + FunctionDefinitionTypes, } from '../definitions/types'; import { findFinalWord, @@ -56,7 +57,10 @@ function extractFunctionArgs(args: ESQLAstItem[]): ESQLFunction[] { function checkContent(fn: ESQLFunction): boolean { const fnDef = getFunctionDefinition(fn.name); - return (!!fnDef && fnDef.type === 'agg') || extractFunctionArgs(fn.args).some(checkContent); + return ( + (!!fnDef && fnDef.type === FunctionDefinitionTypes.AGG) || + extractFunctionArgs(fn.args).some(checkContent) + ); } export function isAggFunctionUsedAlready(command: ESQLCommand, argIndex: number) { @@ -291,7 +295,9 @@ export function getValidSignaturesAndTypesToSuggestNext( // E.g. if true, "fieldName" -> "fieldName, " const alreadyHasComma = fullText ? fullText[offset] === ',' : false; const shouldAddComma = - hasMoreMandatoryArgs && fnDefinition.type !== 'operator' && !alreadyHasComma; + hasMoreMandatoryArgs && + fnDefinition.type !== FunctionDefinitionTypes.OPERATOR && + !alreadyHasComma; const currentArg = enrichedArgs[argIndex]; return { shouldAddComma, @@ -610,7 +616,8 @@ export async function getSuggestionsToRightOfOperatorExpression({ // technically another boolean value should be suggested, but it is a better experience // to actually suggest a wider set of fields/functions const typeToUse = - finalType === 'boolean' && getFunctionDefinition(operator.name)?.type === 'operator' + finalType === 'boolean' && + getFunctionDefinition(operator.name)?.type === FunctionDefinitionTypes.OPERATOR ? ['any'] : (supportedTypes as string[]); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts index 147d8d662a3bf..85317fb44c59f 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts @@ -13,7 +13,7 @@ import { getAllFunctions } from '../shared/helpers'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; import type { CodeActionOptions } from './types'; import type { ESQLRealField } from '../validation/types'; -import type { FieldType } from '../definitions/types'; +import { type FieldType, FunctionDefinitionTypes } from '../definitions/types'; import type { ESQLCallbacks, PartialFieldsMetadataClient } from '../shared/types'; import { FULL_TEXT_SEARCH_FUNCTIONS } from '../shared/constants'; @@ -280,7 +280,7 @@ describe('quick fixes logic', () => { { relaxOnMissingCallbacks: false }, { relaxOnMissingCallbacks: false }, ]) { - for (const fn of getAllFunctions({ type: 'scalar' })) { + for (const fn of getAllFunctions({ type: FunctionDefinitionTypes.SCALAR })) { if (FULL_TEXT_SEARCH_FUNCTIONS.includes(fn.name)) { testQuickFixes( `FROM index | WHERE ${BROKEN_PREFIX}${fn.name}()`, @@ -289,7 +289,7 @@ describe('quick fixes logic', () => { ); } } - for (const fn of getAllFunctions({ type: 'scalar' })) { + for (const fn of getAllFunctions({ type: FunctionDefinitionTypes.SCALAR })) { if (FULL_TEXT_SEARCH_FUNCTIONS.includes(fn.name)) continue; // add an A to the function name to make it invalid testQuickFixes( @@ -318,7 +318,7 @@ describe('quick fixes logic', () => { { equalityCheck: 'include', ...options } ); } - for (const fn of getAllFunctions({ type: 'agg' })) { + for (const fn of getAllFunctions({ type: FunctionDefinitionTypes.AGG })) { if (FULL_TEXT_SEARCH_FUNCTIONS.includes(fn.name)) continue; // add an A to the function name to make it invalid diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.ts index fe55bd3e17b76..1c9951ffeb2df 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/code_actions/actions.ts @@ -29,6 +29,7 @@ import { isSourceItem, shouldBeQuotedText, } from '../shared/helpers'; +import { FunctionDefinitionTypes } from '../definitions/types'; import { ESQLCallbacks } from '../shared/types'; import { buildQueryForFieldsFromSource } from '../validation/helpers'; import { DOUBLE_BACKTICK, SINGLE_TICK_REGEX, METADATA_FIELDS } from '../shared/constants'; @@ -74,9 +75,10 @@ export const getCompatibleFunctionDefinitions = ( command: string, option: string | undefined ): string[] => { - const fnSupportedByCommand = getAllFunctions({ type: ['scalar', 'agg'] }).filter( - ({ name, supportedCommands, supportedOptions }) => - option ? supportedOptions?.includes(option) : supportedCommands.includes(command) + const fnSupportedByCommand = getAllFunctions({ + type: [FunctionDefinitionTypes.SCALAR, FunctionDefinitionTypes.AGG], + }).filter(({ name, supportedCommands, supportedOptions }) => + option ? supportedOptions?.includes(option) : supportedCommands.includes(command) ); return fnSupportedByCommand.map(({ name }) => name); }; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts index 78cfaee709d4b..c5f5fc1302123 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/all_operators.ts @@ -8,7 +8,12 @@ */ import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition, FunctionParameterType, FunctionReturnType } from './types'; +import { + type FunctionDefinition, + type FunctionParameterType, + type FunctionReturnType, + FunctionDefinitionTypes, +} from './types'; import { operatorFunctionDefinitions } from './generated/operators'; type MathFunctionSignature = [FunctionParameterType, FunctionParameterType, FunctionReturnType]; @@ -57,7 +62,7 @@ function createComparisonDefinition( }); return { - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -204,7 +209,7 @@ export const logicalOperators: FunctionDefinition[] = [ }), }, ].map(({ name, description }) => ({ - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -234,7 +239,7 @@ const nullFunctions: FunctionDefinition[] = [ }), }, ].map(({ name, description }) => ({ - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name, description, supportedCommands: ['eval', 'where', 'row', 'sort'], @@ -248,7 +253,7 @@ const nullFunctions: FunctionDefinition[] = [ const otherDefinitions: FunctionDefinition[] = [ { - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name: 'not', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.notDoc', { defaultMessage: 'Not', @@ -263,7 +268,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name: '=', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.assignDoc', { defaultMessage: 'Assign (=)', @@ -290,7 +295,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name: 'as', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.asDoc', { defaultMessage: 'Rename as (AS)', @@ -308,7 +313,7 @@ const otherDefinitions: FunctionDefinition[] = [ ], }, { - type: 'operator' as const, + type: FunctionDefinitionTypes.OPERATOR, name: 'where', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.whereDoc', { defaultMessage: 'WHERE operator', @@ -328,7 +333,7 @@ const otherDefinitions: FunctionDefinition[] = [ { // TODO — this shouldn't be a function or an operator... name: 'info', - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, description: i18n.translate('kbn-esql-validation-autocomplete.esql.definition.infoDoc', { defaultMessage: 'Show information about the current ES node', }), diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts index 497ea79f71e42..9e85cecb6f096 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/commands.ts @@ -36,7 +36,7 @@ import { onOption, withOption, } from './options'; -import type { CommandDefinition } from './types'; +import { type CommandDefinition, FunctionDefinitionTypes } from './types'; import { suggest as suggestForSort } from '../autocomplete/commands/sort'; import { suggest as suggestForKeep } from '../autocomplete/commands/keep'; import { suggest as suggestForDrop } from '../autocomplete/commands/drop'; @@ -81,10 +81,14 @@ const statsValidator = (command: ESQLCommand) => { if (statsArg.length) { function isAggFunction(arg: ESQLAstItem): arg is ESQLFunction { - return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type === 'agg'; + return ( + isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type === FunctionDefinitionTypes.AGG + ); } function isOtherFunction(arg: ESQLAstItem): arg is ESQLFunction { - return isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type !== 'agg'; + return ( + isFunctionItem(arg) && getFunctionDefinition(arg.name)?.type !== FunctionDefinitionTypes.AGG + ); } function checkAggExistence(arg: ESQLFunction): boolean { diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts index 22af81a95bc5c..97de3f4d4d6a0 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/aggregation_functions.ts @@ -27,11 +27,11 @@ */ import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition } from '../types'; +import { type FunctionDefinition, FunctionDefinitionTypes } from '../types'; // Do not edit this manually... generated by scripts/generate_function_definitions.ts const avgDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'avg', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.avg', { defaultMessage: 'The average of a numeric field.', @@ -81,7 +81,7 @@ const avgDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const countDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'count', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.count', { defaultMessage: 'Returns the total number (count) of input values.', @@ -225,7 +225,7 @@ const countDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const countDistinctDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'count_distinct', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.count_distinct', { defaultMessage: 'Returns the approximate number of distinct values.', @@ -796,7 +796,7 @@ const countDistinctDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const maxDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'max', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.max', { defaultMessage: 'The maximum value of a field.', @@ -916,7 +916,7 @@ const maxDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const medianDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'median', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.median', { defaultMessage: @@ -967,7 +967,7 @@ const medianDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const medianAbsoluteDeviationDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'median_absolute_deviation', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.median_absolute_deviation', @@ -1021,7 +1021,7 @@ const medianAbsoluteDeviationDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const minDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'min', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.min', { defaultMessage: 'The minimum value of a field.', @@ -1141,7 +1141,7 @@ const minDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const percentileDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'percentile', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.percentile', { defaultMessage: @@ -1306,7 +1306,7 @@ const percentileDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stCentroidAggDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'st_centroid_agg', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_centroid_agg', { defaultMessage: 'Calculate the spatial centroid over a field with spatial point geometry type.', @@ -1343,7 +1343,7 @@ const stCentroidAggDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stExtentAggDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'st_extent_agg', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_extent_agg', { defaultMessage: @@ -1401,7 +1401,7 @@ const stExtentAggDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stdDevDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'std_dev', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.std_dev', { defaultMessage: 'The standard deviation of a numeric field.', @@ -1451,7 +1451,7 @@ const stdDevDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sumDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'sum', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sum', { defaultMessage: 'The sum of a numeric expression.', @@ -1501,7 +1501,7 @@ const sumDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const topDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'top', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.top', { defaultMessage: 'Collects the top values for a field. Includes repeated values.', @@ -1698,7 +1698,7 @@ const topDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const valuesDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'values', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.values', { defaultMessage: @@ -1818,7 +1818,7 @@ const valuesDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const weightedAvgDefinition: FunctionDefinition = { - type: 'agg', + type: FunctionDefinitionTypes.AGG, name: 'weighted_avg', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.weighted_avg', { defaultMessage: 'The weighted average of a numeric expression.', @@ -1969,7 +1969,7 @@ const weightedAvgDefinition: FunctionDefinition = { 'FROM employees\n| STATS w_avg = WEIGHTED_AVG(salary, height) by languages\n| EVAL w_avg = ROUND(w_avg)\n| KEEP w_avg, languages\n| SORT languages', ], }; -export const aggregationFunctionDefinitions = [ +export const aggFunctionDefinitions = [ avgDefinition, countDefinition, countDistinctDefinition, diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/grouping_functions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/grouping_functions.ts index 04107c20b38d9..a7f814b25a3cd 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/grouping_functions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/grouping_functions.ts @@ -27,11 +27,11 @@ */ import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition } from '../types'; +import { type FunctionDefinition, FunctionDefinitionTypes } from '../types'; // Do not edit this manually... generated by scripts/generate_function_definitions.ts const bucketDefinition: FunctionDefinition = { - type: 'grouping', + type: FunctionDefinitionTypes.GROUPING, name: 'bucket', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.bucket', { defaultMessage: @@ -802,7 +802,7 @@ const bucketDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const categorizeDefinition: FunctionDefinition = { - type: 'grouping', + type: FunctionDefinitionTypes.GROUPING, name: 'categorize', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.categorize', { defaultMessage: 'Groups text messages into categories of similarly formatted text values.', diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts index 8501775b9c53a..07e2d624bc661 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/operators.ts @@ -27,13 +27,13 @@ */ import { i18n } from '@kbn/i18n'; -import type { FunctionDefinition } from '../types'; +import { type FunctionDefinition, FunctionDefinitionTypes } from '../types'; import { isNumericType } from '../../shared/esql_types'; // Do not edit this manually... generated by scripts/generate_function_definitions.ts const addDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '+', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.add', { defaultMessage: @@ -377,7 +377,7 @@ const addDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const divDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '/', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.div', { defaultMessage: @@ -570,7 +570,7 @@ const divDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const equalsDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '==', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.equals', { defaultMessage: @@ -1060,7 +1060,7 @@ const equalsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const greaterThanDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '>', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.greater_than', { defaultMessage: @@ -1434,7 +1434,7 @@ const greaterThanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const greaterThanOrEqualDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '>=', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.greater_than_or_equal', @@ -1811,7 +1811,7 @@ const greaterThanOrEqualDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const inDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'in', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.in', { defaultMessage: @@ -2053,7 +2053,7 @@ const inDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const lessThanDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '<', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.less_than', { defaultMessage: @@ -2427,7 +2427,7 @@ const lessThanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const lessThanOrEqualDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '<=', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.less_than_or_equal', @@ -2748,7 +2748,7 @@ const lessThanOrEqualDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const likeDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'like', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.like', { defaultMessage: @@ -2830,7 +2830,7 @@ const likeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const matchOperatorDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: ':', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.match_operator', { defaultMessage: @@ -3343,7 +3343,7 @@ const matchOperatorDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const modDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '%', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mod', { defaultMessage: @@ -3536,7 +3536,7 @@ const modDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mulDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '*', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mul', { defaultMessage: @@ -3704,7 +3704,7 @@ const mulDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const negDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '-', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.neg', { defaultMessage: 'Returns the negation of the argument.', @@ -3771,7 +3771,7 @@ const negDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notEqualsDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '!=', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_equals', { defaultMessage: @@ -4261,7 +4261,7 @@ const notEqualsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notInDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'not_in', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_in', { defaultMessage: @@ -4505,7 +4505,7 @@ const notInDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notLikeDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'not_like', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_like', { defaultMessage: @@ -4555,7 +4555,7 @@ const notLikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const notRlikeDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'not_rlike', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.not_rlike', { defaultMessage: @@ -4605,7 +4605,7 @@ const notRlikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const rlikeDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: 'rlike', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rlike', { defaultMessage: @@ -4689,7 +4689,7 @@ const rlikeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const subDefinition: FunctionDefinition = { - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, name: '-', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sub', { defaultMessage: diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts index b933992243b9b..7825daff97427 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/generated/scalar_functions.ts @@ -28,12 +28,12 @@ import { i18n } from '@kbn/i18n'; import type { ESQLFunction } from '@kbn/esql-ast'; -import type { FunctionDefinition } from '../types'; +import { type FunctionDefinition, FunctionDefinitionTypes } from '../types'; import { isLiteralItem } from '../../shared/helpers'; // Do not edit this manually... generated by scripts/generate_function_definitions.ts const absDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'abs', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.abs', { defaultMessage: 'Returns the absolute value.', @@ -93,7 +93,7 @@ const absDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const acosDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'acos', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.acos', { defaultMessage: 'Returns the arccosine of `n` as an angle, expressed in radians.', @@ -150,7 +150,7 @@ const acosDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const asinDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'asin', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.asin', { defaultMessage: @@ -208,7 +208,7 @@ const asinDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const atanDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'atan', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.atan', { defaultMessage: @@ -266,7 +266,7 @@ const atanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const atan2Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'atan2', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.atan2', { defaultMessage: @@ -524,7 +524,7 @@ const atan2Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const bitLengthDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'bit_length', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.bit_length', { defaultMessage: 'Returns the bit length of a string.', @@ -563,7 +563,7 @@ const bitLengthDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const byteLengthDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'byte_length', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.byte_length', { defaultMessage: 'Returns the byte length of a string.', @@ -602,7 +602,7 @@ const byteLengthDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const cbrtDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'cbrt', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cbrt', { defaultMessage: @@ -660,7 +660,7 @@ const cbrtDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const ceilDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'ceil', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ceil', { defaultMessage: 'Round a number up to the nearest integer.', @@ -717,7 +717,7 @@ const ceilDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const cidrMatchDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'cidr_match', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cidr_match', { defaultMessage: @@ -769,7 +769,7 @@ const cidrMatchDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const coalesceDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'coalesce', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.coalesce', { defaultMessage: @@ -1050,7 +1050,7 @@ const coalesceDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const concatDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'concat', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.concat', { defaultMessage: 'Concatenates two or more strings.', @@ -1133,7 +1133,7 @@ const concatDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const cosDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'cos', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cos', { defaultMessage: 'Returns the cosine of an angle.', @@ -1190,7 +1190,7 @@ const cosDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const coshDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'cosh', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.cosh', { defaultMessage: 'Returns the hyperbolic cosine of a number.', @@ -1247,7 +1247,7 @@ const coshDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const dateDiffDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'date_diff', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_diff', { defaultMessage: @@ -1489,7 +1489,7 @@ const dateDiffDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const dateExtractDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'date_extract', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_extract', { defaultMessage: 'Extracts parts of a date, like year, month, day, hour.', @@ -1601,7 +1601,7 @@ const dateExtractDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const dateFormatDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'date_format', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_format', { defaultMessage: 'Returns a string representation of a date, in the provided format.', @@ -1700,7 +1700,7 @@ const dateFormatDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const dateParseDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'date_parse', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_parse', { defaultMessage: @@ -1778,7 +1778,7 @@ const dateParseDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const dateTruncDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'date_trunc', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.date_trunc', { defaultMessage: 'Rounds down a date to the closest interval.', @@ -1859,7 +1859,7 @@ const dateTruncDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const eDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'e', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.e', { defaultMessage: "Returns Euler's number.", @@ -1880,7 +1880,7 @@ const eDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const endsWithDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'ends_with', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ends_with', { defaultMessage: @@ -1958,7 +1958,7 @@ const endsWithDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const expDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'exp', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.exp', { defaultMessage: 'Returns the value of e raised to the power of the given number.', @@ -2015,7 +2015,7 @@ const expDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const floorDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'floor', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.floor', { defaultMessage: 'Round a number down to the nearest integer.', @@ -2072,7 +2072,7 @@ const floorDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const fromBase64Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'from_base64', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.from_base64', { defaultMessage: 'Decode a base64 string.', @@ -2109,7 +2109,7 @@ const fromBase64Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const greatestDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'greatest', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.greatest', { defaultMessage: @@ -2342,7 +2342,7 @@ const greatestDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const hashDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'hash', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.hash', { defaultMessage: @@ -2422,7 +2422,7 @@ const hashDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const hypotDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'hypot', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.hypot', { defaultMessage: @@ -2680,7 +2680,7 @@ const hypotDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const ipPrefixDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'ip_prefix', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ip_prefix', { defaultMessage: 'Truncates an IP to a given prefix length.', @@ -2719,7 +2719,7 @@ const ipPrefixDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const kqlDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'kql', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.kql', { defaultMessage: @@ -2762,7 +2762,7 @@ const kqlDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const leastDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'least', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.least', { defaultMessage: @@ -2995,7 +2995,7 @@ const leastDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const leftDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'left', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.left', { defaultMessage: @@ -3045,7 +3045,7 @@ const leftDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const lengthDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'length', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.length', { defaultMessage: 'Returns the character length of a string.', @@ -3084,7 +3084,7 @@ const lengthDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const locateDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'locate', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.locate', { defaultMessage: @@ -3242,7 +3242,7 @@ const locateDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const logDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'log', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.log', { defaultMessage: @@ -3566,7 +3566,7 @@ const logDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const log10Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'log10', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.log10', { defaultMessage: @@ -3647,7 +3647,7 @@ const log10Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const ltrimDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'ltrim', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.ltrim', { defaultMessage: 'Removes leading whitespaces from a string.', @@ -3686,7 +3686,7 @@ const ltrimDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const matchDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'match', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.match', { defaultMessage: @@ -4432,7 +4432,7 @@ const matchDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const md5Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'md5', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.md5', { defaultMessage: 'Computes the MD5 hash of the input.', @@ -4471,7 +4471,7 @@ const md5Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvAppendDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_append', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_append', { defaultMessage: 'Concatenates values of two multi-value fields.', @@ -4743,7 +4743,7 @@ const mvAppendDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvAvgDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_avg', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_avg', { defaultMessage: @@ -4801,7 +4801,7 @@ const mvAvgDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvConcatDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_concat', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_concat', { defaultMessage: @@ -4882,7 +4882,7 @@ const mvConcatDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvCountDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_count', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_count', { defaultMessage: @@ -5050,7 +5050,7 @@ const mvCountDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvDedupeDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_dedupe', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_dedupe', { defaultMessage: 'Remove duplicate values from a multivalued field.', @@ -5217,7 +5217,7 @@ const mvDedupeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvFirstDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_first', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_first', { defaultMessage: @@ -5385,7 +5385,7 @@ const mvFirstDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvLastDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_last', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_last', { defaultMessage: @@ -5553,7 +5553,7 @@ const mvLastDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvMaxDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_max', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_max', { defaultMessage: @@ -5684,7 +5684,7 @@ const mvMaxDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvMedianDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_median', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_median', { defaultMessage: @@ -5745,7 +5745,7 @@ const mvMedianDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvMedianAbsoluteDeviationDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_median_absolute_deviation', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.mv_median_absolute_deviation', @@ -5808,7 +5808,7 @@ const mvMedianAbsoluteDeviationDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvMinDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_min', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_min', { defaultMessage: @@ -5939,7 +5939,7 @@ const mvMinDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvPercentileDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_percentile', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_percentile', { defaultMessage: @@ -6094,7 +6094,7 @@ const mvPercentileDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvPseriesWeightedSumDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_pseries_weighted_sum', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.mv_pseries_weighted_sum', @@ -6132,7 +6132,7 @@ const mvPseriesWeightedSumDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvSliceDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_slice', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_slice', { defaultMessage: @@ -6453,7 +6453,7 @@ const mvSliceDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvSortDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_sort', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_sort', { defaultMessage: 'Sorts a multivalued field in lexicographical order.', @@ -6630,7 +6630,7 @@ const mvSortDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvSumDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_sum', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_sum', { defaultMessage: @@ -6688,7 +6688,7 @@ const mvSumDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const mvZipDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'mv_zip', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.mv_zip', { defaultMessage: @@ -6928,7 +6928,7 @@ const mvZipDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const nowDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'now', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.now', { defaultMessage: 'Returns current date and time.', @@ -6949,7 +6949,7 @@ const nowDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const piDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'pi', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.pi', { defaultMessage: "Returns Pi, the ratio of a circle's circumference to its diameter.", @@ -6970,7 +6970,7 @@ const piDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const powDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'pow', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.pow', { defaultMessage: 'Returns the value of `base` raised to the power of `exponent`.', @@ -7230,7 +7230,7 @@ const powDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const qstrDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'qstr', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.qstr', { defaultMessage: @@ -7273,7 +7273,7 @@ const qstrDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const repeatDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'repeat', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.repeat', { defaultMessage: @@ -7321,7 +7321,7 @@ const repeatDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const replaceDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'replace', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.replace', { defaultMessage: @@ -7499,7 +7499,7 @@ const replaceDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const reverseDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'reverse', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.reverse', { defaultMessage: 'Returns a new string representing the input string in reverse order.', @@ -7539,7 +7539,7 @@ const reverseDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const rightDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'right', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.right', { defaultMessage: @@ -7589,7 +7589,7 @@ const rightDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const roundDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'round', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.round', { defaultMessage: @@ -7769,7 +7769,7 @@ const roundDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const rtrimDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'rtrim', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rtrim', { defaultMessage: 'Removes trailing whitespaces from a string.', @@ -7808,7 +7808,7 @@ const rtrimDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sha1Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'sha1', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sha1', { defaultMessage: 'Computes the SHA1 hash of the input.', @@ -7847,7 +7847,7 @@ const sha1Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sha256Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'sha256', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sha256', { defaultMessage: 'Computes the SHA256 hash of the input.', @@ -7886,7 +7886,7 @@ const sha256Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const signumDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'signum', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.signum', { defaultMessage: @@ -7944,7 +7944,7 @@ const signumDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sinDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'sin', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sin', { defaultMessage: 'Returns the sine of an angle.', @@ -8001,7 +8001,7 @@ const sinDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sinhDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'sinh', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sinh', { defaultMessage: 'Returns the hyperbolic sine of a number.', @@ -8058,7 +8058,7 @@ const sinhDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const spaceDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'space', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.space', { defaultMessage: 'Returns a string made of `number` spaces.', @@ -8085,7 +8085,7 @@ const spaceDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const splitDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'split', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.split', { defaultMessage: 'Split a single valued string into multiple strings.', @@ -8162,7 +8162,7 @@ const splitDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const sqrtDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'sqrt', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sqrt', { defaultMessage: @@ -8220,7 +8220,7 @@ const sqrtDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stContainsDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_contains', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_contains', { defaultMessage: @@ -8360,7 +8360,7 @@ const stContainsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stDisjointDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_disjoint', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_disjoint', { defaultMessage: @@ -8500,7 +8500,7 @@ const stDisjointDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stDistanceDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_distance', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_distance', { defaultMessage: @@ -8550,7 +8550,7 @@ const stDistanceDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stEnvelopeDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_envelope', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_envelope', { defaultMessage: 'Determines the minimum bounding box of the supplied geometry.', @@ -8609,7 +8609,7 @@ const stEnvelopeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stIntersectsDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_intersects', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_intersects', { defaultMessage: @@ -8749,7 +8749,7 @@ const stIntersectsDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stWithinDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_within', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_within', { defaultMessage: @@ -8889,7 +8889,7 @@ const stWithinDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stXDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_x', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_x', { defaultMessage: @@ -8929,7 +8929,7 @@ const stXDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stXmaxDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_xmax', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_xmax', { defaultMessage: @@ -8989,7 +8989,7 @@ const stXmaxDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stXminDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_xmin', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_xmin', { defaultMessage: @@ -9049,7 +9049,7 @@ const stXminDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stYDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_y', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_y', { defaultMessage: @@ -9089,7 +9089,7 @@ const stYDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stYmaxDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_ymax', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_ymax', { defaultMessage: @@ -9149,7 +9149,7 @@ const stYmaxDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const stYminDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'st_ymin', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.st_ymin', { defaultMessage: @@ -9209,7 +9209,7 @@ const stYminDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const startsWithDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'starts_with', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.starts_with', { defaultMessage: @@ -9287,7 +9287,7 @@ const startsWithDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const substringDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'substring', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.substring', { defaultMessage: @@ -9349,7 +9349,7 @@ const substringDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const tanDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'tan', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tan', { defaultMessage: 'Returns the tangent of an angle.', @@ -9406,7 +9406,7 @@ const tanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const tanhDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'tanh', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tanh', { defaultMessage: 'Returns the hyperbolic tangent of a number.', @@ -9463,7 +9463,7 @@ const tanhDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const tauDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'tau', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.tau', { defaultMessage: "Returns the ratio of a circle's circumference to its radius.", @@ -9484,7 +9484,7 @@ const tauDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const termDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'term', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.term', { defaultMessage: @@ -9564,7 +9564,7 @@ const termDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toBase64Definition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_base64', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_base64', { defaultMessage: 'Encode a string to a base64 string.', @@ -9601,7 +9601,7 @@ const toBase64Definition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toBooleanDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_boolean', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_boolean', { defaultMessage: @@ -9689,7 +9689,7 @@ const toBooleanDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toCartesianpointDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_cartesianpoint', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.to_cartesianpoint', @@ -9742,7 +9742,7 @@ const toCartesianpointDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toCartesianshapeDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_cartesianshape', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.to_cartesianshape', @@ -9805,7 +9805,7 @@ const toCartesianshapeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toDateNanosDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_date_nanos', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_date_nanos', { defaultMessage: 'Converts an input to a nanosecond-resolution date value (aka date_nanos).', @@ -9892,7 +9892,7 @@ const toDateNanosDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toDateperiodDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_dateperiod', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_dateperiod', { defaultMessage: 'Converts an input value into a `date_period` value.', @@ -9941,7 +9941,7 @@ const toDateperiodDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toDatetimeDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_datetime', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_datetime', { defaultMessage: @@ -10042,7 +10042,7 @@ const toDatetimeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toDegreesDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_degrees', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_degrees', { defaultMessage: 'Converts a number in radians to degrees.', @@ -10099,7 +10099,7 @@ const toDegreesDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toDoubleDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_double', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_double', { defaultMessage: @@ -10229,7 +10229,7 @@ const toDoubleDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toGeopointDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_geopoint', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_geopoint', { defaultMessage: @@ -10277,7 +10277,7 @@ const toGeopointDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toGeoshapeDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_geoshape', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_geoshape', { defaultMessage: @@ -10337,7 +10337,7 @@ const toGeoshapeDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toIntegerDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_integer', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_integer', { defaultMessage: @@ -10445,7 +10445,7 @@ const toIntegerDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toIpDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_ip', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_ip', { defaultMessage: 'Converts an input string to an IP value.', @@ -10494,7 +10494,7 @@ const toIpDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toLongDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_long', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_long', { defaultMessage: @@ -10624,7 +10624,7 @@ const toLongDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toLowerDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_lower', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_lower', { defaultMessage: 'Returns a new string representing the input string converted to lower case.', @@ -10661,7 +10661,7 @@ const toLowerDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toRadiansDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_radians', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_radians', { defaultMessage: 'Converts a number in degrees to radians.', @@ -10718,7 +10718,7 @@ const toRadiansDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toStringDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_string', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_string', { defaultMessage: 'Converts an input value into a string.', @@ -10885,7 +10885,7 @@ const toStringDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toTimedurationDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_timeduration', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_timeduration', { defaultMessage: 'Converts an input value into a `time_duration` value.', @@ -10934,7 +10934,7 @@ const toTimedurationDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toUnsignedLongDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_unsigned_long', description: i18n.translate( 'kbn-esql-validation-autocomplete.esql.definitions.to_unsigned_long', @@ -11037,7 +11037,7 @@ const toUnsignedLongDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toUpperDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_upper', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_upper', { defaultMessage: 'Returns a new string representing the input string converted to upper case.', @@ -11074,7 +11074,7 @@ const toUpperDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const toVersionDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'to_version', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.to_version', { defaultMessage: 'Converts an input string to a version value.', @@ -11121,7 +11121,7 @@ const toVersionDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const trimDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'trim', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.trim', { defaultMessage: 'Removes leading and trailing whitespaces from a string.', @@ -11160,7 +11160,7 @@ const trimDefinition: FunctionDefinition = { // Do not edit this manually... generated by scripts/generate_function_definitions.ts const caseDefinition: FunctionDefinition = { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'case', description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.case', { defaultMessage: diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts index 0de269191d744..a3aa51c696d61 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -174,8 +174,15 @@ export interface Signature { returnType: FunctionReturnType; } +export enum FunctionDefinitionTypes { + AGG = 'agg', + SCALAR = 'scalar', + OPERATOR = 'operator', + GROUPING = 'grouping', +} + export interface FunctionDefinition { - type: 'agg' | 'scalar' | 'operator' | 'grouping'; + type: FunctionDefinitionTypes; preview?: boolean; ignoreAsSuggestion?: boolean; name: string; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts index 8bc59fad94ff8..95d3a9fa2d33b 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/context.ts @@ -19,6 +19,7 @@ import { isIdentifier, } from '@kbn/esql-ast'; import { ENRICH_MODES } from '../definitions/settings'; +import { FunctionDefinitionTypes } from '../definitions/types'; import { EDITOR_MARKER } from './constants'; import { isOptionItem, @@ -139,7 +140,7 @@ function isNotEnrichClauseAssigment(node: ESQLFunction, command: ESQLCommand) { } function isOperator(node: ESQLFunction) { - return getFunctionDefinition(node.name)?.type === 'operator'; + return getFunctionDefinition(node.name)?.type === FunctionDefinitionTypes.OPERATOR; } /** diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts index d453741e6e1de..b4e3deb664e1e 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.test.ts @@ -9,7 +9,7 @@ import { parse } from '@kbn/esql-ast'; import { getBracketsToClose, getExpressionType, shouldBeQuotedSource } from './helpers'; -import { SupportedDataType } from '../definitions/types'; +import { SupportedDataType, FunctionDefinitionTypes } from '../definitions/types'; import { setTestFunctions } from './test_functions'; describe('shouldBeQuotedSource', () => { @@ -184,7 +184,7 @@ describe('getExpressionType', () => { beforeAll(() => { setTestFunctions([ { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'test', description: 'Test function', supportedCommands: ['eval'], @@ -201,14 +201,14 @@ describe('getExpressionType', () => { ], }, { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'returns_keyword', description: 'Test function', supportedCommands: ['eval'], signatures: [{ params: [], returnType: 'keyword' }], }, { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'accepts_dates', description: 'Test function', supportedCommands: ['eval'], @@ -297,7 +297,7 @@ describe('getExpressionType', () => { it('accounts for the "any" parameter type', () => { setTestFunctions([ { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, name: 'test', description: 'Test function', supportedCommands: ['eval'], diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts index d58d5681422ee..0aa03b3d37999 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/helpers.ts @@ -25,7 +25,7 @@ import { ESQLParamLiteral, ESQLProperNode, } from '@kbn/esql-ast/src/types'; -import { aggregationFunctionDefinitions } from '../definitions/generated/aggregation_functions'; +import { aggFunctionDefinitions } from '../definitions/generated/aggregation_functions'; import { operatorsDefinitions } from '../definitions/all_operators'; import { commandDefinitions } from '../definitions/commands'; import { scalarFunctionDefinitions } from '../definitions/generated/scalar_functions'; @@ -50,6 +50,7 @@ import { FunctionReturnType, ArrayType, SupportedDataType, + FunctionDefinitionTypes, } from '../definitions/types'; import type { ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types'; import { removeMarkerArgFromArgsList } from './context'; @@ -146,7 +147,7 @@ function buildFunctionLookup() { fnLookups = operatorsDefinitions .concat( scalarFunctionDefinitions, - aggregationFunctionDefinitions, + aggFunctionDefinitions, groupingFunctionDefinitions, getTestFunctions() ) @@ -652,7 +653,7 @@ export function shouldBeQuotedText( } export const isAggFunction = (arg: ESQLFunction): boolean => - getFunctionDefinition(arg.name)?.type === 'agg'; + getFunctionDefinition(arg.name)?.type === FunctionDefinitionTypes.AGG; export const isParam = (x: unknown): x is ESQLParamLiteral => !!x && diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/fields_and_variables.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/fields_and_variables.test.ts index 1224edeb7dbce..8a6313255c1af 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/fields_and_variables.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/fields_and_variables.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FunctionParameterType } from '../../definitions/types'; +import { FunctionParameterType, FunctionDefinitionTypes } from '../../definitions/types'; import { setTestFunctions } from '../../shared/test_functions'; import { setup } from './helpers'; @@ -117,7 +117,7 @@ describe('variable support', () => { setTestFunctions([ // this test function is just used to test the type of the variable { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: 'Test function', supportedCommands: ['eval'], name: 'test', @@ -128,7 +128,7 @@ describe('variable support', () => { // this test function is used to check that the correct return type is used // when determining variable types { - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: 'Test function', supportedCommands: ['eval'], name: 'return_value', diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts index df1a8b2e5314d..8b16ea7e3dd26 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/__tests__/functions.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { FunctionDefinition } from '../../definitions/types'; +import { FunctionDefinition, FunctionDefinitionTypes } from '../../definitions/types'; import { setTestFunctions } from '../../shared/test_functions'; import { setup } from './helpers'; @@ -23,7 +23,7 @@ describe('function validation', () => { const definitions: FunctionDefinition[] = [ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -39,7 +39,7 @@ describe('function validation', () => { }, { name: 'returns_integer', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -51,7 +51,7 @@ describe('function validation', () => { }, { name: 'returns_double', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -145,7 +145,7 @@ describe('function validation', () => { it('any type', async () => { const testFn: FunctionDefinition = { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -170,7 +170,7 @@ describe('function validation', () => { it('list type', async () => { const testFn: FunctionDefinition = { name: 'in', - type: 'operator', + type: FunctionDefinitionTypes.OPERATOR, description: '', supportedCommands: ['row'], signatures: [ @@ -198,7 +198,7 @@ describe('function validation', () => { it('checks types by signature', async () => { const testFn: FunctionDefinition = { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -269,7 +269,7 @@ describe('function validation', () => { const testFns: FunctionDefinition[] = [ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -288,7 +288,7 @@ describe('function validation', () => { }, { name: 'variadic_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -327,7 +327,7 @@ describe('function validation', () => { const testFns: FunctionDefinition[] = [ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -354,7 +354,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'supports_all', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -366,7 +366,7 @@ describe('function validation', () => { }, { name: 'does_not_support_all', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -397,7 +397,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -428,7 +428,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -440,7 +440,7 @@ describe('function validation', () => { }, { name: 'test2', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -476,7 +476,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -510,7 +510,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'test1', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -522,7 +522,7 @@ describe('function validation', () => { }, { name: 'test2', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -534,7 +534,7 @@ describe('function validation', () => { }, { name: 'test3', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -561,7 +561,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'eval_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -573,7 +573,7 @@ describe('function validation', () => { }, { name: 'stats_fn', - type: 'agg', + type: FunctionDefinitionTypes.AGG, description: '', supportedCommands: ['stats'], signatures: [ @@ -585,7 +585,7 @@ describe('function validation', () => { }, { name: 'row_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['row'], signatures: [ @@ -597,7 +597,7 @@ describe('function validation', () => { }, { name: 'where_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['where'], signatures: [ @@ -609,7 +609,7 @@ describe('function validation', () => { }, { name: 'sort_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['sort'], signatures: [ @@ -649,7 +649,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'supports_by_option', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], supportedOptions: ['by'], @@ -662,7 +662,7 @@ describe('function validation', () => { }, { name: 'does_not_support_by_option', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], supportedOptions: [], @@ -676,7 +676,7 @@ describe('function validation', () => { { name: 'agg_fn', - type: 'agg', + type: FunctionDefinitionTypes.AGG, description: '', supportedCommands: ['stats'], supportedOptions: [], @@ -703,7 +703,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'test', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -715,7 +715,7 @@ describe('function validation', () => { }, { name: 'test2', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['eval'], signatures: [ @@ -736,7 +736,7 @@ describe('function validation', () => { setTestFunctions([ { name: 'agg_fn', - type: 'agg', + type: FunctionDefinitionTypes.AGG, description: '', supportedCommands: ['stats'], signatures: [ @@ -748,7 +748,7 @@ describe('function validation', () => { }, { name: 'scalar_fn', - type: 'scalar', + type: FunctionDefinitionTypes.SCALAR, description: '', supportedCommands: ['stats'], signatures: [ diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 3661a0f87d11c..7b06c19091a02 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -20,7 +20,7 @@ import { fieldTypes as _fieldTypes, } from '../definitions/types'; import { timeUnits, timeUnitsToSuggest } from '../definitions/literals'; -import { aggregationFunctionDefinitions } from '../definitions/generated/aggregation_functions'; +import { aggFunctionDefinitions } from '../definitions/generated/aggregation_functions'; import capitalize from 'lodash/capitalize'; import { camelCase } from 'lodash'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; @@ -43,7 +43,7 @@ const NESTED_DEPTHS = Array(NESTING_LEVELS) .fill(0) .map((_, i) => i + 1); -const toAvgSignature = aggregationFunctionDefinitions.find(({ name }) => name === 'avg')!; +const toAvgSignature = aggFunctionDefinitions.find(({ name }) => name === 'avg')!; const toInteger = scalarFunctionDefinitions.find(({ name }) => name === 'to_integer')!; const toDoubleSignature = scalarFunctionDefinitions.find(({ name }) => name === 'to_double')!; const toStringSignature = scalarFunctionDefinitions.find(({ name }) => name === 'to_string')!; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts index 9a43caf8e359a..21c4df26d55e8 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -35,6 +35,7 @@ import { CommandModeDefinition, CommandOptionsDefinition, FunctionParameter, + FunctionDefinitionTypes, } from '../definitions/types'; import { areFieldAndVariableTypesCompatible, @@ -215,7 +216,7 @@ function validateNestedFunctionArg( const argFn = getFunctionDefinition(actualArg.name)!; const fnDef = getFunctionDefinition(astFunction.name)!; // no nestying criteria should be enforced only for same type function - if (fnDef.type === 'agg' && argFn.type === 'agg') { + if (fnDef.type === FunctionDefinitionTypes.AGG && argFn.type === FunctionDefinitionTypes.AGG) { messages.push( getMessageFromId({ messageId: 'noNestedArgumentSupport', @@ -838,7 +839,7 @@ const validateAggregates = ( visitFunction: (fn) => { const definition = getFunctionDefinition(fn.name); if (!definition) return; - if (definition.type === 'agg') hasAggregationFunction = true; + if (definition.type === FunctionDefinitionTypes.AGG) hasAggregationFunction = true; }, }); diff --git a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx index 9b67486e702c9..d16572e5a6f61 100644 --- a/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx +++ b/src/platform/plugins/shared/esql/public/triggers/esql_controls/control_flyout/identifier_control_form.tsx @@ -23,7 +23,7 @@ import type { ISearchGeneric } from '@kbn/search-types'; import { ESQLVariableType, ESQLControlVariable, - aggregationFunctionDefinitions, + aggFunctionDefinitions, } from '@kbn/esql-validation-autocomplete'; import { getESQLQueryColumnsRaw } from '@kbn/esql-utils'; import type { ESQLControlState, ControlWidthOptions } from '../types'; @@ -131,7 +131,7 @@ export function IdentifierControlForm({ }); } if (variableType === ESQLVariableType.FUNCTIONS) { - const aggregatedFunctions = aggregationFunctionDefinitions.map((func) => { + const aggregatedFunctions = aggFunctionDefinitions.map((func) => { return { label: func.name, key: func.name, From 3fbb51c1bdbd3473543f0ee9b3a220950c206644 Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:56:58 +1100 Subject: [PATCH 19/23] [8.x] [ui_actions] replace subscribeToCompatibilityChanges with getCompatibilityChangesSubject (#210693) (#211980) # Backport This will backport the following commits from `main` to `8.x`: - [[ui_actions] replace subscribeToCompatibilityChanges with getCompatibilityChangesSubject (#210693)](https://github.com/elastic/kibana/pull/210693) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Nathan Reese --- .../public/deprecation_badge.ts | 13 ++--- .../custom_time_range_badge.test.ts | 11 ++-- .../custom_time_range_badge.tsx | 13 ++--- .../edit_panel_action.test.tsx | 11 ++-- .../edit_panel_action/edit_panel_action.ts | 17 ++---- .../presentation_panel_hover_actions.tsx | 56 ++++++++++++------- .../use_presentation_panel_header_actions.tsx | 43 ++++++++++---- .../presentation_panel_error_internal.tsx | 26 +++++---- .../actions/clear_control_action.test.tsx | 13 ++--- .../public/actions/clear_control_action.tsx | 14 ++--- .../components/floating_actions.tsx | 16 ++++-- .../expand_panel_action.test.tsx | 11 ++-- .../dashboard_actions/expand_panel_action.tsx | 17 +++--- .../filters_notification_action.test.tsx | 20 ++++--- .../filters_notification_action.tsx | 9 +-- .../ui_actions/public/actions/action.ts | 20 ++----- .../public/actions/action_internal.ts | 6 +- .../public/service/ui_actions_service.ts | 2 +- .../open_in_discover_action.ts | 15 ++--- 19 files changed, 177 insertions(+), 156 deletions(-) diff --git a/src/platform/plugins/private/input_control_vis/public/deprecation_badge.ts b/src/platform/plugins/private/input_control_vis/public/deprecation_badge.ts index 1b96eda7fe293..278c6f31e7465 100644 --- a/src/platform/plugins/private/input_control_vis/public/deprecation_badge.ts +++ b/src/platform/plugins/private/input_control_vis/public/deprecation_badge.ts @@ -19,6 +19,7 @@ import { import { Action } from '@kbn/ui-actions-plugin/public'; import { apiHasVisualizeConfig, HasVisualizeConfig } from '@kbn/visualizations-plugin/public'; +import { map } from 'rxjs'; import { INPUT_CONTROL_VIS_TYPE } from './input_control_vis_type'; const ACTION_DEPRECATION_BADGE = 'ACTION_INPUT_CONTROL_DEPRECATION_BADGE'; @@ -66,14 +67,10 @@ export class InputControlDeprecationBadge implements Action) => void - ) { - if (!isApiCompatible(embeddable)) return; - return getViewModeSubject(embeddable)?.subscribe(() => { - onChange(compatibilityCheck(embeddable), this); - }); + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { + return isApiCompatible(embeddable) + ? getViewModeSubject(embeddable)?.pipe(map(() => undefined)) + : undefined; } public async execute() { diff --git a/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.test.ts b/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.test.ts index b7915d5abc358..509fb7fc968ef 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.test.ts +++ b/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.test.ts @@ -10,7 +10,7 @@ import { Filter, TimeRange, type AggregateQuery, type Query } from '@kbn/es-query'; import { PublishesUnifiedSearch } from '@kbn/presentation-publishing'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, take } from 'rxjs'; import { CustomTimeRangeBadge } from './custom_time_range_badge'; const mockTimeRange: TimeRange = { from: 'now-17m', to: 'now' }; @@ -45,11 +45,12 @@ describe('custom time range badge action', () => { expect(await action.isCompatible(emptyContext)).toBe(false); }); - it('calls onChange when time range changes', () => { - const onChange = jest.fn(); + it('getCompatibilityChangesSubject emits when time range changes', (done) => { updateTimeRange(mockTimeRange); - action.subscribeToCompatibilityChanges(context, onChange); + const subject = action.getCompatibilityChangesSubject(context); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); updateTimeRange(undefined); - expect(onChange).toHaveBeenCalledWith(false, action); }); }); diff --git a/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.tsx b/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.tsx index 506c4c10d0424..19f7f1aa6ef5f 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.tsx +++ b/src/platform/plugins/private/presentation_panel/public/panel_actions/customize_panel_action/custom_time_range_badge.tsx @@ -18,6 +18,7 @@ import React from 'react'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; import { apiPublishesTimeRange, EmbeddableApiContext } from '@kbn/presentation-publishing'; +import { map } from 'rxjs'; import { ACTION_CUSTOMIZE_PANEL, CUSTOM_TIME_RANGE_BADGE } from './constants'; import { core, uiActions } from '../../kibana_services'; @@ -58,14 +59,10 @@ export class CustomTimeRangeBadge return apiPublishesTimeRange(embeddable); } - public subscribeToCompatibilityChanges( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: CustomTimeRangeBadge) => void - ) { - if (!apiPublishesTimeRange(embeddable)) return; - return embeddable.timeRange$.subscribe((timeRange) => { - onChange(Boolean(timeRange), this); - }); + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { + return apiPublishesTimeRange(embeddable) + ? embeddable.timeRange$.pipe(map(() => undefined)) + : undefined; } public async execute(context: ActionExecutionMeta & EmbeddableApiContext) { diff --git a/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.test.tsx b/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.test.tsx index 2c7447baf5006..52c3124a385c4 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.test.tsx +++ b/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.test.tsx @@ -8,7 +8,7 @@ */ import { PublishesViewMode, ViewMode } from '@kbn/presentation-publishing'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, take } from 'rxjs'; import { EditPanelAction, EditPanelActionApi } from './edit_panel_action'; describe('Edit panel action', () => { @@ -63,10 +63,11 @@ describe('Edit panel action', () => { expect(await action.getHref(context)).toBe(href); }); - it('calls onChange when view mode changes', () => { - const onChange = jest.fn(); - action.subscribeToCompatibilityChanges(context, onChange); + it('getCompatibilityChangesSubject emits when view mode changes', (done) => { + const subject = action.getCompatibilityChangesSubject(context); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); setViewMode('view'); - expect(onChange).toHaveBeenCalledWith(false, action); }); }); diff --git a/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.ts b/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.ts index 9e1efc2ec928b..a65f52c3ed8ef 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.ts +++ b/src/platform/plugins/private/presentation_panel/public/panel_actions/edit_panel_action/edit_panel_action.ts @@ -23,6 +23,7 @@ import { FrequentCompatibilityChangeAction, IncompatibleActionError, } from '@kbn/ui-actions-plugin/public'; +import { map } from 'rxjs'; import { ACTION_EDIT_PANEL } from './constants'; export type EditPanelActionApi = CanAccessViewMode & HasEditCapabilities; @@ -50,18 +51,10 @@ export class EditPanelAction }); } - public subscribeToCompatibilityChanges( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: Action) => void - ) { - if (!isApiCompatible(embeddable)) return; - return getViewModeSubject(embeddable)?.subscribe((viewMode) => { - if (viewMode === 'edit' && isApiCompatible(embeddable) && embeddable.isEditingEnabled()) { - onChange(true, this); - return; - } - onChange(false, this); - }); + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { + return isApiCompatible(embeddable) + ? getViewModeSubject(embeddable)?.pipe(map(() => undefined)) + : undefined; } public couldBecomeCompatible({ embeddable }: EmbeddableApiContext) { diff --git a/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx b/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx index e258c21e003cd..bf26a12508526 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx +++ b/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx @@ -41,7 +41,7 @@ import { ViewMode, } from '@kbn/presentation-publishing'; import { ActionWithContext } from '@kbn/ui-actions-plugin/public/context_menu/build_eui_context_menu_panels'; -import { Subscription } from 'rxjs'; +import { Subscription, switchMap } from 'rxjs'; import { uiActions } from '../../kibana_services'; import { CONTEXT_MENU_TRIGGER, @@ -188,17 +188,24 @@ export const PresentationPanelHoverActions = ({ for (const frequentlyChangingAction of frequentlyChangingActions) { if ((quickActionIds as readonly string[]).includes(frequentlyChangingAction.id)) { - subscriptions.add( - frequentlyChangingAction.subscribeToCompatibilityChanges( - apiContext, - (isCompatible, action) => - handleActionCompatibilityChange( - 'quickActions', - isCompatible, - action as AnyApiAction - ) + const compatibilitySubscription = frequentlyChangingAction + .getCompatibilityChangesSubject(apiContext) + ?.pipe( + switchMap(async () => { + return await frequentlyChangingAction.isCompatible({ + ...apiContext, + trigger: contextMenuTrigger, + }); + }) ) - ); + .subscribe(async (isCompatible) => { + handleActionCompatibilityChange( + 'quickActions', + isCompatible, + frequentlyChangingAction as AnyApiAction + ); + }); + subscriptions.add(compatibilitySubscription); } } @@ -214,17 +221,24 @@ export const PresentationPanelHoverActions = ({ if ( (ALLOWED_NOTIFICATIONS as readonly string[]).includes(frequentlyChangingNotification.id) ) { - subscriptions.add( - frequentlyChangingNotification.subscribeToCompatibilityChanges( - apiContext, - (isCompatible, action) => - handleActionCompatibilityChange( - 'notifications', - isCompatible, - action as AnyApiAction - ) + const compatibilitySubscription = frequentlyChangingNotification + .getCompatibilityChangesSubject(apiContext) + ?.pipe( + switchMap(async () => { + return await frequentlyChangingNotification.isCompatible({ + ...apiContext, + trigger: panelNotificationTrigger, + }); + }) ) - ); + .subscribe(async (isCompatible) => { + handleActionCompatibilityChange( + 'notifications', + isCompatible, + frequentlyChangingNotification as AnyApiAction + ); + }); + subscriptions.add(compatibilitySubscription); } } })(); diff --git a/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx b/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx index d5655273f3f1e..a8a0edb7d7245 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx +++ b/src/platform/plugins/private/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx @@ -9,7 +9,7 @@ import { EuiBadge, EuiNotificationBadge, EuiToolTip, useEuiTheme } from '@elastic/eui'; import React, { useEffect, useMemo, useState } from 'react'; -import { Subscription } from 'rxjs'; +import { Subscription, switchMap } from 'rxjs'; import { uiActions } from '../../kibana_services'; import { @@ -86,11 +86,20 @@ export const usePresentationPanelHeaderActions = < ); if (canceled) return; for (const badge of frequentlyChangingBadges) { - subscriptions.add( - badge.subscribeToCompatibilityChanges(apiContext, (isCompatible, action) => - handleActionCompatibilityChange('badge', isCompatible, action as AnyApiAction) + const compatibilitySubject = badge + .getCompatibilityChangesSubject(apiContext) + ?.pipe( + switchMap(async () => { + return await badge.isCompatible({ + ...apiContext, + trigger: panelBadgeTrigger, + }); + }) ) - ); + .subscribe(async (isCompatible) => { + handleActionCompatibilityChange('badge', isCompatible, badge as AnyApiAction); + }); + subscriptions.add(compatibilitySubject); } // subscribe to any frequently changing notification actions @@ -101,12 +110,26 @@ export const usePresentationPanelHeaderActions = < ); if (canceled) return; for (const notification of frequentlyChangingNotifications) { - if (!disabledNotifications.includes(notification.id)) - subscriptions.add( - notification.subscribeToCompatibilityChanges(apiContext, (isCompatible, action) => - handleActionCompatibilityChange('notification', isCompatible, action as AnyApiAction) + if (!disabledNotifications.includes(notification.id)) { + const compatibilitySubject = notification + .getCompatibilityChangesSubject(apiContext) + ?.pipe( + switchMap(async () => { + return await notification.isCompatible({ + ...apiContext, + trigger: panelNotificationTrigger, + }); + }) ) - ); + .subscribe(async (isCompatible) => { + handleActionCompatibilityChange( + 'notification', + isCompatible, + notification as AnyApiAction + ); + }); + subscriptions.add(compatibilitySubject); + } } })(); diff --git a/src/platform/plugins/private/presentation_panel/public/panel_component/presentation_panel_error_internal.tsx b/src/platform/plugins/private/presentation_panel/public/panel_component/presentation_panel_error_internal.tsx index 3a5c7c5b7830d..7948efac46114 100644 --- a/src/platform/plugins/private/presentation_panel/public/panel_component/presentation_panel_error_internal.tsx +++ b/src/platform/plugins/private/presentation_panel/public/panel_component/presentation_panel_error_internal.tsx @@ -14,7 +14,7 @@ import { ErrorLike } from '@kbn/expressions-plugin/common'; import { EmbeddableApiContext, useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { renderSearchError } from '@kbn/search-errors'; import { Markdown } from '@kbn/shared-ux-markdown'; -import { Subscription } from 'rxjs'; +import { Subscription, switchMap } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { useErrorTextStyle } from '@kbn/react-hooks'; import { ActionExecutionMeta } from '@kbn/ui-actions-plugin/public'; @@ -80,20 +80,26 @@ export const PresentationPanelErrorInternal = ({ api, error }: PresentationPanel const subscription = new Subscription(); (async () => { const editPanelAction = await uiActions.getAction(ACTION_EDIT_PANEL); - if (canceled || !editPanelAction?.couldBecomeCompatible?.({ embeddable: api })) return; - - const initiallyCompatible = await editPanelAction?.isCompatible({ + const context = { embeddable: api, trigger: { id: CONTEXT_MENU_TRIGGER }, - } as EmbeddableApiContext & ActionExecutionMeta); + }; + if (canceled || !editPanelAction?.couldBecomeCompatible?.(context)) return; + + const initiallyCompatible = await editPanelAction?.isCompatible(context); if (canceled) return; setIsEditable(initiallyCompatible); - - subscription.add( - editPanelAction?.subscribeToCompatibilityChanges?.({ embeddable: api }, (isCompatible) => { + const compatibilitySubscription = editPanelAction + ?.getCompatibilityChangesSubject?.(context) + ?.pipe( + switchMap(async () => { + return await editPanelAction.isCompatible(context); + }) + ) + .subscribe(async (isCompatible) => { if (!canceled) setIsEditable(isCompatible); - }) - ); + }); + subscription.add(compatibilitySubscription); })(); return () => { diff --git a/src/platform/plugins/shared/controls/public/actions/clear_control_action.test.tsx b/src/platform/plugins/shared/controls/public/actions/clear_control_action.test.tsx index 19b182ecb6d62..4059e83a2a754 100644 --- a/src/platform/plugins/shared/controls/public/actions/clear_control_action.test.tsx +++ b/src/platform/plugins/shared/controls/public/actions/clear_control_action.test.tsx @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, take } from 'rxjs'; import { getMockedControlGroupApi } from '../controls/mocks/control_mocks'; import { ClearControlAction } from './clear_control_action'; @@ -46,13 +46,12 @@ describe('ClearControlAction', () => { }).rejects.toThrow(Error); }); - test('should call onChange when isCompatible changes', () => { - const onChange = jest.fn(); - + test('should call onChange when isCompatible changes', (done) => { + const subject = clearControlAction.getCompatibilityChangesSubject({ embeddable: controlApi }); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); hasSelections$.next(true); - clearControlAction.subscribeToCompatibilityChanges({ embeddable: controlApi }, onChange); - - expect(onChange).toHaveBeenCalledWith(true, clearControlAction); }); describe('Clear control button compatibility', () => { diff --git a/src/platform/plugins/shared/controls/public/actions/clear_control_action.tsx b/src/platform/plugins/shared/controls/public/actions/clear_control_action.tsx index f435f7e885c5b..6440d7093d5a0 100644 --- a/src/platform/plugins/shared/controls/public/actions/clear_control_action.tsx +++ b/src/platform/plugins/shared/controls/public/actions/clear_control_action.tsx @@ -28,6 +28,7 @@ import { type Action, } from '@kbn/ui-actions-plugin/public'; import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers'; +import { map } from 'rxjs'; import { CONTROL_GROUP_TYPE } from '../../common'; import { CanClearSelections, isClearableControl } from '../types'; @@ -89,15 +90,10 @@ export class ClearControlAction return isClearableControl(embeddable); } - public subscribeToCompatibilityChanges( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: ClearControlAction) => void - ) { - if (!isClearableControl(embeddable)) return; - - return embeddable.hasSelections$.subscribe((selection) => { - onChange(Boolean(selection), this); - }); + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { + return isClearableControl(embeddable) + ? embeddable.hasSelections$.pipe(map(() => undefined)) + : undefined; } public async isCompatible({ embeddable }: EmbeddableApiContext) { diff --git a/src/platform/plugins/shared/controls/public/control_group/components/floating_actions.tsx b/src/platform/plugins/shared/controls/public/control_group/components/floating_actions.tsx index b6c51619eda0e..b17bc8e0bc056 100644 --- a/src/platform/plugins/shared/controls/public/control_group/components/floating_actions.tsx +++ b/src/platform/plugins/shared/controls/public/control_group/components/floating_actions.tsx @@ -10,7 +10,7 @@ import classNames from 'classnames'; import React, { FC, ReactElement, useEffect, useState } from 'react'; import { v4 } from 'uuid'; -import { Subscription } from 'rxjs'; +import { Subscription, switchMap } from 'rxjs'; import { type ViewMode } from '@kbn/embeddable-plugin/public'; import { apiHasUniqueId } from '@kbn/presentation-publishing'; @@ -96,9 +96,17 @@ export const FloatingActions: FC = ({ if (canceled) return; for (const action of frequentlyChangingActions) { - subscriptions.add( - action.subscribeToCompatibilityChanges(context, handleActionCompatibilityChange) - ); + const compatibilitySubscription = action + .getCompatibilityChangesSubject(context) + ?.pipe( + switchMap(async () => { + return await action.isCompatible(context); + }) + ) + .subscribe(async (isCompatible) => { + handleActionCompatibilityChange(isCompatible, action); + }); + subscriptions.add(compatibilitySubscription); } })(); diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.test.tsx b/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.test.tsx index a2806a641db6a..36b0efa22fa6e 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.test.tsx +++ b/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.test.tsx @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, take } from 'rxjs'; import { ExpandPanelActionApi, ExpandPanelAction } from './expand_panel_action'; describe('Expand panel action', () => { @@ -40,11 +40,12 @@ describe('Expand panel action', () => { expect(await action.isCompatible(emptyContext)).toBe(false); }); - it('calls onChange when expandedPanelId changes', async () => { - const onChange = jest.fn(); - action.subscribeToCompatibilityChanges(context, onChange); + it('getCompatibilityChangesSubject emits when expandedPanelId changes', (done) => { + const subject = action.getCompatibilityChangesSubject(context); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); expandedPanelId$.next('superPanelId'); - expect(onChange).toHaveBeenCalledWith(true, action); }); it('returns the correct icon based on expanded panel id', async () => { diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.tsx b/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.tsx index a1d915deec22b..e42d3c7478f85 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.tsx +++ b/src/platform/plugins/shared/dashboard/public/dashboard_actions/expand_panel_action.tsx @@ -16,7 +16,7 @@ import { HasUniqueId, } from '@kbn/presentation-publishing'; import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { skip } from 'rxjs'; +import { map, skip } from 'rxjs'; import { dashboardExpandPanelActionStrings } from './_dashboard_actions_strings'; import { ACTION_EXPAND_PANEL, DASHBOARD_ACTION_GROUP } from './constants'; @@ -52,14 +52,13 @@ export class ExpandPanelAction implements Action { return apiHasParentApi(embeddable) && apiCanExpandPanels(embeddable.parentApi); } - public subscribeToCompatibilityChanges( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: ExpandPanelAction) => void - ) { - if (!isApiCompatible(embeddable)) return; - return embeddable.parentApi.expandedPanelId$.pipe(skip(1)).subscribe(() => { - onChange(isApiCompatible(embeddable), this); - }); + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { + return isApiCompatible(embeddable) + ? embeddable.parentApi.expandedPanelId$.pipe( + skip(1), + map(() => undefined) + ) + : undefined; } public async execute({ embeddable }: EmbeddableApiContext) { diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.test.tsx b/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.test.tsx index e639168b00c7f..e7b5eb4874dc7 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.test.tsx +++ b/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.test.tsx @@ -9,7 +9,7 @@ import { Filter, FilterStateStore, type AggregateQuery, type Query } from '@kbn/es-query'; -import { BehaviorSubject } from 'rxjs'; +import { BehaviorSubject, take } from 'rxjs'; import { FiltersNotificationAction, FiltersNotificationActionApi, @@ -77,17 +77,19 @@ describe('filters notification action', () => { expect(await action.isCompatible(context)).toBe(true); }); - it('calls onChange when filters change', async () => { - const onChange = jest.fn(); - action.subscribeToCompatibilityChanges(context, onChange); + it('getCompatibilityChangesSubject emits when filters change', (done) => { + const subject = action.getCompatibilityChangesSubject(context); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); updateFilters([getMockPhraseFilter('SuperField', 'SuperValue')]); - expect(onChange).toHaveBeenCalledWith(true, action); }); - it('calls onChange when query changes', async () => { - const onChange = jest.fn(); - action.subscribeToCompatibilityChanges(context, onChange); + it('getCompatibilityChangesSubject emits when query changes', (done) => { + const subject = action.getCompatibilityChangesSubject(context); + subject?.pipe(take(1)).subscribe(() => { + done(); + }); updateQuery({ esql: 'FROM test_dataview' } as AggregateQuery); - expect(onChange).toHaveBeenCalledWith(true, action); }); }); diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.tsx b/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.tsx index fe19b68ff7a08..cfac51e5489c8 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.tsx +++ b/src/platform/plugins/shared/dashboard/public/dashboard_actions/filters_notification_action.tsx @@ -8,7 +8,7 @@ */ import React from 'react'; -import { merge } from 'rxjs'; +import { map, merge } from 'rxjs'; import { isOfAggregateQueryType, isOfQueryType } from '@kbn/es-query'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; @@ -87,14 +87,11 @@ export class FiltersNotificationAction implements Action { return apiPublishesPartialUnifiedSearch(embeddable); } - public subscribeToCompatibilityChanges( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: FiltersNotificationAction) => void - ) { + public getCompatibilityChangesSubject({ embeddable }: EmbeddableApiContext) { if (!isApiCompatible(embeddable)) return; return merge( ...[embeddable.query$, embeddable.filters$].filter((value) => Boolean(value)) - ).subscribe(() => onChange(compatibilityCheck(embeddable), this)); + ).pipe(map(() => undefined)); } public execute = async () => {}; diff --git a/src/platform/plugins/shared/ui_actions/public/actions/action.ts b/src/platform/plugins/shared/ui_actions/public/actions/action.ts index a4e2b1e8e8548..ebde9b5dd22b0 100644 --- a/src/platform/plugins/shared/ui_actions/public/actions/action.ts +++ b/src/platform/plugins/shared/ui_actions/public/actions/action.ts @@ -9,7 +9,7 @@ import type { Presentable } from '@kbn/ui-actions-browser/src/types'; import type { Trigger } from '@kbn/ui-actions-browser/src/triggers'; -import { Subscription } from 'rxjs'; +import { Observable } from 'rxjs'; /** * During action execution we can provide additional information, @@ -41,7 +41,7 @@ export interface ActionMenuItemProps { } export type FrequentCompatibilityChangeAction = Action & - Required, 'subscribeToCompatibilityChanges' | 'couldBecomeCompatible'>>; + Required, 'getCompatibilityChangesSubject' | 'couldBecomeCompatible'>>; export interface Action extends Partial>> { @@ -98,13 +98,9 @@ export interface Action shouldAutoExecute?(context: ActionExecutionContext): Promise; /** - * Allows this action to call a method when its compatibility changes. - * @returns a subscription that can be used to unsubscribe from the changes. + * @returns an Observable that emits when this action's compatibility changes. */ - subscribeToCompatibilityChanges?: ( - context: Context, - onChange: (isCompatible: boolean, action: Action) => void - ) => Subscription | undefined; + getCompatibilityChangesSubject?: (context: Context) => Observable | undefined; /** * Determines if action could become compatible given the context. If present, @@ -179,13 +175,9 @@ export interface ActionDefinition showNotification?: boolean; /** - * Allows this action to call a method when its compatibility changes. - * @returns a subscription that can be used to unsubscribe from the changes. + * @returns an Observable that emits when this action's compatibility should be recalculated. */ - subscribeToCompatibilityChanges?: ( - context: Context, - onChange: (isCompatible: boolean, action: Action) => void - ) => Subscription | undefined; + getCompatibilityChangesSubject?: (context: Context) => Observable | undefined; /** * Determines if action could become compatible given the context. If present, diff --git a/src/platform/plugins/shared/ui_actions/public/actions/action_internal.ts b/src/platform/plugins/shared/ui_actions/public/actions/action_internal.ts index 6f979849bdc41..313ac79e1b80e 100644 --- a/src/platform/plugins/shared/ui_actions/public/actions/action_internal.ts +++ b/src/platform/plugins/shared/ui_actions/public/actions/action_internal.ts @@ -27,7 +27,7 @@ export class ActionInternal public readonly showNotification?: boolean; public readonly disabled?: boolean; - public readonly subscribeToCompatibilityChanges?: Action['subscribeToCompatibilityChanges']; + public readonly getCompatibilityChangesSubject?: Action['getCompatibilityChangesSubject']; public readonly couldBecomeCompatible?: Action['couldBecomeCompatible']; public errorLogged?: boolean; @@ -41,8 +41,8 @@ export class ActionInternal this.disabled = this.definition.disabled; this.errorLogged = false; - if (this.definition.subscribeToCompatibilityChanges) { - this.subscribeToCompatibilityChanges = definition.subscribeToCompatibilityChanges; + if (this.definition.getCompatibilityChangesSubject) { + this.getCompatibilityChangesSubject = definition.getCompatibilityChangesSubject; } if (this.definition.couldBecomeCompatible) { this.couldBecomeCompatible = definition.couldBecomeCompatible; diff --git a/src/platform/plugins/shared/ui_actions/public/service/ui_actions_service.ts b/src/platform/plugins/shared/ui_actions/public/service/ui_actions_service.ts index 581be20979cb5..a5c51765c2b3a 100644 --- a/src/platform/plugins/shared/ui_actions/public/service/ui_actions_service.ts +++ b/src/platform/plugins/shared/ui_actions/public/service/ui_actions_service.ts @@ -222,7 +222,7 @@ export class UiActionsService { ): Promise => { return (await this.getTriggerActions(triggerId)).filter((action) => { return ( - Boolean(action.subscribeToCompatibilityChanges) && + Boolean(action.getCompatibilityChangesSubject) && action.couldBecomeCompatible?.({ ...context, trigger: this.getTrigger(triggerId), diff --git a/x-pack/platform/plugins/shared/lens/public/trigger_actions/open_in_discover_action.ts b/x-pack/platform/plugins/shared/lens/public/trigger_actions/open_in_discover_action.ts index fa67aa74f9de3..15ee562711320 100644 --- a/x-pack/platform/plugins/shared/lens/public/trigger_actions/open_in_discover_action.ts +++ b/x-pack/platform/plugins/shared/lens/public/trigger_actions/open_in_discover_action.ts @@ -6,9 +6,10 @@ */ import { i18n } from '@kbn/i18n'; -import { Action, createAction, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; +import { createAction, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import type { DataViewsService } from '@kbn/data-views-plugin/public'; +import { map } from 'rxjs'; import type { DiscoverAppLocator } from './open_in_discover_helpers'; import { LensApi } from '../react_embeddable/types'; @@ -53,15 +54,9 @@ export const createOpenInDiscoverAction = ( throw new IncompatibleActionError(); return hasDiscoverAccess && Boolean((embeddable as LensApi).canViewUnderlyingData$); }, - subscribeToCompatibilityChanges: ( - { embeddable }: EmbeddableApiContext, - onChange: (isCompatible: boolean, action: Action) => void - ) => { - if (!typeof (embeddable as LensApi).canViewUnderlyingData$) - throw new IncompatibleActionError(); - return (embeddable as LensApi).canViewUnderlyingData$.subscribe((canViewUnderlyingData) => { - onChange(canViewUnderlyingData, actionDefinition); - }); + getCompatibilityChangesSubject: ({ embeddable }: EmbeddableApiContext) => { + if (!typeof (embeddable as LensApi).canViewUnderlyingData$) return; + return (embeddable as LensApi).canViewUnderlyingData$.pipe(map(() => undefined)); }, execute: async (context: EmbeddableApiContext) => { const { execute } = await getDiscoverHelpersAsync(); From 60d0a229515dcfdda51131ff4b6e44455f775575 Mon Sep 17 00:00:00 2001 From: seanrathier Date: Thu, 20 Feb 2025 18:25:23 -0500 Subject: [PATCH 20/23] [8.x] Remove setup_access from gcp package policy (#209126) (#211957) # Backport This will backport the following commits from `main` to `8.x`: - [Remove setup_access from gcp package policy (#209126)](https://github.com/elastic/kibana/pull/209126) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) Co-authored-by: Maxim Kholod --- .../gcp_credential_form.tsx | 19 +++++-------------- .../policy_template_form.test.tsx | 9 --------- .../components/fleet_extensions/utils.test.ts | 3 --- .../components/fleet_extensions/utils.ts | 14 +------------- 4 files changed, 6 insertions(+), 39 deletions(-) diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx index e0e0690cf7edf..5074af8b5a2a7 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx +++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/gcp_credentials_form/gcp_credential_form.tsx @@ -338,17 +338,16 @@ export const getInputVarsFields = (input: NewPackagePolicyInput, fields: GcpFiel }); const getSetupFormatFromInput = ( - input: Extract< - NewPackagePolicyPostureInput, - { type: 'cloudbeat/cis_aws' | 'cloudbeat/cis_eks' | 'cloudbeat/cis_gcp' } - > + input: Extract ): SetupFormatGCP => { - const credentialsType = input.streams[0].vars?.setup_access?.value; + const credentialsType = getGcpCredentialsType(input); + // Google Cloud shell is the default value if (!credentialsType) { return GCP_SETUP_ACCESS.CLOUD_SHELL; } - if (credentialsType !== GCP_SETUP_ACCESS.CLOUD_SHELL) { + + if (credentialsType !== GCP_CREDENTIALS_TYPE.CREDENTIALS_NONE) { return GCP_SETUP_ACCESS.MANUAL; } @@ -474,10 +473,6 @@ export const GcpCredentialsForm = ({ updatePolicy( getPosturePolicy(newPolicy, input.type, { - setup_access: { - value: GCP_SETUP_ACCESS.CLOUD_SHELL, - type: 'text', - }, 'gcp.credentials.type': { value: GCP_CREDENTIALS_TYPE.CREDENTIALS_NONE, type: 'text', @@ -490,10 +485,6 @@ export const GcpCredentialsForm = ({ } else { updatePolicy( getPosturePolicy(newPolicy, input.type, { - setup_access: { - value: GCP_SETUP_ACCESS.MANUAL, - type: 'text', - }, 'gcp.credentials.type': { // Restoring last manual credentials type value: lastCredentialsType.current || GCP_CREDENTIALS_TYPE.CREDENTIALS_FILE, diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx index 676d75b4a9088..64019ad2690c6 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx +++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.test.tsx @@ -1169,7 +1169,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { credentials_type: { value: 'credentials-file' }, - setup_access: { value: 'manual' }, }); const { getByText } = render( @@ -1191,7 +1190,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { credentials_type: { value: 'credentials-file' }, - setup_access: { value: 'manual' }, }); const { getByText } = render( @@ -1208,7 +1206,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.account_type': { value: GCP_ORGANIZATION_ACCOUNT }, - setup_access: { value: 'google_cloud_shell' }, }); const { getByTestId } = render( @@ -1228,7 +1225,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.credentials.type': { value: 'credentials-file' }, - setup_access: { value: 'manual' }, }); const { getByLabelText, getByRole } = render( @@ -1247,7 +1243,6 @@ describe('', () => { policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.project_id': { value: 'a' }, 'gcp.credentials.type': { value: 'credentials-file' }, - setup_access: { value: 'manual' }, }); const { getByTestId } = render( @@ -1289,7 +1284,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.account_type': { value: GCP_ORGANIZATION_ACCOUNT }, - setup_access: { value: 'google_cloud_shell' }, }); const { getByLabelText, getByTestId } = render( @@ -1305,7 +1299,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.account_type': { value: GCP_ORGANIZATION_ACCOUNT }, - setup_access: { value: 'manual' }, }); const { getByLabelText, getByTestId } = render( @@ -1321,7 +1314,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.account_type': { value: GCP_SINGLE_ACCOUNT }, - setup_access: { value: 'google_cloud_shell' }, }); const { queryByLabelText, queryByTestId } = render( @@ -1337,7 +1329,6 @@ describe('', () => { let policy = getMockPolicyGCP(); policy = getPosturePolicy(policy, CLOUDBEAT_GCP, { 'gcp.account_type': { value: GCP_ORGANIZATION_ACCOUNT }, - setup_access: { value: 'manual' }, }); const { getByTestId } = render( diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts index 13bb5398de44c..4d25816b4e149 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts +++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.test.ts @@ -446,7 +446,6 @@ describe('getDefaultGcpHiddenVars', () => { expect(result).toMatchObject({ 'gcp.credentials.type': { value: 'credentials-json', type: 'text' }, - setup_access: { value: 'manual', type: 'text' }, }); }); @@ -456,7 +455,6 @@ describe('getDefaultGcpHiddenVars', () => { expect(result).toMatchObject({ 'gcp.credentials.type': { value: 'credentials-none', type: 'text' }, - setup_access: { value: 'google_cloud_shell', type: 'text' }, }); }); @@ -483,7 +481,6 @@ describe('getDefaultGcpHiddenVars', () => { expect(result).toMatchObject({ 'gcp.credentials.type': { value: 'credentials-file', type: 'text' }, - setup_access: { value: 'manual', type: 'text' }, }); }); }); diff --git a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts index 0a0bdddf731a4..e384a7fc49d64 100644 --- a/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts +++ b/x-pack/solutions/security/plugins/cloud_security_posture/public/components/fleet_extensions/utils.ts @@ -43,7 +43,7 @@ import { DEFAULT_AWS_CREDENTIALS_TYPE, DEFAULT_MANUAL_AWS_CREDENTIALS_TYPE, } from './aws_credentials_form/get_aws_credentials_form_options'; -import { GCP_CREDENTIALS_TYPE, GCP_SETUP_ACCESS } from './gcp_credentials_form/gcp_credential_form'; +import { GCP_CREDENTIALS_TYPE } from './gcp_credentials_form/gcp_credential_form'; import { AZURE_CREDENTIALS_TYPE } from './azure_credentials_form/azure_credentials_form'; // Posture policies only support the default namespace @@ -257,10 +257,6 @@ export const getDefaultGcpHiddenVars = ( value: GCP_CREDENTIALS_TYPE.CREDENTIALS_JSON, type: 'text', }, - setup_access: { - value: GCP_SETUP_ACCESS.MANUAL, - type: 'text', - }, }; } @@ -271,10 +267,6 @@ export const getDefaultGcpHiddenVars = ( value: GCP_CREDENTIALS_TYPE.CREDENTIALS_NONE, type: 'text', }, - setup_access: { - value: GCP_SETUP_ACCESS.CLOUD_SHELL, - type: 'text', - }, }; } @@ -283,10 +275,6 @@ export const getDefaultGcpHiddenVars = ( value: GCP_CREDENTIALS_TYPE.CREDENTIALS_FILE, type: 'text', }, - setup_access: { - value: GCP_SETUP_ACCESS.MANUAL, - type: 'text', - }, }; }; From f1f557f22de44522e4b89ce0407928a6171f882a Mon Sep 17 00:00:00 2001 From: Andrew Macri Date: Thu, 20 Feb 2025 18:41:44 -0500 Subject: [PATCH 21/23] [8.x] [Security Solution] [Attack discovery] Removes Alerts filtering feature flag (#209851) (#211985) # Backport This will backport the following commits from `main` to `8.x`: - [[Security Solution] [Attack discovery] Removes Alerts filtering feature flag (#209851)](https://github.com/elastic/kibana/pull/209851) ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) --- .../impl/capabilities/index.ts | 1 - .../get_capabilities_route.gen.ts | 1 - .../get_capabilities_route.schema.yaml | 3 - .../translations/translations/fr-FR.json | 10 -- .../translations/translations/ja-JP.json | 10 -- .../translations/translations/zh-CN.json | 10 -- .../common/experimental_features.ts | 5 - .../pages/header/index.test.tsx | 17 +- .../attack_discovery/pages/header/index.tsx | 32 +--- .../alerts_settings/index.test.tsx | 39 ----- .../settings_modal/alerts_settings/index.tsx | 78 --------- .../settings_modal/footer/index.test.tsx | 42 ----- .../header/settings_modal/footer/index.tsx | 57 ------- .../header/settings_modal/index.test.tsx | 72 -------- .../pages/header/settings_modal/index.tsx | 158 ------------------ .../is_tour_enabled/index.test.ts | 76 --------- .../settings_modal/is_tour_enabled/index.ts | 18 -- .../header/settings_modal/translations.ts | 81 --------- .../attack_discovery/pages/index.test.tsx | 43 +---- .../public/attack_discovery/pages/index.tsx | 29 +--- .../loading_messages/index.test.tsx | 42 +---- .../loading_messages/index.tsx | 18 +- .../pages/settings_flyout/footer/index.tsx | 2 +- .../settings_flyout/footer/translations.ts | 29 ++++ .../security_solution/server/plugin.ts | 1 - 25 files changed, 58 insertions(+), 816 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.test.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/footer/index.test.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/footer/index.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/index.test.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/index.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/is_tour_enabled/index.test.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/is_tour_enabled/index.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/translations.ts create mode 100644 x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/settings_flyout/footer/translations.ts diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts index adf474a991dbe..9de1be6adc837 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/capabilities/index.ts @@ -20,7 +20,6 @@ export type AssistantFeatureKey = keyof AssistantFeatures; */ export const defaultAssistantFeatures = Object.freeze({ assistantModelEvaluation: false, - attackDiscoveryAlertFiltering: false, defendInsights: false, contentReferencesEnabled: false, }); diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts index 78ee4a6c3e605..9ff0c2ebf59e7 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.gen.ts @@ -19,7 +19,6 @@ import { z } from '@kbn/zod'; export type GetCapabilitiesResponse = z.infer; export const GetCapabilitiesResponse = z.object({ assistantModelEvaluation: z.boolean(), - attackDiscoveryAlertFiltering: z.boolean(), contentReferencesEnabled: z.boolean(), defendInsights: z.boolean(), }); diff --git a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml index 684ff6f020793..2dc79cfe3d116 100644 --- a/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml +++ b/x-pack/platform/packages/shared/kbn-elastic-assistant-common/impl/schemas/capabilities/get_capabilities_route.schema.yaml @@ -22,15 +22,12 @@ paths: properties: assistantModelEvaluation: type: boolean - attackDiscoveryAlertFiltering: - type: boolean contentReferencesEnabled: type: boolean defendInsights: type: boolean required: - assistantModelEvaluation - - attackDiscoveryAlertFiltering - contentReferencesEnabled - defendInsights '400': diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 6655ed8407ebb..dfb1b22e878d1 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -36917,16 +36917,6 @@ "xpack.securitySolution.attackDiscovery.pages.pageTitle.statusConnectors": "Vous avez {newDiscoveriesCount} {newDiscoveriesCount, plural, =1 {nouvelle découverte} other {nouvelles découvertes}} à travers {newConnectorResultsCount} {newConnectorResultsCount, plural, =1 {connecteur} other {connecteurs}} à examiner.", "xpack.securitySolution.attackDiscovery.pages.welcome.firstSetUpLabel": "Tout d’abord, configurez un connecteur d’IA générative.", "xpack.securitySolution.attackDiscovery.pages.welcome.welcomeToAttackDiscoveryLabel": "Bienvenue sur Attack discovery !", - "xpack.securitySolution.attackDiscovery.settingsModal.alertsLabel": "Alertes", - "xpack.securitySolution.attackDiscovery.settingsModal.attackDiscoverySendsMoreAlertsTourText": "La découverte d'attaques envoie davantage d'alertes en tant que contexte.", - "xpack.securitySolution.attackDiscovery.settingsModal.cancelButton": "Annuler", - "xpack.securitySolution.attackDiscovery.settingsModal.configureYourSettingsHereTourText": "Configurez vos paramètres ici.", - "xpack.securitySolution.attackDiscovery.settingsModal.latestAndRiskiestOpenAlertsLabel": "Envoyez à Attack discovery des informations sur vos {alertsCount} alertes ouvertes ou confirmées les plus récentes et les plus risquées.", - "xpack.securitySolution.attackDiscovery.settingsModal.resetLabel": "Réinitialiser", - "xpack.securitySolution.attackDiscovery.settingsModal.saveButton": "Enregistrer", - "xpack.securitySolution.attackDiscovery.settingsModal.settingsLabel": "Paramètres", - "xpack.securitySolution.attackDiscovery.settingsModal.tourSubtitle": "Améliorations récentes de Attack Discovery", - "xpack.securitySolution.attackDiscovery.settingsModal.tourTitle": "Envoyer plus d'alertes", "xpack.securitySolution.attackDiscovery.showAnonymizedLabel": "Afficher les anonymisés", "xpack.securitySolution.attackDiscovery.showRealValuesLabel": "Afficher les valeurs réelles", "xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} {alertsCount, plural, =1 {alerte} other {alertes}}", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 72e94ddc729af..7858228f01626 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -36775,16 +36775,6 @@ "xpack.securitySolution.attackDiscovery.pages.pageTitle.statusConnectors": "{newConnectorResultsCount} {newConnectorResultsCount, plural, other {コネクター}}全体で、表示する{newDiscoveriesCount}件の新しい{newDiscoveriesCount, plural, other {検出}}があります。", "xpack.securitySolution.attackDiscovery.pages.welcome.firstSetUpLabel": "まず、生成AIコネクターを設定します。", "xpack.securitySolution.attackDiscovery.pages.welcome.welcomeToAttackDiscoveryLabel": "Attack Discoveryへようこそ!", - "xpack.securitySolution.attackDiscovery.settingsModal.alertsLabel": "アラート", - "xpack.securitySolution.attackDiscovery.settingsModal.attackDiscoverySendsMoreAlertsTourText": "Attack discoveryはその他のアラートをコンテキストとして送信します。", - "xpack.securitySolution.attackDiscovery.settingsModal.cancelButton": "キャンセル", - "xpack.securitySolution.attackDiscovery.settingsModal.configureYourSettingsHereTourText": "ここで設定を構成します。", - "xpack.securitySolution.attackDiscovery.settingsModal.latestAndRiskiestOpenAlertsLabel": "{alertsCount}件の最新の最もリスクが高い未解決または確認済みのアラートに関するAttack discovery情報を送信します。", - "xpack.securitySolution.attackDiscovery.settingsModal.resetLabel": "リセット", - "xpack.securitySolution.attackDiscovery.settingsModal.saveButton": "保存", - "xpack.securitySolution.attackDiscovery.settingsModal.settingsLabel": "設定", - "xpack.securitySolution.attackDiscovery.settingsModal.tourSubtitle": "最近のAttack discoveryの改良", - "xpack.securitySolution.attackDiscovery.settingsModal.tourTitle": "その他のアラートを送信", "xpack.securitySolution.attackDiscovery.showAnonymizedLabel": "匿名化して表示", "xpack.securitySolution.attackDiscovery.showRealValuesLabel": "実際の値を表示", "xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} {alertsCount, plural, other {件のアラート}}", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index 86757243ecddb..80fd1b8d3f8ab 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -36869,16 +36869,6 @@ "xpack.securitySolution.attackDiscovery.pages.pageTitle.statusConnectors": "您具有 {newDiscoveriesCount} 个新{newDiscoveriesCount, plural, other {发现}}可跨 {newConnectorResultsCount} 个{newConnectorResultsCount, plural, other {连接器}}查看。", "xpack.securitySolution.attackDiscovery.pages.welcome.firstSetUpLabel": "首先设置生成式 AI 连接器。", "xpack.securitySolution.attackDiscovery.pages.welcome.welcomeToAttackDiscoveryLabel": "欢迎使用 Attack Discovery!", - "xpack.securitySolution.attackDiscovery.settingsModal.alertsLabel": "告警", - "xpack.securitySolution.attackDiscovery.settingsModal.attackDiscoverySendsMoreAlertsTourText": "Attack Discovery 会发送更多告警作为上下文。", - "xpack.securitySolution.attackDiscovery.settingsModal.cancelButton": "取消", - "xpack.securitySolution.attackDiscovery.settingsModal.configureYourSettingsHereTourText": "在此配置您的设置。", - "xpack.securitySolution.attackDiscovery.settingsModal.latestAndRiskiestOpenAlertsLabel": "发送有关 {alertsCount} 个最新和风险最高的未决或已确认告警的 Attack Discovery 信息。", - "xpack.securitySolution.attackDiscovery.settingsModal.resetLabel": "重置", - "xpack.securitySolution.attackDiscovery.settingsModal.saveButton": "保存", - "xpack.securitySolution.attackDiscovery.settingsModal.settingsLabel": "设置", - "xpack.securitySolution.attackDiscovery.settingsModal.tourSubtitle": "最近的 Attack Discovery 改进", - "xpack.securitySolution.attackDiscovery.settingsModal.tourTitle": "发送更多告警", "xpack.securitySolution.attackDiscovery.showAnonymizedLabel": "显示已匿名处理项", "xpack.securitySolution.attackDiscovery.showRealValuesLabel": "显示实际值", "xpack.securitySolution.attackDiscovery.summaryCount.alertsLabel": "{alertsCount} 个{alertsCount, plural, other {告警}}", diff --git a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts index efc30c0e3d126..f4c4228a098ca 100644 --- a/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/solutions/security/plugins/security_solution/common/experimental_features.ts @@ -114,11 +114,6 @@ export const allowedExperimentalValues = Object.freeze({ */ assistantModelEvaluation: false, - /** - * Enables filtering of Attack Discovery alerts in a flyout - */ - attackDiscoveryAlertFiltering: false, - /** * Enables content references (citations) in the AI Assistant */ diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.test.tsx index e48027812f1ec..2124c38722ec0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.test.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.test.tsx @@ -6,7 +6,6 @@ */ import { DEFAULT_ATTACK_DISCOVERY_MAX_ALERTS } from '@kbn/elastic-assistant'; -import { defaultAssistantFeatures } from '@kbn/elastic-assistant-common'; import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import React from 'react'; @@ -16,18 +15,6 @@ import { Header } from '.'; jest.mock('../../../assistant/use_assistant_availability'); -jest.mock('@kbn/elastic-assistant-common', () => { - const original = jest.requireActual('@kbn/elastic-assistant-common'); - - return { - ...original, - defaultAssistantFeatures: { - ...original.defaultAssistantFeatures, - attackDiscoveryAlertFiltering: jest.mocked(false), // <-- feature flag is off by default - }, - }; -}); - const defaultProps = { stats: null, connectorId: 'testConnectorId', @@ -50,7 +37,6 @@ describe('Actions', () => { }); jest.clearAllMocks(); - (defaultAssistantFeatures.attackDiscoveryAlertFiltering as jest.Mocked) = false; // reset feature flag to off }); it('renders the connector selector', () => { @@ -139,8 +125,7 @@ describe('Actions', () => { expect(generate).toBeDisabled(); }); - it('invokes openFlyout when the settings button is clicked, when the attackDiscoveryAlertFiltering feature flag is on', async () => { - (defaultAssistantFeatures.attackDiscoveryAlertFiltering as jest.Mocked) = true; + it('invokes openFlyout when the settings button is clicked', async () => { const openFlyout = jest.fn(); render( diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.tsx index 46019520401e5..8b299eaab7025 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/index.tsx @@ -15,12 +15,11 @@ import { useEuiTheme, } from '@elastic/eui'; import { css } from '@emotion/react'; -import { ConnectorSelectorInline, useAssistantContext } from '@kbn/elastic-assistant'; +import { ConnectorSelectorInline } from '@kbn/elastic-assistant'; import type { AttackDiscoveryStats } from '@kbn/elastic-assistant-common'; import { noop } from 'lodash/fp'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { SettingsModal } from './settings_modal'; import { StatusBell } from './status_bell'; import * as i18n from './translations'; @@ -51,10 +50,6 @@ const HeaderComponent: React.FC = ({ setLocalStorageAttackDiscoveryMaxAlerts, stats, }) => { - const { - assistantFeatures: { attackDiscoveryAlertFiltering }, - } = useAssistantContext(); - const { euiTheme } = useEuiTheme(); const disabled = connectorId == null; @@ -120,24 +115,15 @@ const HeaderComponent: React.FC = ({ `} grow={false} > - {attackDiscoveryAlertFiltering ? ( - - - - ) : ( - + - )} + diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.test.tsx deleted file mode 100644 index 958c9094fabf3..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { render, screen, fireEvent } from '@testing-library/react'; -import React from 'react'; - -import { AlertsSettings, MAX_ALERTS } from '.'; - -const maxAlerts = '150'; - -const setMaxAlerts = jest.fn(); - -describe('AlertsSettings', () => { - it('calls setMaxAlerts when the alerts range changes', () => { - render(); - - fireEvent.click(screen.getByText(`${MAX_ALERTS}`)); - - expect(setMaxAlerts).toHaveBeenCalledWith(`${MAX_ALERTS}`); - }); - - it('displays the correct maxAlerts value', () => { - render(); - - expect(screen.getByTestId('alertsRange')).toHaveValue(maxAlerts); - }); - - it('displays the expected text for anonymization settings', () => { - render(); - - expect(screen.getByTestId('latestAndRiskiest')).toHaveTextContent( - 'Send Attack discovery information about your 150 newest and riskiest open or acknowledged alerts.' - ); - }); -}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.tsx deleted file mode 100644 index 7741d3214ee36..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/alerts_settings/index.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { SingleRangeChangeEvent } from '@kbn/elastic-assistant'; -import { EuiFlexGroup, EuiFlexItem, EuiForm, EuiFormRow, EuiSpacer, EuiText } from '@elastic/eui'; -import { - AlertsRange, - SELECT_FEWER_ALERTS, - YOUR_ANONYMIZATION_SETTINGS, -} from '@kbn/elastic-assistant'; -import React, { useCallback } from 'react'; - -import * as i18n from '../translations'; - -export const MAX_ALERTS = 500; -export const MIN_ALERTS = 50; -export const STEP = 50; - -interface Props { - maxAlerts: string; - setMaxAlerts: React.Dispatch>; -} - -const AlertsSettingsComponent: React.FC = ({ maxAlerts, setMaxAlerts }) => { - const onChangeAlertsRange = useCallback( - (e: SingleRangeChangeEvent) => { - setMaxAlerts(e.currentTarget.value); - }, - [setMaxAlerts] - ); - - return ( - - - - - - - - - - - - {i18n.LATEST_AND_RISKIEST_OPEN_ALERTS(Number(maxAlerts))} - - - - - - - {YOUR_ANONYMIZATION_SETTINGS} - - - - - - {SELECT_FEWER_ALERTS} - - - - - - ); -}; - -AlertsSettingsComponent.displayName = 'AlertsSettings'; - -export const AlertsSettings = React.memo(AlertsSettingsComponent); diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/footer/index.test.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/footer/index.test.tsx deleted file mode 100644 index e487304c41350..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/header/settings_modal/footer/index.test.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { fireEvent, render, screen } from '@testing-library/react'; - -import { Footer } from '.'; - -describe('Footer', () => { - const closeModal = jest.fn(); - const onReset = jest.fn(); - const onSave = jest.fn(); - - beforeEach(() => jest.clearAllMocks()); - - it('calls onReset when the reset button is clicked', () => { - render(