diff --git a/docs/user/alerting/alert-types.asciidoc b/docs/user/alerting/alert-types.asciidoc index 279739e95b52..016ecc316729 100644 --- a/docs/user/alerting/alert-types.asciidoc +++ b/docs/user/alerting/alert-types.asciidoc @@ -130,12 +130,13 @@ image::images/alert-types-es-query-select.png[Choosing an ES query alert type] [float] ==== Defining the conditions -The ES query alert has 4 clauses that define the condition to detect. +The ES query alert has 5 clauses that define the condition to detect. [role="screenshot"] image::images/alert-types-es-query-conditions.png[Four clauses define the condition to detect] Index:: This clause requires an *index or index pattern* and a *time field* that will be used for the *time window*. +Size:: This clause specifies the number of documents to pass to the configured actions when the the threshold condition is met. ES query:: This clause specifies the ES DSL query to execute. The number of documents that match this query will be evaulated against the threshold condition. Aggregations are not supported at this time. Threshold:: This clause defines a threshold value and a comparison operator (`is above`, `is above or equals`, `is below`, `is below or equals`, or `is between`). The number of documents that match the specified query is compared to this threshold. diff --git a/docs/user/alerting/images/alert-types-es-query-conditions.png b/docs/user/alerting/images/alert-types-es-query-conditions.png index ce2bd6a42a4b..3cbba5eb4950 100644 Binary files a/docs/user/alerting/images/alert-types-es-query-conditions.png and b/docs/user/alerting/images/alert-types-es-query-conditions.png differ diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx index 0a9f94f8efae..27ddb28eed77 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.test.tsx @@ -126,6 +126,7 @@ describe('EsQueryAlertTypeExpression', () => { index: ['test-index'], timeField: '@timestamp', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '>', threshold: [0], timeWindowSize: 15, @@ -137,6 +138,7 @@ describe('EsQueryAlertTypeExpression', () => { const errors = { index: [], esQuery: [], + size: [], timeField: [], timeWindowSize: [], }; @@ -169,6 +171,7 @@ describe('EsQueryAlertTypeExpression', () => { test('should render EsQueryAlertTypeExpression with expected components', async () => { const wrapper = await setup(getAlertParams()); expect(wrapper.find('[data-test-subj="indexSelectPopover"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="sizeValueExpression"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="queryJsonEditor"]').exists()).toBeTruthy(); expect(wrapper.find('[data-test-subj="testQuerySuccess"]').exists()).toBeFalsy(); expect(wrapper.find('[data-test-subj="testQueryError"]').exists()).toBeFalsy(); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx index 27f8071564c5..37c64688ec49 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression.tsx @@ -30,6 +30,7 @@ import { COMPARATORS, ThresholdExpression, ForLastExpression, + ValueExpression, AlertTypeParamsExpressionProps, } from '../../../../triggers_actions_ui/public'; import { validateExpression } from './validation'; @@ -45,6 +46,7 @@ const DEFAULT_VALUES = { "match_all" : {} } }`, + SIZE: 100, TIME_WINDOW_SIZE: 5, TIME_WINDOW_UNIT: 'm', THRESHOLD: [1000], @@ -53,6 +55,7 @@ const DEFAULT_VALUES = { const expressionFieldsWithValidation = [ 'index', 'esQuery', + 'size', 'timeField', 'threshold0', 'threshold1', @@ -74,6 +77,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< index, timeField, esQuery, + size, thresholdComparator, threshold, timeWindowSize, @@ -83,6 +87,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< const getDefaultParams = () => ({ ...alertParams, esQuery: esQuery ?? DEFAULT_VALUES.QUERY, + size: size ?? DEFAULT_VALUES.SIZE, timeWindowSize: timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, threshold: threshold ?? DEFAULT_VALUES.THRESHOLD, @@ -214,7 +219,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent<
@@ -234,6 +239,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ...alertParams, index: indices, esQuery: DEFAULT_VALUES.QUERY, + size: DEFAULT_VALUES.SIZE, thresholdComparator: DEFAULT_VALUES.THRESHOLD_COMPARATOR, timeWindowSize: DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: DEFAULT_VALUES.TIME_WINDOW_UNIT, @@ -246,6 +252,19 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< }} onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)} /> + { + setParam('size', updatedValue); + }} + />
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts index a22af7a7bc8a..af34b88ba28c 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/types.ts @@ -17,6 +17,7 @@ export interface EsQueryAlertParams extends AlertTypeParams { index: string[]; timeField?: string; esQuery: string; + size: number; thresholdComparator?: string; threshold: number[]; timeWindowSize: number; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts index 7d604e964fb9..52278b457655 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.test.ts @@ -13,6 +13,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: [], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -25,6 +26,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -37,6 +39,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -49,6 +52,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"aggs\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 1, timeWindowUnit: 's', threshold: [0], @@ -61,6 +65,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [], timeWindowSize: 1, timeWindowUnit: 's', @@ -74,6 +79,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [1], timeWindowSize: 1, timeWindowUnit: 's', @@ -87,6 +93,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = { index: ['test'], esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, threshold: [10, 1], timeWindowSize: 1, timeWindowUnit: 's', @@ -97,4 +104,34 @@ describe('expression params validation', () => { 'Threshold 1 must be > Threshold 0.' ); }); + + test('if size property is < 0 should return proper error message', () => { + const initialParams: EsQueryAlertParams = { + index: ['test'], + esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: -1, + timeWindowSize: 1, + timeWindowUnit: 's', + threshold: [0], + }; + expect(validateExpression(initialParams).errors.size.length).toBeGreaterThan(0); + expect(validateExpression(initialParams).errors.size[0]).toBe( + 'Size must be between 0 and 10,000.' + ); + }); + + test('if size property is > 10000 should return proper error message', () => { + const initialParams: EsQueryAlertParams = { + index: ['test'], + esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n`, + size: 25000, + timeWindowSize: 1, + timeWindowUnit: 's', + threshold: [0], + }; + expect(validateExpression(initialParams).errors.size.length).toBeGreaterThan(0); + expect(validateExpression(initialParams).errors.size[0]).toBe( + 'Size must be between 0 and 10,000.' + ); + }); }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts index 8b402d63ae56..e6449dd4a608 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/validation.ts @@ -10,12 +10,21 @@ import { EsQueryAlertParams } from './types'; import { ValidationResult, builtInComparators } from '../../../../triggers_actions_ui/public'; export const validateExpression = (alertParams: EsQueryAlertParams): ValidationResult => { - const { index, timeField, esQuery, threshold, timeWindowSize, thresholdComparator } = alertParams; + const { + index, + timeField, + esQuery, + size, + threshold, + timeWindowSize, + thresholdComparator, + } = alertParams; const validationResult = { errors: {} }; const errors = { index: new Array(), timeField: new Array(), esQuery: new Array(), + size: new Array(), threshold0: new Array(), threshold1: new Array(), thresholdComparator: new Array(), @@ -94,5 +103,20 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR }) ); } + if (!size) { + errors.size.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSizeText', { + defaultMessage: 'Size is required.', + }) + ); + } + if ((size && size < 0) || size > 10000) { + errors.size.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.invalidSizeRangeText', { + defaultMessage: 'Size must be between 0 and {max, number}.', + values: { max: 10000 }, + }) + ); + } return validationResult; }; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.test.ts index d4b2029c1157..9d4edd83a391 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/action_context.test.ts @@ -14,6 +14,7 @@ describe('ActionContext', () => { index: ['[index]'], timeField: '[timeField]', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '>', @@ -41,6 +42,7 @@ describe('ActionContext', () => { index: ['[index]'], timeField: '[timeField]', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: 'between', diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts index 2049f9f1153d..c38dad513437 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.test.ts @@ -57,6 +57,10 @@ describe('alertType', () => { "description": "The string representation of the ES query.", "name": "esQuery", }, + Object { + "description": "The number of hits to retrieve for each query.", + "name": "size", + }, Object { "description": "An array of values to use as the threshold; 'between' and 'notBetween' require two values, the others require one.", "name": "threshold", @@ -75,6 +79,7 @@ describe('alertType', () => { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '<', @@ -92,6 +97,7 @@ describe('alertType', () => { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: 'between', diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts index 51c1fc4073d6..8fe988d95d72 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type.ts @@ -23,8 +23,6 @@ import { ESSearchHit } from '../../../../../typings/elasticsearch'; export const ES_QUERY_ID = '.es-query'; -const DEFAULT_MAX_HITS_PER_EXECUTION = 1000; - const ActionGroupId = 'query matched'; const ConditionMetAlertInstanceId = 'query matched'; @@ -88,6 +86,13 @@ export function getAlertType( } ); + const actionVariableContextSizeLabel = i18n.translate( + 'xpack.stackAlerts.esQuery.actionVariableContextSizeLabel', + { + defaultMessage: 'The number of hits to retrieve for each query.', + } + ); + const actionVariableContextThresholdLabel = i18n.translate( 'xpack.stackAlerts.esQuery.actionVariableContextThresholdLabel', { @@ -130,6 +135,7 @@ export function getAlertType( params: [ { name: 'index', description: actionVariableContextIndexLabel }, { name: 'esQuery', description: actionVariableContextQueryLabel }, + { name: 'size', description: actionVariableContextSizeLabel }, { name: 'threshold', description: actionVariableContextThresholdLabel }, { name: 'thresholdComparator', description: actionVariableContextThresholdComparatorLabel }, ], @@ -160,7 +166,7 @@ export function getAlertType( } // During each alert execution, we run the configured query, get a hit count - // (hits.total) and retrieve up to DEFAULT_MAX_HITS_PER_EXECUTION hits. We + // (hits.total) and retrieve up to params.size hits. We // evaluate the threshold condition using the value of hits.total. If the threshold // condition is met, the hits are counted toward the query match and we update // the alert state with the timestamp of the latest hit. In the next execution @@ -200,7 +206,7 @@ export function getAlertType( from: dateStart, to: dateEnd, filter, - size: DEFAULT_MAX_HITS_PER_EXECUTION, + size: params.size, sortOrder: 'desc', searchAfterSortId: undefined, timeField: params.timeField, diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts index a1a697446ff6..ab3ca6a2d4c3 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.test.ts @@ -7,12 +7,17 @@ import { TypeOf } from '@kbn/config-schema'; import type { Writable } from '@kbn/utility-types'; -import { EsQueryAlertParamsSchema, EsQueryAlertParams } from './alert_type_params'; +import { + EsQueryAlertParamsSchema, + EsQueryAlertParams, + ES_QUERY_MAX_HITS_PER_EXECUTION, +} from './alert_type_params'; const DefaultParams: Writable> = { index: ['index-name'], timeField: 'time-field', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, timeWindowSize: 5, timeWindowUnit: 'm', thresholdComparator: '>', @@ -99,6 +104,28 @@ describe('alertType Params validate()', () => { ); }); + it('fails for invalid size', async () => { + delete params.size; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: expected value of type [number] but got [undefined]"` + ); + + params.size = 'foo'; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: expected value of type [number] but got [string]"` + ); + + params.size = -1; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: Value must be equal to or greater than [0]."` + ); + + params.size = ES_QUERY_MAX_HITS_PER_EXECUTION + 1; + expect(onValidate()).toThrowErrorMatchingInlineSnapshot( + `"[size]: Value must be equal to or lower than [10000]."` + ); + }); + it('fails for invalid timeWindowSize', async () => { delete params.timeWindowSize; expect(onValidate()).toThrowErrorMatchingInlineSnapshot( diff --git a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts index 24fed92776b5..23f314b52151 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/es_query/alert_type_params.ts @@ -11,6 +11,8 @@ import { ComparatorFnNames } from '../lib'; import { validateTimeWindowUnits } from '../../../../triggers_actions_ui/server'; import { AlertTypeState } from '../../../../alerts/server'; +export const ES_QUERY_MAX_HITS_PER_EXECUTION = 10000; + // alert type parameters export type EsQueryAlertParams = TypeOf; export interface EsQueryAlertState extends AlertTypeState { @@ -21,6 +23,7 @@ export const EsQueryAlertParamsSchemaProperties = { index: schema.arrayOf(schema.string({ minLength: 1 }), { minSize: 1 }), timeField: schema.string({ minLength: 1 }), esQuery: schema.string({ minLength: 1 }), + size: schema.number({ min: 0, max: ES_QUERY_MAX_HITS_PER_EXECUTION }), timeWindowSize: schema.number({ min: 1 }), timeWindowUnit: schema.string({ validate: validateTimeWindowUnits }), threshold: schema.arrayOf(schema.number(), { minSize: 1, maxSize: 2 }), diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts index bfcbba28b4bd..f975375adcb0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/index.ts @@ -10,3 +10,4 @@ export { OfExpression } from './of'; export { GroupByExpression } from './group_by_over'; export { ThresholdExpression } from './threshold'; export { ForLastExpression } from './for_the_last'; +export { ValueExpression } from './value'; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx new file mode 100644 index 000000000000..e9a3dce84e14 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.test.tsx @@ -0,0 +1,136 @@ +/* + * 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 * as React from 'react'; +import { shallow } from 'enzyme'; +import { act } from 'react-dom/test-utils'; +import { ValueExpression } from './value'; +import { mountWithIntl, nextTick } from '@kbn/test/jest'; + +describe('value expression', () => { + it('renders description and value', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="valueFieldTitle"]')).toMatchInlineSnapshot(` + + test + + `); + expect(wrapper.find('[data-test-subj="valueFieldNumberForm"]')).toMatchInlineSnapshot(` + + + + `); + }); + + it('renders errors', () => { + const wrapper = shallow( + + ); + expect(wrapper.find('[data-test-subj="valueFieldNumberForm"]')).toMatchInlineSnapshot(` + + + + `); + }); + + it('renders closed popover initially and opens on click', async () => { + const wrapper = mountWithIntl( + + ); + + expect(wrapper.find('[data-test-subj="valueExpression"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="valueFieldTitle"]').exists()).toBeFalsy(); + expect(wrapper.find('[data-test-subj="valueFieldNumber"]').exists()).toBeFalsy(); + + wrapper.find('[data-test-subj="valueExpression"]').first().simulate('click'); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + expect(wrapper.find('[data-test-subj="valueFieldTitle"]').exists()).toBeTruthy(); + expect(wrapper.find('[data-test-subj="valueFieldNumber"]').exists()).toBeTruthy(); + }); + + it('emits onChangeSelectedValue action when value is updated', async () => { + const onChangeSelectedValue = jest.fn(); + const wrapper = mountWithIntl( + + ); + + wrapper.find('[data-test-subj="valueExpression"]').first().simulate('click'); + await act(async () => { + await nextTick(); + wrapper.update(); + }); + wrapper + .find('input[data-test-subj="valueFieldNumber"]') + .simulate('change', { target: { value: 3000 } }); + expect(onChangeSelectedValue).toHaveBeenCalledWith(3000); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx new file mode 100644 index 000000000000..cdf57136fe4b --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/value.tsx @@ -0,0 +1,102 @@ +/* + * 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, { useState } from 'react'; +import { + EuiExpression, + EuiPopover, + EuiFieldNumber, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, +} from '@elastic/eui'; +import { ClosablePopoverTitle } from './components'; +import { IErrorObject } from '../../types'; + +interface ValueExpressionProps { + description: string; + value: number; + onChangeSelectedValue: (updatedValue: number) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; + display?: 'fullWidth' | 'inline'; + errors: string | string[] | IErrorObject; +} + +export const ValueExpression = ({ + description, + value, + onChangeSelectedValue, + display = 'inline', + popupPosition, + errors, +}: ValueExpressionProps) => { + const [valuePopoverOpen, setValuePopoverOpen] = useState(false); + return ( + { + setValuePopoverOpen(true); + }} + /> + } + isOpen={valuePopoverOpen} + closePopover={() => { + setValuePopoverOpen(false); + }} + ownFocus + display={display === 'fullWidth' ? 'block' : 'inlineBlock'} + anchorPosition={popupPosition ?? 'downLeft'} + repositionOnScroll + > +
+ setValuePopoverOpen(false)} + > + <>{description} + + + + 0 && value !== undefined} + error={errors} + > + 0 && value !== undefined} + onChange={(e: any) => { + onChangeSelectedValue(e.target.value as number); + }} + /> + + + +
+
+ ); +}; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts index 30fd3aea2b2d..777caacd465d 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/builtin_alert_types/es_query/alert.ts @@ -68,6 +68,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'never fire', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '<', threshold: [0], }); @@ -75,6 +76,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'always fire', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + size: 100, thresholdComparator: '>', threshold: [-1], }); @@ -123,6 +125,7 @@ export default function alertTests({ getService }: FtrProviderContext) { await createAlert({ name: 'never fire', esQuery: JSON.stringify(rangeQuery(ES_GROUPS_TO_WRITE * ALERT_INTERVALS_TO_WRITE + 1)), + size: 100, thresholdComparator: '>=', threshold: [0], }); @@ -132,6 +135,7 @@ export default function alertTests({ getService }: FtrProviderContext) { esQuery: JSON.stringify( rangeQuery(Math.floor((ES_GROUPS_TO_WRITE * ALERT_INTERVALS_TO_WRITE) / 2)) ), + size: 100, thresholdComparator: '>=', threshold: [0], }); @@ -173,6 +177,7 @@ export default function alertTests({ getService }: FtrProviderContext) { name: string; timeField?: string; esQuery: string; + size: number; thresholdComparator: string; threshold: number[]; timeWindowSize?: number; @@ -215,6 +220,7 @@ export default function alertTests({ getService }: FtrProviderContext) { index: [ES_TEST_INDEX_NAME], timeField: params.timeField || 'date', esQuery: params.esQuery, + size: params.size, timeWindowSize: params.timeWindowSize || ALERT_INTERVAL_SECONDS * 5, timeWindowUnit: 's', thresholdComparator: params.thresholdComparator,