From 6d7f00d62ca443f99a7e25859f2996201b4d30c7 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 20 Jun 2022 16:44:08 +0200 Subject: [PATCH 01/52] [Alerting][Discover] Add query form type selection for ES query --- .../expression/es_query_expression.test.tsx | 2 + .../expression/es_query_expression.tsx | 13 +++- .../expression/es_query_form_type_chooser.tsx | 68 +++++++++++++++++++ .../es_query/expression/expression.tsx | 39 ++++++++--- 4 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx index 7e38fcf81c678..a0c80ef880c42 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx @@ -22,6 +22,7 @@ import { import { useKibana } from '@kbn/kibana-react-plugin/public'; import { EsQueryAlertParams, SearchType } from '../types'; import { EsQueryExpression } from './es_query_expression'; +import { EsQueryFormType } from './es_query_form_type_chooser'; jest.mock('@kbn/kibana-react-plugin/public'); jest.mock('@kbn/es-ui-shared-plugin/public', () => ({ @@ -143,6 +144,7 @@ describe('EsQueryAlertTypeExpression', () => { const wrapper = mountWithIntl( +> & { + activeEsQueryFormType: EsQueryFormType; +}; + +export const EsQueryExpression: React.FC = ({ ruleParams, setRuleParams, setRuleProperty, errors, data, -}: RuleTypeParamsExpressionProps>) => { + activeEsQueryFormType, +}) => { const { index, timeField, @@ -162,6 +170,7 @@ export const EsQueryExpression = ({ return ( + {activeEsQueryFormType}
= [ + { + formType: EsQueryFormType.KQL_OR_LUCENE, + label: i18n.translate( + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.kqlOrLuceneFormTypeLabel', + { + defaultMessage: 'KQL or Lucene', + } + ), + }, + { + formType: EsQueryFormType.QUERY_DSL, + label: i18n.translate( + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.queryDslFormTypeLabel', + { + defaultMessage: 'Query DSL', + } + ), + }, +]; + +export interface EsQueryFormTypeProps { + onFormTypeSelect: (formType: EsQueryFormType) => void; +} + +export const EsQueryFormTypeChooser: React.FC = ({ onFormTypeSelect }) => { + return ( + <> + +
+ +
+
+ + {FORM_TYPE_ITEMS.map((item) => ( + onFormTypeSelect(item.formType)} + /> + ))} + + + ); +}; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index 3b5e978b999c8..b2a99d861dec8 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, PropsWithChildren } from 'react'; +import React, { memo, PropsWithChildren, useState } from 'react'; import { i18n } from '@kbn/i18n'; import deepEqual from 'fast-deep-equal'; @@ -16,6 +16,7 @@ import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/p import { ErrorKey, EsQueryAlertParams } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; import { EsQueryExpression } from './es_query_expression'; +import { EsQueryFormType, EsQueryFormTypeChooser } from './es_query_form_type_chooser'; import { isSearchSourceAlert } from '../util'; import { EXPRESSION_ERROR_KEYS } from '../constants'; @@ -38,6 +39,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< > = (props) => { const { ruleParams, errors } = props; const isSearchSource = isSearchSourceAlert(ruleParams); + const [activeEsQueryFormType, setActiveEsQueryFormType] = useState(null); const hasExpressionErrors = Object.keys(errors).some((errorKey) => { return ( @@ -54,19 +56,36 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< } ); - return ( + const expressionError = hasExpressionErrors && ( <> - {hasExpressionErrors && ( - <> - - - - )} + + + + ); - {isSearchSource ? ( + // on Discover page + if (isSearchSource) { + return ( + <> + {expressionError} + + ); + } + + // on Stack Management page + return ( + <> + {expressionError} + + {activeEsQueryFormType ? ( + ) : ( - + )} ); From b27a92c6259632a91702cde89d03500a7cbce774 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 20 Jun 2022 17:23:19 +0200 Subject: [PATCH 02/52] [Alerting] Add labels --- .../expression/es_query_form_type_chooser.tsx | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx index 8db599243753f..8939584a0c664 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiListGroup, EuiListGroupItem, EuiTitle } from '@elastic/eui'; +import { EuiListGroup, EuiListGroupItem, EuiText, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -15,7 +15,7 @@ export enum EsQueryFormType { QUERY_DSL = 'query_dsl', } -const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string }> = [ +const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string; description: string }> = [ { formType: EsQueryFormType.KQL_OR_LUCENE, label: i18n.translate( @@ -24,6 +24,13 @@ const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string }> = [ defaultMessage: 'KQL or Lucene', } ), + description: i18n.translate( + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.kqlOrLuceneFormTypeDescription', + { + defaultMessage: + 'Make use of a data view, write the query using KQL or Lucene and add filters.', + } + ), }, { formType: EsQueryFormType.QUERY_DSL, @@ -33,6 +40,12 @@ const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string }> = [ defaultMessage: 'Query DSL', } ), + description: i18n.translate( + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.queryDslFormTypeDescription', + { + defaultMessage: 'Make use of the powerful Query DSL of Elasticsearch.', + } + ), }, ]; @@ -51,14 +64,21 @@ export const EsQueryFormTypeChooser: React.FC = ({ onFormT />
- + {FORM_TYPE_ITEMS.map((item) => ( + {item.label} + +

{item.description}

+
+ + } onClick={() => onFormTypeSelect(item.formType)} /> ))} From 10c4ed0e5f569ac78c666278d9ec780e0eab99ec Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 21 Jun 2022 14:44:47 +0200 Subject: [PATCH 03/52] [Alerting] Unify common rule expressiosn --- .../expression/es_query_expression.tsx | 102 +++--------- .../expression/es_query_form_type_chooser.tsx | 57 ++++++- .../es_query/expression/expression.tsx | 41 ++--- .../search_source_expression_form.tsx | 79 +++------- .../es_query/rule_common_expressions/index.ts | 8 + .../rule_common_expressions.tsx | 146 ++++++++++++++++++ .../es_query/test_query_row/index.ts | 9 ++ .../test_query_row.tsx | 11 +- .../use_test_query.test.ts | 0 .../use_test_query.ts | 0 10 files changed, 289 insertions(+), 164 deletions(-) create mode 100644 x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/index.ts create mode 100644 x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx create mode 100644 x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts rename x-pack/plugins/stack_alerts/public/alert_types/es_query/{expression => test_query_row}/test_query_row.tsx (93%) rename x-pack/plugins/stack_alerts/public/alert_types/es_query/{expression => test_query_row}/use_test_query.test.ts (100%) rename x-pack/plugins/stack_alerts/public/alert_types/es_query/{expression => test_query_row}/use_test_query.ts (100%) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 874ade181452d..663e31041135b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -13,34 +13,20 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { XJsonMode } from '@kbn/ace'; import 'brace/theme/github'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiSpacer, - EuiFormRow, - EuiTitle, - EuiLink, - EuiIconTip, -} from '@elastic/eui'; +import { EuiSpacer, EuiFormRow, EuiTitle, EuiLink } from '@elastic/eui'; import { DocLinksStart, HttpSetup } from '@kbn/core/public'; import { XJson, EuiCodeEditor } from '@kbn/es-ui-shared-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { - getFields, - ValueExpression, - RuleTypeParamsExpressionProps, - ForLastExpression, - ThresholdExpression, -} from '@kbn/triggers-actions-ui-plugin/public'; +import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { parseDuration } from '@kbn/alerting-plugin/common'; import { validateExpression } from '../validation'; import { buildSortedEventsQuery } from '../../../../common/build_sorted_events_query'; import { EsQueryAlertParams, SearchType } from '../types'; import { IndexSelectPopover } from '../../components/index_select_popover'; import { DEFAULT_VALUES } from '../constants'; -import { TestQueryRow } from './test_query_row'; -import { totalHitsToNumber } from './use_test_query'; +import { RuleCommonExpressions } from '../rule_common_expressions'; +import { totalHitsToNumber } from '../test_query_row'; import { EsQueryFormType } from './es_query_form_type_chooser'; const { useXJsonMode } = XJson; @@ -179,7 +165,9 @@ export const EsQueryExpression: React.FC = ({ /> + + = ({ }} onTimeFieldChange={(updatedTimeField: string) => setParam('timeField', updatedTimeField)} /> - { - setParam('size', updatedValue); - }} - /> - + + +
= ({ }} /> - + - - - -
- -
-
-
- - - -
- - - setParam('threshold', selectedThresholds) - } - onChangeSelectedThresholdComparator={(selectedThresholdComparator) => - setParam('thresholdComparator', selectedThresholdComparator) - } - /> - setParam('threshold', selectedThresholds)} + onChangeThresholdComparator={(selectedThresholdComparator) => + setParam('thresholdComparator', selectedThresholdComparator) + } onChangeWindowSize={(selectedWindowSize: number | undefined) => setParam('timeWindowSize', selectedWindowSize) } onChangeWindowUnit={(selectedWindowUnit: string) => setParam('timeWindowUnit', selectedWindowUnit) } + onChangeSizeValue={(updatedValue) => { + setParam('size', updatedValue); + }} + errors={errors} + hasValidationErrors={hasValidationErrors()} + onTestFetch={onTestQuery} /> + ); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx index 8939584a0c664..6a2a288722f13 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_form_type_chooser.tsx @@ -6,7 +6,16 @@ */ import React from 'react'; -import { EuiListGroup, EuiListGroupItem, EuiText, EuiTitle } from '@elastic/eui'; +import { + EuiButtonIcon, + EuiFlexGroup, + EuiFlexItem, + EuiListGroup, + EuiListGroupItem, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -50,17 +59,54 @@ const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string; descrip ]; export interface EsQueryFormTypeProps { - onFormTypeSelect: (formType: EsQueryFormType) => void; + activeFormType: EsQueryFormType | null; + onFormTypeSelect: (formType: EsQueryFormType | null) => void; } -export const EsQueryFormTypeChooser: React.FC = ({ onFormTypeSelect }) => { +export const EsQueryFormTypeChooser: React.FC = ({ + activeFormType, + onFormTypeSelect, +}) => { + if (activeFormType) { + const activeFormTypeItem = FORM_TYPE_ITEMS.find((item) => item.formType === activeFormType); + + return ( + <> + + + +
{activeFormTypeItem?.label}
+
+
+ + onFormTypeSelect(null)} + /> + +
+ + {activeFormTypeItem?.description} + + + + ); + } + return ( <> - +
@@ -83,6 +129,7 @@ export const EsQueryFormTypeChooser: React.FC = ({ onFormT /> ))} + ); }; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index b2a99d861dec8..bc499ff5156e4 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -11,7 +11,7 @@ import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; -import { EuiSpacer, EuiCallOut } from '@elastic/eui'; +import { EuiSpacer, EuiCallOut, EuiHorizontalRule } from '@elastic/eui'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { ErrorKey, EsQueryAlertParams } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; @@ -63,30 +63,33 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); - // on Discover page - if (isSearchSource) { - return ( - <> - {expressionError} - - - ); - } - - // on Stack Management page return ( <> {expressionError} - {activeEsQueryFormType ? ( - + {isSearchSource ? ( + <> + {/* From Discover page */} + + ) : ( - + <> + {/* From Stack Management page */} + + {activeEsQueryFormType && ( + + )} + )} + + ); }; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index c351a1fe04c6a..dbf50fbc3f499 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -13,21 +13,21 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { DataView, Query, ISearchSource, getTime } from '@kbn/data-plugin/common'; -import { - ForLastExpression, - IErrorObject, - ThresholdExpression, - ValueExpression, -} from '@kbn/triggers-actions-ui-plugin/public'; -import { SearchBar } from '@kbn/unified-search-plugin/public'; +import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; +import { SearchBar, SearchBarProps } from '@kbn/unified-search-plugin/public'; import { mapAndFlattenFilters, SavedQuery, TimeHistory } from '@kbn/data-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { EsQueryAlertParams, SearchType } from '../types'; import { DEFAULT_VALUES } from '../constants'; import { DataViewSelectPopover } from '../../components/data_view_select_popover'; import { useTriggersAndActionsUiDeps } from '../util'; -import { totalHitsToNumber } from './use_test_query'; -import { TestQueryRow } from './test_query_row'; +import { RuleCommonExpressions } from '../rule_common_expressions'; +import { totalHitsToNumber } from '../test_query_row'; + +const HIDDEN_FILTER_PANEL_OPTIONS: SearchBarProps['hiddenFilterPanelOptions'] = [ + 'pinFilter', + 'disableFilter', +]; interface LocalState { index: DataView; @@ -234,62 +234,27 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp dateRangeFrom={undefined} dateRangeTo={undefined} timeHistory={timeHistory} - hiddenFilterPanelOptions={['pinFilter', 'disableFilter']} + hiddenFilterPanelOptions={HIDDEN_FILTER_PANEL_OPTIONS} /> - - -
- -
-
- - + + - - - -
- -
-
- - - - + ); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/index.ts new file mode 100644 index 0000000000000..7a1eff20adc71 --- /dev/null +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { RuleCommonExpressions } from './rule_common_expressions'; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx new file mode 100644 index 0000000000000..49aa40d0240ea --- /dev/null +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -0,0 +1,146 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n-react'; +import { EuiFlexGroup, EuiFlexItem, EuiIconTip, EuiSpacer, EuiTitle } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { + ForLastExpression, + IErrorObject, + ThresholdExpression, + ValueExpression, +} from '@kbn/triggers-actions-ui-plugin/public'; +import { CommonAlertParams } from '../types'; +import { DEFAULT_VALUES } from '../constants'; +import { TestQueryRow, TestQueryRowProps } from '../test_query_row'; + +export interface RuleCommonExpressionsProps { + thresholdComparator?: CommonAlertParams['thresholdComparator']; + threshold?: CommonAlertParams['threshold']; + timeWindowSize: CommonAlertParams['timeWindowSize']; + timeWindowUnit: CommonAlertParams['timeWindowUnit']; + size: CommonAlertParams['size']; + errors: IErrorObject; + hasValidationErrors: boolean; + onChangeThreshold: Parameters[0]['onChangeSelectedThreshold']; + onChangeThresholdComparator: Parameters< + typeof ThresholdExpression + >[0]['onChangeSelectedThresholdComparator']; + onChangeWindowSize: Parameters[0]['onChangeWindowSize']; + onChangeWindowUnit: Parameters[0]['onChangeWindowUnit']; + onChangeSizeValue: Parameters[0]['onChangeSelectedValue']; + onTestFetch: TestQueryRowProps['fetch']; +} + +export const RuleCommonExpressions: React.FC = ({ + thresholdComparator, + threshold, + timeWindowSize, + timeWindowUnit, + size, + errors, + hasValidationErrors, + onChangeThreshold, + onChangeThresholdComparator, + onChangeWindowSize, + onChangeWindowUnit, + onChangeSizeValue, + onTestFetch, +}) => { + return ( + <> + + + +
+ +
+
+
+ + + +
+ + + + + + + +
+ +
+
+
+ + + +
+ + + + + + ); +}; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts new file mode 100644 index 0000000000000..b8a1f384272cd --- /dev/null +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { TestQueryRow, TestQueryRowProps } from './test_query_row'; +export { useTestQuery, totalHitsToNumber } from './use_test_query'; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/test_query_row.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx similarity index 93% rename from x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/test_query_row.tsx rename to x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx index f78bae7cfcaf6..46462190c4b39 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/test_query_row.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx @@ -9,13 +9,12 @@ import { EuiButton, EuiFormRow, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { useTestQuery } from './use_test_query'; -export function TestQueryRow({ - fetch, - hasValidationErrors, -}: { +export interface TestQueryRowProps { fetch: () => Promise<{ nrOfDocs: number; timeWindow: string }>; hasValidationErrors: boolean; -}) { +} + +export const TestQueryRow: React.FC = ({ fetch, hasValidationErrors }) => { const { onTestQuery, testQueryResult, testQueryError, testQueryLoading } = useTestQuery(fetch); return ( @@ -65,4 +64,4 @@ export function TestQueryRow({ )} ); -} +}; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/use_test_query.test.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/use_test_query.test.ts similarity index 100% rename from x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/use_test_query.test.ts rename to x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/use_test_query.test.ts diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/use_test_query.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/use_test_query.ts similarity index 100% rename from x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/use_test_query.ts rename to x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/use_test_query.ts From 6f2d4b6bb869382ed01745be099234a9d39b9bec Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 21 Jun 2022 15:09:59 +0200 Subject: [PATCH 04/52] [Alerting] Fix code style --- .../public/alert_types/es_query/test_query_row/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts index b8a1f384272cd..51e09eb17fbd8 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/index.ts @@ -5,5 +5,6 @@ * 2.0. */ -export { TestQueryRow, TestQueryRowProps } from './test_query_row'; +export { TestQueryRow } from './test_query_row'; +export type { TestQueryRowProps } from './test_query_row'; export { useTestQuery, totalHitsToNumber } from './use_test_query'; From 1873c56d006b3fd5067442c98a4a42a75808053b Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 21 Jun 2022 15:30:25 +0200 Subject: [PATCH 05/52] [Alerting] More refactoring --- .../expression/search_source_expression.tsx | 6 ++- .../search_source_expression_form.tsx | 50 +++++++++---------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index 26b2d074bfd8b..69356ae2298cb 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -89,9 +89,13 @@ export const SearchSourceExpression = ({ return ( diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index dbf50fbc3f499..0fbbdc1dfd70b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -17,7 +17,7 @@ import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; import { SearchBar, SearchBarProps } from '@kbn/unified-search-plugin/public'; import { mapAndFlattenFilters, SavedQuery, TimeHistory } from '@kbn/data-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { EsQueryAlertParams, SearchType } from '../types'; +import { CommonAlertParams } from '../types'; import { DEFAULT_VALUES } from '../constants'; import { DataViewSelectPopover } from '../../components/data_view_select_popover'; import { useTriggersAndActionsUiDeps } from '../util'; @@ -33,9 +33,11 @@ interface LocalState { index: DataView; filter: Filter[]; query: Query; - threshold: number[]; - timeWindowSize: number; - size: number; + thresholdComparator: CommonAlertParams['thresholdComparator']; + threshold: CommonAlertParams['threshold']; + timeWindowSize: CommonAlertParams['timeWindowSize']; + timeWindowUnit: CommonAlertParams['timeWindowUnit']; + size: CommonAlertParams['size']; } interface LocalStateAction { @@ -51,8 +53,12 @@ interface SearchSourceParamsAction { } interface SearchSourceExpressionFormProps { + thresholdComparator?: CommonAlertParams['thresholdComparator']; + threshold?: CommonAlertParams['threshold']; + timeWindowSize: CommonAlertParams['timeWindowSize']; + timeWindowUnit: CommonAlertParams['timeWindowUnit']; + size: CommonAlertParams['size']; searchSource: ISearchSource; - ruleParams: EsQueryAlertParams; errors: IErrorObject; initialSavedQuery?: SavedQuery; setParam: (paramField: string, paramValue: unknown) => void; @@ -64,8 +70,7 @@ const isSearchSourceParam = (action: LocalStateAction): action is SearchSourcePa export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProps) => { const { data } = useTriggersAndActionsUiDeps(); - const { searchSource, ruleParams, errors, initialSavedQuery, setParam } = props; - const { thresholdComparator, timeWindowUnit } = ruleParams; + const { searchSource, errors, initialSavedQuery, setParam } = props; const [savedQuery, setSavedQuery] = useState(); const timeHistory = useMemo(() => new TimeHistory(new Storage(localStorage)), []); @@ -86,19 +91,14 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp index: searchSource.getField('index')!, query: searchSource.getField('query')!, filter: mapAndFlattenFilters(searchSource.getField('filter') as Filter[]), - threshold: ruleParams.threshold, - timeWindowSize: ruleParams.timeWindowSize, - size: ruleParams.size, + threshold: props.threshold ?? DEFAULT_VALUES.THRESHOLD, + thresholdComparator: props.thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, + timeWindowSize: props.timeWindowSize, + timeWindowUnit: props.timeWindowUnit, + size: props.size, } ); - const { - index: dataView, - query, - filter: filters, - threshold, - timeWindowSize, - size, - } = ruleConfiguration; + const { index: dataView, query, filter: filters } = ruleConfiguration; const dataViews = useMemo(() => [dataView], [dataView]); const onSelectDataView = useCallback( @@ -173,7 +173,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp [] ); const onTestFetch = useCallback(async () => { - const timeWindow = `${timeWindowSize}${timeWindowUnit}`; + const timeWindow = `${ruleConfiguration.timeWindowSize}${ruleConfiguration.timeWindowUnit}`; const testSearchSource = searchSource.createCopy(); const timeFilter = getTime(searchSource.getField('index')!, { from: `now-${timeWindow}`, @@ -185,7 +185,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp ); const { rawResponse } = await firstValueFrom(testSearchSource.fetch$()); return { nrOfDocs: totalHitsToNumber(rawResponse.hits.total), timeWindow }; - }, [searchSource, timeWindowSize, timeWindowUnit, ruleConfiguration]); + }, [searchSource, ruleConfiguration]); return ( @@ -240,11 +240,11 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp Date: Wed, 22 Jun 2022 09:56:17 +0200 Subject: [PATCH 06/52] [Alerting] Show different UI based on user choice --- .../expression/es_query_expression.tsx | 25 +++--------- .../es_query/expression/expression.tsx | 39 +++++++++++++------ .../expression/search_source_expression.tsx | 30 +++++--------- .../search_source_expression_form.tsx | 32 +++++++-------- 4 files changed, 58 insertions(+), 68 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 663e31041135b..13a1a938400c9 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, Fragment, useEffect, useCallback } from 'react'; +import React, { Fragment, useCallback, useEffect, useState } from 'react'; import { firstValueFrom } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -13,10 +13,10 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { XJsonMode } from '@kbn/ace'; import 'brace/theme/github'; -import { EuiSpacer, EuiFormRow, EuiTitle, EuiLink } from '@elastic/eui'; +import { EuiFormRow, EuiLink, EuiSpacer, EuiTitle } from '@elastic/eui'; import { DocLinksStart, HttpSetup } from '@kbn/core/public'; -import { XJson, EuiCodeEditor } from '@kbn/es-ui-shared-plugin/public'; +import { EuiCodeEditor, XJson } from '@kbn/es-ui-shared-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { parseDuration } from '@kbn/alerting-plugin/common'; @@ -27,7 +27,6 @@ import { IndexSelectPopover } from '../../components/index_select_popover'; import { DEFAULT_VALUES } from '../constants'; import { RuleCommonExpressions } from '../rule_common_expressions'; import { totalHitsToNumber } from '../test_query_row'; -import { EsQueryFormType } from './es_query_form_type_chooser'; const { useXJsonMode } = XJson; const xJsonMode = new XJsonMode(); @@ -37,20 +36,9 @@ interface KibanaDeps { docLinks: DocLinksStart; } -type EsQueryExpressionProps = RuleTypeParamsExpressionProps< - EsQueryAlertParams -> & { - activeEsQueryFormType: EsQueryFormType; -}; - -export const EsQueryExpression: React.FC = ({ - ruleParams, - setRuleParams, - setRuleProperty, - errors, - data, - activeEsQueryFormType, -}) => { +export const EsQueryExpression: React.FC< + RuleTypeParamsExpressionProps> +> = ({ ruleParams, setRuleParams, setRuleProperty, errors, data }) => { const { index, timeField, @@ -156,7 +144,6 @@ export const EsQueryExpression: React.FC = ({ return ( - {activeEsQueryFormType}
(null); + const { data } = useTriggersAndActionsUiDeps(); + const emptySearchConfiguration = useMemo(() => { + return data.search.searchSource.createEmpty().getSerializedFields(); + }, [data.search.searchSource]); const hasExpressionErrors = Object.keys(errors).some((errorKey) => { return ( @@ -69,21 +71,36 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< {isSearchSource ? ( <> - {/* From Discover page */} - + {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( + + )} + ) : ( <> - {/* From Stack Management page */} - {activeEsQueryFormType && ( - + )} + {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( + )} diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index 69356ae2298cb..120090cd8bdca 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -11,29 +11,23 @@ import { EuiSpacer, EuiLoadingSpinner, EuiEmptyPrompt, EuiCallOut } from '@elast import { ISearchSource } from '@kbn/data-plugin/common'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { SavedQuery } from '@kbn/data-plugin/public'; -import { EsQueryAlertParams, SearchType } from '../types'; +import { CommonAlertParams, OnlySearchSourceAlertParams, SearchType } from '../types'; import { useTriggersAndActionsUiDeps } from '../util'; import { SearchSourceExpressionForm } from './search_source_expression_form'; import { DEFAULT_VALUES } from '../constants'; -export type SearchSourceExpressionProps = RuleTypeParamsExpressionProps< - EsQueryAlertParams ->; +export type SearchSourceExpressionProps = RuleTypeParamsExpressionProps & + OnlySearchSourceAlertParams; export const SearchSourceExpression = ({ + searchConfiguration, + savedQueryId, ruleParams, errors, setRuleParams, setRuleProperty, }: SearchSourceExpressionProps) => { - const { - searchConfiguration, - thresholdComparator, - threshold, - timeWindowSize, - timeWindowUnit, - size, - } = ruleParams; + const { thresholdComparator, threshold, timeWindowSize, timeWindowUnit, size } = ruleParams; const { data } = useTriggersAndActionsUiDeps(); const [searchSource, setSearchSource] = useState(); @@ -67,10 +61,10 @@ export const SearchSourceExpression = ({ }, [data.search.searchSource, data.dataViews]); useEffect(() => { - if (ruleParams.savedQueryId) { - data.query.savedQueries.getSavedQuery(ruleParams.savedQueryId).then(setSavedQuery); + if (savedQueryId) { + data.query.savedQueries.getSavedQuery(savedQueryId).then(setSavedQuery); } - }, [data.query.savedQueries, ruleParams.savedQueryId]); + }, [data.query.savedQueries, savedQueryId]); if (paramsError) { return ( @@ -89,11 +83,7 @@ export const SearchSourceExpression = ({ return ( void; @@ -70,7 +66,7 @@ const isSearchSourceParam = (action: LocalStateAction): action is SearchSourcePa export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProps) => { const { data } = useTriggersAndActionsUiDeps(); - const { searchSource, errors, initialSavedQuery, setParam } = props; + const { searchSource, errors, initialSavedQuery, setParam, ruleParams } = props; const [savedQuery, setSavedQuery] = useState(); const timeHistory = useMemo(() => new TimeHistory(new Storage(localStorage)), []); @@ -91,15 +87,15 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp index: searchSource.getField('index')!, query: searchSource.getField('query')!, filter: mapAndFlattenFilters(searchSource.getField('filter') as Filter[]), - threshold: props.threshold ?? DEFAULT_VALUES.THRESHOLD, - thresholdComparator: props.thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, - timeWindowSize: props.timeWindowSize, - timeWindowUnit: props.timeWindowUnit, - size: props.size, + threshold: ruleParams.threshold ?? DEFAULT_VALUES.THRESHOLD, + thresholdComparator: ruleParams.thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, + timeWindowSize: ruleParams.timeWindowSize, + timeWindowUnit: ruleParams.timeWindowUnit, + size: ruleParams.size, } ); const { index: dataView, query, filter: filters } = ruleConfiguration; - const dataViews = useMemo(() => [dataView], [dataView]); + const dataViews = useMemo(() => (dataView ? [dataView] : []), [dataView]); const onSelectDataView = useCallback( (newDataViewId) => @@ -201,8 +197,8 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp @@ -224,10 +220,10 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp onClearSavedQuery={onClearSavedQuery} onSavedQueryUpdated={onSavedQuery} onSaved={onSavedQuery} - showSaveQuery={true} - showQueryBar={true} - showQueryInput={true} - showFilterBar={true} + showSaveQuery + showQueryBar + showQueryInput + showFilterBar showDatePicker={false} showAutoRefreshOnly={false} showSubmitButton={false} From bb7e0f10bd4f676ee33708d76663f10ab9af1e00 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 11:09:29 +0200 Subject: [PATCH 07/52] [Alerting] Improve validation and reset rule params when view changes --- .../components/data_view_select_popover.tsx | 7 ++- .../expression/es_query_expression.tsx | 17 +++--- .../es_query/expression/expression.tsx | 52 +++++++++++-------- .../expression/search_source_expression.tsx | 32 ++++++++---- .../search_source_expression_form.tsx | 7 +-- .../public/alert_types/es_query/validation.ts | 24 ++++++--- 6 files changed, 87 insertions(+), 52 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index a62b640e0d8eb..b9688ddd61d56 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -62,7 +62,12 @@ export const DataViewSelectPopover: React.FunctionComponent { setDataViewPopoverOpen(true); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 13a1a938400c9..7380527c851d5 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -20,7 +20,7 @@ import { EuiCodeEditor, XJson } from '@kbn/es-ui-shared-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { getFields, RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { parseDuration } from '@kbn/alerting-plugin/common'; -import { validateExpression } from '../validation'; +import { hasExpressionValidationErrors } from '../validation'; import { buildSortedEventsQuery } from '../../../../common/build_sorted_events_query'; import { EsQueryAlertParams, SearchType } from '../types'; import { IndexSelectPopover } from '../../components/index_select_popover'; @@ -50,7 +50,7 @@ export const EsQueryExpression: React.FC< timeWindowUnit, } = ruleParams; - const [currentAlertParams, setCurrentAlertParams] = useState< + const [currentRuleParams, setCurrentRuleParams] = useState< EsQueryAlertParams >({ ...ruleParams, @@ -60,12 +60,12 @@ export const EsQueryExpression: React.FC< thresholdComparator: thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, size: size ?? DEFAULT_VALUES.SIZE, esQuery: esQuery ?? DEFAULT_VALUES.QUERY, - searchType: 'esQuery', + searchType: SearchType.esQuery, }); const setParam = useCallback( (paramField: string, paramValue: unknown) => { - setCurrentAlertParams((currentParams) => ({ + setCurrentRuleParams((currentParams) => ({ ...currentParams, [paramField]: paramValue, })); @@ -88,7 +88,7 @@ export const EsQueryExpression: React.FC< const { convertToJson, setXJson, xJson } = useXJsonMode(DEFAULT_VALUES.QUERY); const setDefaultExpressionValues = async () => { - setRuleProperty('params', currentAlertParams); + setRuleProperty('params', currentRuleParams); setXJson(esQuery ?? DEFAULT_VALUES.QUERY); if (index && index.length > 0) { @@ -109,11 +109,8 @@ export const EsQueryExpression: React.FC< }; const hasValidationErrors = useCallback(() => { - const { errors: validationErrors } = validateExpression(currentAlertParams); - return Object.keys(validationErrors).some( - (key) => validationErrors[key] && validationErrors[key].length - ); - }, [currentAlertParams]); + return hasExpressionValidationErrors(currentRuleParams); + }, [currentRuleParams]); const onTestQuery = useCallback(async () => { const window = `${timeWindowSize}${timeWindowUnit}`; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index 516422a3f4223..4f5726edb7e20 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -5,17 +5,17 @@ * 2.0. */ -import React, { memo, PropsWithChildren, useMemo, useState } from 'react'; +import React, { memo, PropsWithChildren, useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; import { EuiCallOut, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; -import { ErrorKey, EsQueryAlertParams } from '../types'; +import { ErrorKey, EsQueryAlertParams, SearchType } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; import { EsQueryExpression } from './es_query_expression'; import { EsQueryFormType, EsQueryFormTypeChooser } from './es_query_form_type_chooser'; -import { isSearchSourceAlert, useTriggersAndActionsUiDeps } from '../util'; +import { isSearchSourceAlert } from '../util'; import { EXPRESSION_ERROR_KEYS } from '../constants'; function areSearchSourceExpressionPropsEqual( @@ -35,13 +35,27 @@ const SearchSourceExpressionMemoized = memo( export const EsQueryAlertTypeExpression: React.FunctionComponent< RuleTypeParamsExpressionProps > = (props) => { - const { ruleParams, errors } = props; + const { ruleParams, errors, setRuleProperty } = props; const isSearchSource = isSearchSourceAlert(ruleParams); const [activeEsQueryFormType, setActiveEsQueryFormType] = useState(null); - const { data } = useTriggersAndActionsUiDeps(); - const emptySearchConfiguration = useMemo(() => { - return data.search.searchSource.createEmpty().getSerializedFields(); - }, [data.search.searchSource]); + + const resetFormType = useCallback(() => { + // @ts-ignore Reset rule params regardless of their type + setRuleProperty('params', {}); + setActiveEsQueryFormType(null); + }, [setActiveEsQueryFormType, setRuleProperty]); + + const formTypeSelected = useCallback( + (formType: EsQueryFormType | null) => { + if (!formType) { + resetFormType(); + return; + } + + setActiveEsQueryFormType(formType); + }, + [setActiveEsQueryFormType, resetFormType] + ); const hasExpressionErrors = Object.keys(errors).some((errorKey) => { return ( @@ -74,22 +88,16 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( )} - + ) : ( <> {activeEsQueryFormType === EsQueryFormType.QUERY_DSL && ( @@ -97,10 +105,12 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( )} diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index 120090cd8bdca..f64446bc7d1d0 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -11,23 +11,33 @@ import { EuiSpacer, EuiLoadingSpinner, EuiEmptyPrompt, EuiCallOut } from '@elast import { ISearchSource } from '@kbn/data-plugin/common'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { SavedQuery } from '@kbn/data-plugin/public'; -import { CommonAlertParams, OnlySearchSourceAlertParams, SearchType } from '../types'; +import { EsQueryAlertParams, SearchType } from '../types'; import { useTriggersAndActionsUiDeps } from '../util'; import { SearchSourceExpressionForm } from './search_source_expression_form'; import { DEFAULT_VALUES } from '../constants'; -export type SearchSourceExpressionProps = RuleTypeParamsExpressionProps & - OnlySearchSourceAlertParams; +export type SearchSourceExpressionProps = RuleTypeParamsExpressionProps< + EsQueryAlertParams +> & { + shouldResetSearchConfiguration?: boolean; +}; export const SearchSourceExpression = ({ - searchConfiguration, - savedQueryId, ruleParams, errors, setRuleParams, setRuleProperty, + shouldResetSearchConfiguration, }: SearchSourceExpressionProps) => { - const { thresholdComparator, threshold, timeWindowSize, timeWindowUnit, size } = ruleParams; + const { + thresholdComparator, + threshold, + timeWindowSize, + timeWindowUnit, + size, + savedQueryId, + searchConfiguration, + } = ruleParams; const { data } = useTriggersAndActionsUiDeps(); const [searchSource, setSearchSource] = useState(); @@ -40,8 +50,12 @@ export const SearchSourceExpression = ({ ); useEffect(() => { + const initialSearchConfiguration = shouldResetSearchConfiguration + ? data.search.searchSource.createEmpty().getSerializedFields() + : searchConfiguration; + setRuleProperty('params', { - searchConfiguration, + searchConfiguration: initialSearchConfiguration, searchType: SearchType.searchSource, timeWindowSize: timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, @@ -52,13 +66,13 @@ export const SearchSourceExpression = ({ const initSearchSource = () => data.search.searchSource - .create(searchConfiguration) + .create(initialSearchConfiguration) .then((fetchedSearchSource) => setSearchSource(fetchedSearchSource)) .catch(setParamsError); initSearchSource(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data.search.searchSource, data.dataViews]); + }, [data.search.searchSource, data.dataViews, shouldResetSearchConfiguration]); useEffect(() => { if (savedQueryId) { diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index d06976d1daa27..6d6e5933a9a72 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -17,12 +17,13 @@ import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; import { SearchBar, SearchBarProps } from '@kbn/unified-search-plugin/public'; import { mapAndFlattenFilters, SavedQuery, TimeHistory } from '@kbn/data-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { CommonAlertParams } from '../types'; +import { CommonAlertParams, EsQueryAlertParams, SearchType } from '../types'; import { DEFAULT_VALUES } from '../constants'; import { DataViewSelectPopover } from '../../components/data_view_select_popover'; import { useTriggersAndActionsUiDeps } from '../util'; import { RuleCommonExpressions } from '../rule_common_expressions'; import { totalHitsToNumber } from '../test_query_row'; +import { hasExpressionValidationErrors } from '../validation'; const HIDDEN_FILTER_PANEL_OPTIONS: SearchBarProps['hiddenFilterPanelOptions'] = [ 'pinFilter', @@ -54,7 +55,7 @@ interface SearchSourceParamsAction { interface SearchSourceExpressionFormProps { searchSource: ISearchSource; - ruleParams: CommonAlertParams; + ruleParams: EsQueryAlertParams; errors: IErrorObject; initialSavedQuery?: SavedQuery; setParam: (paramField: string, paramValue: unknown) => void; @@ -247,7 +248,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp onChangeWindowUnit={onChangeWindowUnit} onChangeSizeValue={onChangeSizeValue} errors={errors} - hasValidationErrors={false} + hasValidationErrors={hasExpressionValidationErrors(ruleParams) || !ruleConfiguration.index} onTestFetch={onTestFetch} /> 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 8a1135e75492f..17f9473d9819b 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 @@ -12,8 +12,8 @@ import { EsQueryAlertParams, ExpressionErrors } from './types'; import { isSearchSourceAlert } from './util'; import { EXPRESSION_ERRORS } from './constants'; -export const validateExpression = (alertParams: EsQueryAlertParams): ValidationResult => { - const { size, threshold, timeWindowSize, thresholdComparator } = alertParams; +export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationResult => { + const { size, threshold, timeWindowSize, thresholdComparator } = ruleParams; const validationResult = { errors: {} }; const errors: ExpressionErrors = defaultsDeep({}, EXPRESSION_ERRORS); validationResult.errors = errors; @@ -72,9 +72,9 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR * Skip esQuery and index params check if it is search source alert, * since it should contain searchConfiguration instead of esQuery and index. */ - const isSearchSource = isSearchSourceAlert(alertParams); + const isSearchSource = isSearchSourceAlert(ruleParams); if (isSearchSource) { - if (!alertParams.searchConfiguration) { + if (!ruleParams.searchConfiguration) { errors.searchConfiguration.push( i18n.translate( 'xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchConfiguration', @@ -87,7 +87,7 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR return validationResult; } - if (!alertParams.index || alertParams.index.length === 0) { + if (!ruleParams.index || ruleParams.index.length === 0) { errors.index.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredIndexText', { defaultMessage: 'Index is required.', @@ -95,7 +95,7 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR ); } - if (!alertParams.timeField) { + if (!ruleParams.timeField) { errors.timeField.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredTimeFieldText', { defaultMessage: 'Time field is required.', @@ -103,7 +103,7 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR ); } - if (!alertParams.esQuery) { + if (!ruleParams.esQuery) { errors.esQuery.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredQueryText', { defaultMessage: 'Elasticsearch query is required.', @@ -111,7 +111,7 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR ); } else { try { - const parsedQuery = JSON.parse(alertParams.esQuery); + const parsedQuery = JSON.parse(ruleParams.esQuery); if (!parsedQuery.query) { errors.esQuery.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredEsQueryText', { @@ -130,3 +130,11 @@ export const validateExpression = (alertParams: EsQueryAlertParams): ValidationR return validationResult; }; + +// TODO: add tests +export const hasExpressionValidationErrors = (ruleParams: EsQueryAlertParams) => { + const { errors: validationErrors } = validateExpression(ruleParams); + return Object.keys(validationErrors).some( + (key) => validationErrors[key] && validationErrors[key].length + ); +}; From f03a99a3f80a3a4ef8a7308376c557c77970ead5 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 11:21:58 +0200 Subject: [PATCH 08/52] Resolve conflicts --- .../alert_types/es_query/expression/es_query_expression.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 7380527c851d5..5e17795e8fd65 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -5,8 +5,8 @@ * 2.0. */ -import React, { Fragment, useCallback, useEffect, useState } from 'react'; -import { firstValueFrom } from 'rxjs'; +import React, { useState, Fragment, useEffect, useCallback } from 'react'; +import { lastValueFrom } from 'rxjs'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -120,7 +120,7 @@ export const EsQueryExpression: React.FC< const timeWindow = parseDuration(window); const parsedQuery = JSON.parse(esQuery); const now = Date.now(); - const { rawResponse } = await firstValueFrom( + const { rawResponse } = await lastValueFrom( data.search.search({ params: buildSortedEventsQuery({ index, From d64ceca22e29088e5d282fa419d7821a6b032d98 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 11:30:44 +0200 Subject: [PATCH 09/52] [Alerting] Fix button color --- .../public/application/sections/rule_form/confirm_rule_close.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/confirm_rule_close.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/confirm_rule_close.tsx index 1b3ad3473b7ec..f553755c430e8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/confirm_rule_close.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/confirm_rule_close.tsx @@ -26,6 +26,7 @@ export const ConfirmRuleClose: React.FC = ({ onConfirm, onCancel }) => { )} onCancel={onCancel} onConfirm={onConfirm} + buttonColor="danger" confirmButtonText={i18n.translate( 'xpack.triggersActionsUI.sections.confirmRuleClose.confirmRuleCloseConfirmButtonText', { From c3638ea2707b3e856d2a5c28f779df05c7c47be8 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 11:32:15 +0200 Subject: [PATCH 10/52] [Alerting] Revert tmp changes --- .../es_query/expression/es_query_expression.test.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx index e92c3833389ba..e361c4d98bb77 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.test.tsx @@ -22,7 +22,6 @@ import { import { useKibana } from '@kbn/kibana-react-plugin/public'; import { EsQueryAlertParams, SearchType } from '../types'; import { EsQueryExpression } from './es_query_expression'; -import { EsQueryFormType } from './es_query_form_type_chooser'; jest.mock('@kbn/kibana-react-plugin/public'); jest.mock('@kbn/es-ui-shared-plugin/public', () => ({ @@ -144,7 +143,6 @@ describe('EsQueryAlertTypeExpression', () => { const wrapper = mountWithIntl( Date: Wed, 22 Jun 2022 15:26:47 +0200 Subject: [PATCH 11/52] [Alerting] Fix query input --- .../es_query/expression/search_source_expression.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index f64446bc7d1d0..6a3f0caa6a4bb 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -50,9 +50,13 @@ export const SearchSourceExpression = ({ ); useEffect(() => { - const initialSearchConfiguration = shouldResetSearchConfiguration - ? data.search.searchSource.createEmpty().getSerializedFields() - : searchConfiguration; + let initialSearchConfiguration = searchConfiguration; + + if (shouldResetSearchConfiguration) { + const newSearchSource = data.search.searchSource.createEmpty(); + newSearchSource.setField('query', data.query.queryString.getDefaultQuery()); + initialSearchConfiguration = newSearchSource.getSerializedFields(); + } setRuleProperty('params', { searchConfiguration: initialSearchConfiguration, From 01fed9837ce15000bbc69feba808dfdc3860a160 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 15:44:37 +0200 Subject: [PATCH 12/52] [Alerting] Fix thresholdComparator and timeWindowUnit changes --- .../search_source_expression_form.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 26e977206bc65..6333fa9a59bf3 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -42,8 +42,10 @@ interface LocalState { } interface LocalStateAction { - type: SearchSourceParamsAction['type'] | ('threshold' | 'timeWindowSize' | 'size'); - payload: SearchSourceParamsAction['payload'] | (number[] | number); + type: + | SearchSourceParamsAction['type'] + | ('threshold' | 'thresholdComparator' | 'timeWindowSize' | 'timeWindowUnit' | 'size'); + payload: SearchSourceParamsAction['payload'] | (number[] | number | string); } type LocalStateReducer = (prevState: LocalState, action: LocalStateAction) => LocalState; @@ -90,9 +92,9 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp filter: mapAndFlattenFilters(searchSource.getField('filter') as Filter[]), threshold: ruleParams.threshold ?? DEFAULT_VALUES.THRESHOLD, thresholdComparator: ruleParams.thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, - timeWindowSize: ruleParams.timeWindowSize, - timeWindowUnit: ruleParams.timeWindowUnit, - size: ruleParams.size, + timeWindowSize: ruleParams.timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, + timeWindowUnit: ruleParams.timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, + size: ruleParams.size ?? DEFAULT_VALUES.SIZE, } ); const { index: dataView, query, filter: filters } = ruleConfiguration; @@ -142,8 +144,9 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp // window size const onChangeWindowUnit = useCallback( - (selectedWindowUnit: string) => setParam('timeWindowUnit', selectedWindowUnit), - [setParam] + (selectedWindowUnit: string) => + dispatch({ type: 'timeWindowUnit', payload: selectedWindowUnit }), + [] ); const onChangeWindowSize = useCallback( @@ -155,8 +158,9 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp // threshold const onChangeSelectedThresholdComparator = useCallback( (selectedThresholdComparator?: string) => - setParam('thresholdComparator', selectedThresholdComparator), - [setParam] + selectedThresholdComparator && + dispatch({ type: 'thresholdComparator', payload: selectedThresholdComparator }), + [] ); const onChangeSelectedThreshold = useCallback( @@ -169,6 +173,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp (updatedValue: number) => dispatch({ type: 'size', payload: updatedValue }), [] ); + const onTestFetch = useCallback(async () => { const timeWindow = `${ruleConfiguration.timeWindowSize}${ruleConfiguration.timeWindowUnit}`; const testSearchSource = searchSource.createCopy(); From 9906708bfb49322b2045b1ae00e61c6e02ead62d Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 16:07:16 +0200 Subject: [PATCH 13/52] [Alerting] Unify UI for different query form types --- .../alert_types/components/index_select_popover.tsx | 8 +++++++- .../es_query/expression/es_query_expression.tsx | 13 ++----------- .../expression/es_query_form_type_chooser.tsx | 9 +++------ x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.tsx index aad203016a065..c3923e08bbd78 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/index_select_popover.tsx @@ -104,7 +104,13 @@ export const IndexSelectPopover: React.FunctionComponent = ({ description={i18n.translate('xpack.stackAlerts.components.ui.alertParams.indexLabel', { defaultMessage: 'index', })} - value={index && index.length > 0 ? renderIndices(index) : firstFieldOption.text} + value={ + index && index.length > 0 + ? renderIndices(index) + : i18n.translate('xpack.stackAlerts.components.ui.alertParams.indexPlaceholder', { + defaultMessage: 'Select an index', + }) + } isActive={indexPopoverOpen} onClick={() => { setIndexPopoverOpen(true); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 5e17795e8fd65..74cbf66ccf239 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -144,8 +144,8 @@ export const EsQueryExpression: React.FC<
@@ -183,15 +183,6 @@ export const EsQueryExpression: React.FC< - -
- -
-
- = ({ <> - -
{activeFormTypeItem?.label}
-
+ + {activeFormTypeItem?.description} +
= ({ />
- - {activeFormTypeItem?.description} - ); diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 3eeda946ada8f..15b00c635a46d 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -27805,7 +27805,6 @@ "xpack.stackAlerts.esQuery.ui.queryPrompt": "Définir la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Documentation DSL sur la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Recherche Elasticsearch", - "xpack.stackAlerts.esQuery.ui.selectIndex": "Sélectionner un index et une taille", "xpack.stackAlerts.esQuery.ui.sizeExpression": "Taille", "xpack.stackAlerts.esQuery.ui.testQuery": "Tester la recherche", "xpack.stackAlerts.esQuery.ui.validation.error.greaterThenThreshold0Text": "Seuil 1 doit être supérieur à Seuil 0.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2fa35f6e723b2..e310c5b8768a1 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27963,7 +27963,6 @@ "xpack.stackAlerts.esQuery.ui.queryPrompt": "Elasticsearchクエリを定義", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "ElasticsearchクエリDSLドキュメント", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch クエリ", - "xpack.stackAlerts.esQuery.ui.selectIndex": "インデックスとサイズを選択", "xpack.stackAlerts.esQuery.ui.sizeExpression": "サイズ", "xpack.stackAlerts.esQuery.ui.testQuery": "クエリのテスト", "xpack.stackAlerts.esQuery.ui.validation.error.greaterThenThreshold0Text": "しきい値1はしきい値0より大きくなければなりません。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 01b30dda57b2c..ae5efddf8ea23 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27996,7 +27996,6 @@ "xpack.stackAlerts.esQuery.ui.queryPrompt": "定义 Elasticsearch 查询", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Elasticsearch 查询 DSL 文档", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch 查询", - "xpack.stackAlerts.esQuery.ui.selectIndex": "选择索引和大小", "xpack.stackAlerts.esQuery.ui.sizeExpression": "大小", "xpack.stackAlerts.esQuery.ui.testQuery": "测试查询", "xpack.stackAlerts.esQuery.ui.validation.error.greaterThenThreshold0Text": "阈值 1 必须 > 阈值 0。", From a92802b498b6c4ed3a115328d24b3b1a0e7966f1 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 22 Jun 2022 16:20:36 +0200 Subject: [PATCH 14/52] [Alerting] Clean up translations --- x-pack/plugins/translations/translations/fr-FR.json | 1 - x-pack/plugins/translations/translations/ja-JP.json | 1 - x-pack/plugins/translations/translations/zh-CN.json | 1 - 3 files changed, 3 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 15b00c635a46d..6e86ea710755a 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -27802,7 +27802,6 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "La recherche correspond à {count} documents dans le/la/les dernier(s)/dernière(s) {window}.", "xpack.stackAlerts.esQuery.ui.queryEditor": "Éditeur de recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryError": "Erreur lors du test de la recherche : {message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "Définir la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Documentation DSL sur la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.sizeExpression": "Taille", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index e310c5b8768a1..cceb85ca88698 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -27960,7 +27960,6 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "前回の{window}でクエリが{count}個のドキュメントと一致しました。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearchクエリエディター", "xpack.stackAlerts.esQuery.ui.queryError": "クエリのテストエラー:{message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "Elasticsearchクエリを定義", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "ElasticsearchクエリDSLドキュメント", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch クエリ", "xpack.stackAlerts.esQuery.ui.sizeExpression": "サイズ", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ae5efddf8ea23..d93e5a2c15c6c 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -27993,7 +27993,6 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "查询在过去 {window} 匹配 {count} 个文档。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearch 查询编辑器", "xpack.stackAlerts.esQuery.ui.queryError": "测试查询时出错:{message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "定义 Elasticsearch 查询", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Elasticsearch 查询 DSL 文档", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch 查询", "xpack.stackAlerts.esQuery.ui.sizeExpression": "大小", From c81e760adceeacd5b89ccf56fb31e94a786467ea Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 23 Jun 2022 11:53:44 +0200 Subject: [PATCH 15/52] [Alerting] Fix for tests --- .../search_source_expression.test.tsx | 30 +++++++++---------- .../search_source_expression_form.tsx | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx index 1ad76de08f5e7..ff8f9b4019028 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx @@ -54,24 +54,24 @@ const testResultPartial = { running: true, }; +const searchSourceFieldsMock = { + query: { + query: '', + language: 'kuery', + }, + filter: [], + index: { + id: '90943e30-9a47-11e8-b64d-95841ca0b247', + title: 'kibana_sample_data_logs', + fields: [], + }, +}; + const searchSourceMock = { id: 'data_source6', - fields: { - query: { - query: '', - language: 'kuery', - }, - filter: [], - index: { - id: '90943e30-9a47-11e8-b64d-95841ca0b247', - title: 'kibana_sample_data_logs', - }, - }, + fields: searchSourceFieldsMock, getField: (name: string) => { - if (name === 'filter') { - return []; - } - return ''; + return (searchSourceFieldsMock as Record)[name] || ''; }, setField: jest.fn(), createCopy: jest.fn(() => { diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 6333fa9a59bf3..1f669350cbadd 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -253,7 +253,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp onChangeWindowUnit={onChangeWindowUnit} onChangeSizeValue={onChangeSizeValue} errors={errors} - hasValidationErrors={hasExpressionValidationErrors(ruleParams) || !ruleConfiguration.index} + hasValidationErrors={hasExpressionValidationErrors(ruleParams) || !dataView} onTestFetch={onTestFetch} /> From f5d4f13bb8d3979060608d70bdf5d6b3c1ed3315 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 23 Jun 2022 14:26:51 +0200 Subject: [PATCH 16/52] [Alerting] Update help tooltips --- .../rule_common_expressions.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx index 49aa40d0240ea..effa3fc6ed48f 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -54,7 +54,7 @@ export const RuleCommonExpressions: React.FC = ({ }) => { return ( <> - +
@@ -70,9 +70,6 @@ export const RuleCommonExpressions: React.FC = ({ position="right" color="subdued" type="questionInCircle" - iconProps={{ - className: 'eui-alignTop', - }} content={i18n.translate('xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip', { defaultMessage: 'The time window defined below applies only to the first rule check.', })} @@ -101,7 +98,7 @@ export const RuleCommonExpressions: React.FC = ({ onChangeWindowUnit={onChangeWindowUnit} /> - +
@@ -117,9 +114,6 @@ export const RuleCommonExpressions: React.FC = ({ position="right" color="subdued" type="questionInCircle" - iconProps={{ - className: 'eui-alignTop', - }} content={i18n.translate('xpack.stackAlerts.esQuery.ui.selectSizePrompt.toolTip', { defaultMessage: 'Specifies the number of documents to pass to the configured actions when the threshold condition is met.', From a95db6dbb775ed06a84feedeff6f7e231eb8538a Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 23 Jun 2022 14:32:13 +0200 Subject: [PATCH 17/52] [Alerting] Preselect a default data view --- .../expression/search_source_expression.tsx | 37 ++++++----- .../search_source_expression_form.tsx | 64 ++++++++++--------- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index 6a3f0caa6a4bb..f214f4f18fb89 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -50,29 +50,34 @@ export const SearchSourceExpression = ({ ); useEffect(() => { - let initialSearchConfiguration = searchConfiguration; + const initSearchSource = async () => { + let initialSearchConfiguration = searchConfiguration; - if (shouldResetSearchConfiguration) { - const newSearchSource = data.search.searchSource.createEmpty(); - newSearchSource.setField('query', data.query.queryString.getDefaultQuery()); - initialSearchConfiguration = newSearchSource.getSerializedFields(); - } + if (shouldResetSearchConfiguration) { + const newSearchSource = data.search.searchSource.createEmpty(); + newSearchSource.setField('query', data.query.queryString.getDefaultQuery()); + const defaultDataView = await data.dataViews.getDefaultDataView(); + if (defaultDataView) { + newSearchSource.setField('index', defaultDataView); + } + initialSearchConfiguration = newSearchSource.getSerializedFields(); + } - setRuleProperty('params', { - searchConfiguration: initialSearchConfiguration, - searchType: SearchType.searchSource, - timeWindowSize: timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, - timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, - threshold: threshold ?? DEFAULT_VALUES.THRESHOLD, - thresholdComparator: thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, - size: size ?? DEFAULT_VALUES.SIZE, - }); + setRuleProperty('params', { + searchConfiguration: initialSearchConfiguration, + searchType: SearchType.searchSource, + timeWindowSize: timeWindowSize ?? DEFAULT_VALUES.TIME_WINDOW_SIZE, + timeWindowUnit: timeWindowUnit ?? DEFAULT_VALUES.TIME_WINDOW_UNIT, + threshold: threshold ?? DEFAULT_VALUES.THRESHOLD, + thresholdComparator: thresholdComparator ?? DEFAULT_VALUES.THRESHOLD_COMPARATOR, + size: size ?? DEFAULT_VALUES.SIZE, + }); - const initSearchSource = () => data.search.searchSource .create(initialSearchConfiguration) .then((fetchedSearchSource) => setSearchSource(fetchedSearchSource)) .catch(setParamsError); + }; initSearchSource(); // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 1f669350cbadd..506745286ffec 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -208,36 +208,40 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp onSelectDataView={onSelectDataView} /> - - - + {dataViews.length > 0 && ( + <> + + + + + )} From 71c801e15d76d96dc77ac08b5248117f56f5792f Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 23 Jun 2022 15:40:48 +0200 Subject: [PATCH 18/52] [Alerting] Add validation tests --- .../alert_types/es_query/validation.test.ts | 17 ++++++++++++++++- .../public/alert_types/es_query/validation.ts | 1 - 2 files changed, 16 insertions(+), 2 deletions(-) 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 90b7f96b781b9..be0ebb9388129 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 @@ -6,7 +6,7 @@ */ import { EsQueryAlertParams, SearchType } from './types'; -import { validateExpression } from './validation'; +import { validateExpression, hasExpressionValidationErrors } from './validation'; describe('expression params validation', () => { test('if index property is invalid should return proper error message', () => { @@ -63,6 +63,7 @@ describe('expression params validation', () => { }; expect(validateExpression(initialParams).errors.esQuery.length).toBeGreaterThan(0); expect(validateExpression(initialParams).errors.esQuery[0]).toBe(`Query field is required.`); + expect(hasExpressionValidationErrors(initialParams)).toBe(true); }); test('if searchConfiguration property is not set should return proper error message', () => { @@ -157,4 +158,18 @@ describe('expression params validation', () => { 'Size must be between 0 and 10,000.' ); }); + + test('should not return error messages if all is correct', () => { + const initialParams: EsQueryAlertParams = { + index: ['test'], + esQuery: '{"query":{"match_all":{}}}', + size: 250, + timeWindowSize: 100, + timeWindowUnit: 's', + threshold: [0], + timeField: '@timestamp', + }; + expect(validateExpression(initialParams).errors.size.length).toBe(0); + expect(hasExpressionValidationErrors(initialParams)).toBe(false); + }); }); 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 17f9473d9819b..a492dd2635a78 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 @@ -131,7 +131,6 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe return validationResult; }; -// TODO: add tests export const hasExpressionValidationErrors = (ruleParams: EsQueryAlertParams) => { const { errors: validationErrors } = validateExpression(ruleParams); return Object.keys(validationErrors).some( From 2ede80330af5880456c8a0dbbb77737643ee279c Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 23 Jun 2022 18:24:20 +0200 Subject: [PATCH 19/52] [Alerting] Add more tests --- .../expression/es_query_expression.tsx | 2 +- .../es_query/expression/expression.test.tsx | 210 ++++++++++++++++++ .../es_query/expression/expression.tsx | 28 +-- ...hooser.tsx => query_form_type_chooser.tsx} | 21 +- 4 files changed, 236 insertions(+), 25 deletions(-) create mode 100644 x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.test.tsx rename x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/{es_query_form_type_chooser.tsx => query_form_type_chooser.tsx} (84%) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 74cbf66ccf239..c1ccda07fe46b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -195,7 +195,7 @@ export const EsQueryExpression: React.FC< isInvalid={errors.esQuery.length > 0} error={errors.esQuery} helpText={ - + = { + size: 100, + thresholdComparator: '>', + threshold: [0], + timeWindowSize: 15, + timeWindowUnit: 's', + index: ['test-index'], + timeField: '@timestamp', + esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, +}; +const defaultSearchSourceRuleParams: EsQueryAlertParams = { + size: 100, + thresholdComparator: '>', + threshold: [0], + timeWindowSize: 15, + timeWindowUnit: 's', + index: ['test-index'], + timeField: '@timestamp', + searchType: SearchType.searchSource, + searchConfiguration: {}, +}; + +const dataViewPluginMock = dataViewPluginMocks.createStartContract(); +const chartsStartMock = chartPluginMock.createStartContract(); +const unifiedSearchMock = unifiedSearchPluginMock.createStartContract(); +export const uiSettingsMock = { + get: jest.fn(), +} as unknown as IUiSettingsClient; + +const mockSearchResult = new Subject(); +const searchSourceFieldsMock = { + query: { + query: '', + language: 'kuery', + }, + filter: [], + index: { + id: '90943e30-9a47-11e8-b64d-95841ca0b247', + title: 'kibana_sample_data_logs', + fields: [], + }, +}; + +const searchSourceMock = { + id: 'data_source6', + fields: searchSourceFieldsMock, + getField: (name: string) => { + return (searchSourceFieldsMock as Record)[name] || ''; + }, + setField: jest.fn(), + createCopy: jest.fn(() => { + return searchSourceMock; + }), + setParent: jest.fn(() => { + return searchSourceMock; + }), + fetch$: jest.fn(() => { + return mockSearchResult; + }), +} as unknown as ISearchSource; + +const savedQueryMock = { + id: 'test-id', + attributes: { + title: 'test-filter-set', + description: '', + query: { + query: 'category.keyword : "Men\'s Shoes" ', + language: 'kuery', + }, + filters: [], + }, +}; + +const dataMock = dataPluginMock.createStartContract(); +(dataMock.search.searchSource.create as jest.Mock).mockImplementation(() => + Promise.resolve(searchSourceMock) +); +(dataMock.dataViews.getIdsWithTitle as jest.Mock).mockImplementation(() => Promise.resolve([])); +dataMock.dataViews.getDefaultDataView = jest.fn(() => Promise.resolve(null)); +(dataMock.query.savedQueries.getSavedQuery as jest.Mock).mockImplementation(() => + Promise.resolve(savedQueryMock) +); +dataMock.query.savedQueries.findSavedQueries = jest.fn(() => + Promise.resolve({ total: 0, queries: [] }) +); + +const setup = ( + ruleParams: EsQueryAlertParams | EsQueryAlertParams +) => { + const errors = { + index: [], + esQuery: [], + size: [], + timeField: [], + timeWindowSize: [], + searchConfiguration: [], + }; + + return mountWithIntl( + + + + ); +}; + +describe('EsQueryAlertTypeExpression', () => { + test('should render options by default', async () => { + const wrapper = setup({} as EsQueryAlertParams); + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormType_kql_or_lucene').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormType_query_dsl').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); + }); + + test('should switch to QueryDSL form type on selection and return back on cancel', async () => { + let wrapper = setup({} as EsQueryAlertParams); + await act(async () => { + findTestSubject(wrapper, 'queryFormType_query_dsl').simulate('click'); + }); + wrapper = await wrapper.update(); + + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); + expect(findTestSubject(wrapper, 'queryJsonEditor').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'selectIndexExpression').exists()).toBeTruthy(); + + await act(async () => { + findTestSubject(wrapper, 'queryFormTypeChooserCancel').simulate('click'); + }); + wrapper = await wrapper.update(); + expect(findTestSubject(wrapper, 'selectIndexExpression').exists()).toBeFalsy(); + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); + }); + + test('should switch to KQL or Lucene form type on selection and return back on cancel', async () => { + let wrapper = setup({} as EsQueryAlertParams); + await act(async () => { + findTestSubject(wrapper, 'queryFormType_kql_or_lucene').simulate('click'); + }); + wrapper = await wrapper.update(); + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); + expect(findTestSubject(wrapper, 'selectDataViewExpression').exists()).toBeTruthy(); + + await act(async () => { + findTestSubject(wrapper, 'queryFormTypeChooserCancel').simulate('click'); + }); + wrapper = await wrapper.update(); + expect(findTestSubject(wrapper, 'selectDataViewExpression').exists()).toBeFalsy(); + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); + }); + + test('should render QueryDSL form type chooser even if default rule params were passed', async () => { + const wrapper = setup(defaultEsQueryRuleParams); + expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); + expect(findTestSubject(wrapper, 'selectIndexExpression').exists()).toBeFalsy(); + }); + + test('should render KQL and Lucene view without the form type chooser when default rule params were passed', async () => { + let wrapper: ReactWrapper; + await act(async () => { + wrapper = setup(defaultSearchSourceRuleParams); + wrapper = await wrapper.update(); + }); + expect(findTestSubject(wrapper!, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); + expect(findTestSubject(wrapper!, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); + expect(findTestSubject(wrapper!, 'selectDataViewExpression').exists()).toBeFalsy(); + }); +}); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index 4f5726edb7e20..91cfa15e2cc1b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -14,7 +14,7 @@ import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/p import { ErrorKey, EsQueryAlertParams, SearchType } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; import { EsQueryExpression } from './es_query_expression'; -import { EsQueryFormType, EsQueryFormTypeChooser } from './es_query_form_type_chooser'; +import { QueryFormType, QueryFormTypeChooser } from './query_form_type_chooser'; import { isSearchSourceAlert } from '../util'; import { EXPRESSION_ERROR_KEYS } from '../constants'; @@ -37,24 +37,24 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< > = (props) => { const { ruleParams, errors, setRuleProperty } = props; const isSearchSource = isSearchSourceAlert(ruleParams); - const [activeEsQueryFormType, setActiveEsQueryFormType] = useState(null); + const [activeQueryFormType, setActiveQueryFormType] = useState(null); const resetFormType = useCallback(() => { // @ts-ignore Reset rule params regardless of their type setRuleProperty('params', {}); - setActiveEsQueryFormType(null); - }, [setActiveEsQueryFormType, setRuleProperty]); + setActiveQueryFormType(null); + }, [setActiveQueryFormType, setRuleProperty]); const formTypeSelected = useCallback( - (formType: EsQueryFormType | null) => { + (formType: QueryFormType | null) => { if (!formType) { resetFormType(); return; } - setActiveEsQueryFormType(formType); + setActiveQueryFormType(formType); }, - [setActiveEsQueryFormType, resetFormType] + [setActiveQueryFormType, resetFormType] ); const hasExpressionErrors = Object.keys(errors).some((errorKey) => { @@ -85,9 +85,9 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< {isSearchSource ? ( <> - {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( - )} @@ -95,14 +95,14 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ) : ( <> - - {activeEsQueryFormType === EsQueryFormType.QUERY_DSL && ( + {activeQueryFormType === QueryFormType.QUERY_DSL && ( )} - {activeEsQueryFormType === EsQueryFormType.KQL_OR_LUCENE && ( + {activeQueryFormType === QueryFormType.KQL_OR_LUCENE && ( = [ +const FORM_TYPE_ITEMS: Array<{ formType: QueryFormType; label: string; description: string }> = [ { - formType: EsQueryFormType.KQL_OR_LUCENE, + formType: QueryFormType.KQL_OR_LUCENE, label: i18n.translate( 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.kqlOrLuceneFormTypeLabel', { @@ -42,7 +42,7 @@ const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string; descrip ), }, { - formType: EsQueryFormType.QUERY_DSL, + formType: QueryFormType.QUERY_DSL, label: i18n.translate( 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.queryDslFormTypeLabel', { @@ -58,12 +58,12 @@ const FORM_TYPE_ITEMS: Array<{ formType: EsQueryFormType; label: string; descrip }, ]; -export interface EsQueryFormTypeProps { - activeFormType: EsQueryFormType | null; - onFormTypeSelect: (formType: EsQueryFormType | null) => void; +export interface QueryFormTypeProps { + activeFormType: QueryFormType | null; + onFormTypeSelect: (formType: QueryFormType | null) => void; } -export const EsQueryFormTypeChooser: React.FC = ({ +export const QueryFormTypeChooser: React.FC = ({ activeFormType, onFormTypeSelect, }) => { @@ -82,6 +82,7 @@ export const EsQueryFormTypeChooser: React.FC = ({ = ({ return ( <> -
+
= ({ From f890da1e81a75c78fb6fbcf4122abec85c415aa8 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Fri, 24 Jun 2022 10:48:51 +0200 Subject: [PATCH 20/52] [Alerting] Add the smaller title --- .../es_query/expression/query_form_type_chooser.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx index 06dc72e9cd35c..4a8b21ec90895 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx @@ -74,9 +74,9 @@ export const QueryFormTypeChooser: React.FC = ({ <> - - {activeFormTypeItem?.description} - + +
{activeFormTypeItem?.label}
+
= ({ />
+ + {activeFormTypeItem?.description} + ); From 1f57bb5abd33c808592fa6ce4384e06966238804 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Fri, 24 Jun 2022 11:15:20 +0200 Subject: [PATCH 21/52] [Alerting] Fix localization bug --- .../public/application/sections/rule_form/rule_edit.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx index 64137c8d40880..bcf81d6c4f150 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_edit.tsx @@ -207,9 +207,12 @@ export const RuleEdit = ({ canChangeTrigger={false} setHasActionsDisabled={setHasActionsDisabled} setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} - operation="i18n.translate('xpack.triggersActionsUI.sections.ruleEdit.operationName', { - defaultMessage: 'edit', - })" + operation={i18n.translate( + 'xpack.triggersActionsUI.sections.ruleEdit.operationName', + { + defaultMessage: 'edit', + } + )} metadata={metadata} /> From e5286ae98318243279c6b1e989ac239d4b67b767 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Fri, 24 Jun 2022 11:54:15 +0200 Subject: [PATCH 22/52] [Alerting] Fix rules editing view --- .../expression/es_query_expression.tsx | 2 +- .../es_query/expression/expression.test.tsx | 30 ++++++++++---- .../es_query/expression/expression.tsx | 40 +++++++++++-------- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index c1ccda07fe46b..74cbf66ccf239 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -195,7 +195,7 @@ export const EsQueryExpression: React.FC< isInvalid={errors.esQuery.length > 0} error={errors.esQuery} helpText={ - + const dataViewPluginMock = dataViewPluginMocks.createStartContract(); const chartsStartMock = chartPluginMock.createStartContract(); const unifiedSearchMock = unifiedSearchPluginMock.createStartContract(); +const httpMock = httpServiceMock.createStartContract(); +const docLinksMock = docLinksServiceMock.createStartContract(); export const uiSettingsMock = { get: jest.fn(), } as unknown as IUiSettingsClient; @@ -109,6 +112,7 @@ dataMock.dataViews.getDefaultDataView = jest.fn(() => Promise.resolve(null)); dataMock.query.savedQueries.findSavedQueries = jest.fn(() => Promise.resolve({ total: 0, queries: [] }) ); +(httpMock.post as jest.Mock).mockImplementation(() => Promise.resolve({ fields: [] })); const setup = ( ruleParams: EsQueryAlertParams | EsQueryAlertParams @@ -124,7 +128,12 @@ const setup = ( return mountWithIntl( { expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); }); - test('should render QueryDSL form type chooser even if default rule params were passed', async () => { - const wrapper = setup(defaultEsQueryRuleParams); - expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); - expect(findTestSubject(wrapper, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); - expect(findTestSubject(wrapper, 'selectIndexExpression').exists()).toBeFalsy(); + test('should render QueryDSL view without the form type chooser if some rule params were passed', async () => { + let wrapper: ReactWrapper; + await act(async () => { + wrapper = setup(defaultEsQueryRuleParams); + wrapper = await wrapper.update(); + }); + expect(findTestSubject(wrapper!, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); + expect(findTestSubject(wrapper!, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); + expect(findTestSubject(wrapper!, 'selectIndexExpression').exists()).toBeTruthy(); }); - test('should render KQL and Lucene view without the form type chooser when default rule params were passed', async () => { + test('should render KQL and Lucene view without the form type chooser if some rule params were passed', async () => { let wrapper: ReactWrapper; await act(async () => { wrapper = setup(defaultSearchSourceRuleParams); wrapper = await wrapper.update(); }); + wrapper = await wrapper!.update(); expect(findTestSubject(wrapper!, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); expect(findTestSubject(wrapper!, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); - expect(findTestSubject(wrapper!, 'selectDataViewExpression').exists()).toBeFalsy(); + expect(findTestSubject(wrapper!, 'selectDataViewExpression').exists()).toBeTruthy(); }); }); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index 91cfa15e2cc1b..103c38f72d76e 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -79,30 +79,34 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); + // Creating a rule from Stack Management page + if ((!ruleParams || !Object.keys(ruleParams).length) && !activeQueryFormType) { + // Showing the type chooser + return ( + + ); + } + return ( <> {expressionError} + {/* Showing the selected type */} + {activeQueryFormType && ( + + )} + {isSearchSource ? ( - <> - {activeQueryFormType === QueryFormType.KQL_OR_LUCENE && ( - - )} - - + ) : ( <> - - {activeQueryFormType === QueryFormType.QUERY_DSL && ( - - )} - {activeQueryFormType === QueryFormType.KQL_OR_LUCENE && ( + {activeQueryFormType === QueryFormType.KQL_OR_LUCENE ? ( + ) : ( + )} )} From 176bfdc837b472b781fcb5e8637ec02e50510e28 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Fri, 24 Jun 2022 14:14:58 +0200 Subject: [PATCH 23/52] [Alerting] Fix layout for mobile --- .../alert_types/es_query/expression/query_form_type_chooser.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx index 4a8b21ec90895..73120957cb00e 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx @@ -72,7 +72,7 @@ export const QueryFormTypeChooser: React.FC = ({ return ( <> - +
{activeFormTypeItem?.label}
From ef4eb777a6c77c46b0a4d0cf7786e85f7af09719 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 27 Jun 2022 13:04:58 +0200 Subject: [PATCH 24/52] [Alerting] Address PR comments --- .../public/alert_types/es_query/expression/expression.tsx | 2 +- .../es_query/expression/query_form_type_chooser.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index 103c38f72d76e..febdb9e17ff01 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -40,7 +40,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< const [activeQueryFormType, setActiveQueryFormType] = useState(null); const resetFormType = useCallback(() => { - // @ts-ignore Reset rule params regardless of their type + // @ts-expect-error Reset rule params regardless of their type setRuleProperty('params', {}); setActiveQueryFormType(null); }, [setActiveQueryFormType, setRuleProperty]); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx index 73120957cb00e..49093f0f25f16 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx @@ -84,9 +84,9 @@ export const QueryFormTypeChooser: React.FC = ({ color="danger" data-test-subj="queryFormTypeChooserCancel" aria-label={i18n.translate( - 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.deleteAriaLabel', + 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.cancelSelectionAriaLabel', { - defaultMessage: 'Delete', + defaultMessage: 'Cancel selection', } )} onClick={() => onFormTypeSelect(null)} From d238453b6c527938a8e7596c97ed4d8585724550 Mon Sep 17 00:00:00 2001 From: Dzmitry Tamashevich Date: Mon, 27 Jun 2022 21:20:38 +0300 Subject: [PATCH 25/52] [Discover] unify searchType and formType --- .../public/alert_types/es_query/constants.ts | 1 + .../es_query/expression/expression.tsx | 72 +++++++------------ .../expression/query_form_type_chooser.tsx | 22 +++--- .../expression/search_source_expression.tsx | 3 +- .../public/alert_types/es_query/types.ts | 4 +- .../public/alert_types/es_query/validation.ts | 11 +++ 6 files changed, 49 insertions(+), 64 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts index da85c878f3281..91b48d8b38c4c 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts @@ -31,6 +31,7 @@ export const EXPRESSION_ERRORS = { thresholdComparator: new Array(), timeWindowSize: new Array(), searchConfiguration: new Array(), + searchType: new Array(), }; export const EXPRESSION_ERROR_KEYS = Object.keys(EXPRESSION_ERRORS) as ErrorKey[]; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index febdb9e17ff01..c827000bcb548 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, PropsWithChildren, useCallback, useState } from 'react'; +import React, { memo, PropsWithChildren, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; @@ -14,7 +14,7 @@ import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/p import { ErrorKey, EsQueryAlertParams, SearchType } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; import { EsQueryExpression } from './es_query_expression'; -import { QueryFormType, QueryFormTypeChooser } from './query_form_type_chooser'; +import { QueryFormTypeChooser } from './query_form_type_chooser'; import { isSearchSourceAlert } from '../util'; import { EXPRESSION_ERROR_KEYS } from '../constants'; @@ -35,26 +35,19 @@ const SearchSourceExpressionMemoized = memo( export const EsQueryAlertTypeExpression: React.FunctionComponent< RuleTypeParamsExpressionProps > = (props) => { - const { ruleParams, errors, setRuleProperty } = props; + const { ruleParams, errors, setRuleProperty, setRuleParams } = props; const isSearchSource = isSearchSourceAlert(ruleParams); - const [activeQueryFormType, setActiveQueryFormType] = useState(null); - - const resetFormType = useCallback(() => { - // @ts-expect-error Reset rule params regardless of their type - setRuleProperty('params', {}); - setActiveQueryFormType(null); - }, [setActiveQueryFormType, setRuleProperty]); const formTypeSelected = useCallback( - (formType: QueryFormType | null) => { - if (!formType) { - resetFormType(); + (searchType: SearchType | null) => { + if (!searchType) { + // @ts-expect-error Reset rule params regardless of their type + setRuleProperty('params', {}); return; } - - setActiveQueryFormType(formType); + setRuleParams('searchType', searchType); }, - [setActiveQueryFormType, resetFormType] + [setRuleParams, setRuleProperty] ); const hasExpressionErrors = Object.keys(errors).some((errorKey) => { @@ -79,47 +72,30 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); - // Creating a rule from Stack Management page - if ((!ruleParams || !Object.keys(ruleParams).length) && !activeQueryFormType) { - // Showing the type chooser - return ( - - ); - } - return ( <> {expressionError} - {/* Showing the selected type */} - {activeQueryFormType && ( - - )} - - {isSearchSource ? ( - - ) : ( + {ruleParams.searchType ? ( <> - {activeQueryFormType === QueryFormType.KQL_OR_LUCENE ? ( - + {/* Showing the selected type */} + + + {isSearchSource ? ( + ) : ( )} + ) : ( + // Choosing a rule type from Stack Management page + )} diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx index 49093f0f25f16..1f357d82f9768 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx @@ -18,15 +18,11 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { SearchType } from '../types'; -export enum QueryFormType { - KQL_OR_LUCENE = 'kql_or_lucene', - QUERY_DSL = 'query_dsl', -} - -const FORM_TYPE_ITEMS: Array<{ formType: QueryFormType; label: string; description: string }> = [ +const FORM_TYPE_ITEMS: Array<{ formType: SearchType; label: string; description: string }> = [ { - formType: QueryFormType.KQL_OR_LUCENE, + formType: SearchType.searchSource, label: i18n.translate( 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.kqlOrLuceneFormTypeLabel', { @@ -42,7 +38,7 @@ const FORM_TYPE_ITEMS: Array<{ formType: QueryFormType; label: string; descripti ), }, { - formType: QueryFormType.QUERY_DSL, + formType: SearchType.esQuery, label: i18n.translate( 'xpack.stackAlerts.esQuery.ui.selectQueryFormType.queryDslFormTypeLabel', { @@ -59,16 +55,16 @@ const FORM_TYPE_ITEMS: Array<{ formType: QueryFormType; label: string; descripti ]; export interface QueryFormTypeProps { - activeFormType: QueryFormType | null; - onFormTypeSelect: (formType: QueryFormType | null) => void; + searchType: SearchType | null; + onFormTypeSelect: (formType: SearchType | null) => void; } export const QueryFormTypeChooser: React.FC = ({ - activeFormType, + searchType, onFormTypeSelect, }) => { - if (activeFormType) { - const activeFormTypeItem = FORM_TYPE_ITEMS.find((item) => item.formType === activeFormType); + if (searchType) { + const activeFormTypeItem = FORM_TYPE_ITEMS.find((item) => item.formType === searchType); return ( <> diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index f214f4f18fb89..14a55f0cf428a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -53,7 +53,8 @@ export const SearchSourceExpression = ({ const initSearchSource = async () => { let initialSearchConfiguration = searchConfiguration; - if (shouldResetSearchConfiguration) { + // Init searchConfiguration when creating rule from Stack Management page + if (!searchConfiguration) { const newSearchSource = data.search.searchSource.createEmpty(); newSearchSource.setField('query', data.query.queryString.getDefaultQuery()); const defaultDataView = await data.dataViews.getDefaultDataView(); 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 703570ad5faae..d9848190975dc 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 @@ -40,8 +40,8 @@ export interface OnlyEsQueryAlertParams { timeField: string; } export interface OnlySearchSourceAlertParams { - searchType: 'searchSource'; - searchConfiguration: SerializedSearchSourceFields; + searchType?: 'searchSource'; + searchConfiguration?: SerializedSearchSourceFields; savedQueryId?: string; } 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 a492dd2635a78..4a59b264fccd6 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 @@ -17,6 +17,17 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe const validationResult = { errors: {} }; const errors: ExpressionErrors = defaultsDeep({}, EXPRESSION_ERRORS); validationResult.errors = errors; + + if (!ruleParams.searchType) { + errors.searchType.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchType', { + defaultMessage: 'Select query type', + }) + ); + + return validationResult; + } + if (!threshold || threshold.length === 0 || threshold[0] === undefined) { errors.threshold0.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredThreshold0Text', { From 1bfbe98ea6c9663be13a7b06ee1274d418531e39 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 10:24:37 +0200 Subject: [PATCH 26/52] [Alerting] Allow to create new data views from Data View Expression --- .../data_view_select_popover.test.tsx | 8 +- .../components/data_view_select_popover.tsx | 89 ++++++++++++++----- .../search_source_expression_form.tsx | 6 +- .../public/alert_types/es_query/types.ts | 2 + .../plugins/triggers_actions_ui/kibana.json | 2 +- .../public/application/app.tsx | 2 + .../triggers_actions_ui/public/plugin.ts | 3 + .../plugins/triggers_actions_ui/tsconfig.json | 1 + 8 files changed, 81 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.test.tsx index 94e6a6b0c0cd4..75bbf0afbc77d 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.test.tsx @@ -7,15 +7,15 @@ import React from 'react'; import { mountWithIntl, nextTick } from '@kbn/test-jest-helpers'; -import { DataViewSelectPopover } from './data_view_select_popover'; +import { DataViewSelectPopover, DataViewSelectPopoverProps } from './data_view_select_popover'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { act } from 'react-dom/test-utils'; -const props = { +const props: DataViewSelectPopoverProps = { onSelectDataView: () => {}, - initialDataViewTitle: 'kibana_sample_data_logs', - initialDataViewId: 'mock-data-logs-id', + dataViewName: 'kibana_sample_data_logs', + dataViewId: 'mock-data-logs-id', }; const dataViewOptions = [ diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index b9688ddd61d56..58c054081660d 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -5,48 +5,76 @@ * 2.0. */ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { + EuiButtonEmpty, EuiButtonIcon, EuiExpression, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiPopover, + EuiPopoverFooter, EuiPopoverTitle, } from '@elastic/eui'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; import { DataViewListItem } from '@kbn/data-views-plugin/public'; import { useTriggersAndActionsUiDeps } from '../es_query/util'; -interface DataViewSelectPopoverProps { +export interface DataViewSelectPopoverProps { onSelectDataView: (newDataViewId: string) => void; - initialDataViewTitle: string; - initialDataViewId?: string; + dataViewName?: string; + dataViewId?: string; } export const DataViewSelectPopover: React.FunctionComponent = ({ onSelectDataView, - initialDataViewTitle, - initialDataViewId, + dataViewName, + dataViewId, }) => { - const { data } = useTriggersAndActionsUiDeps(); + const { data, dataViewEditor } = useTriggersAndActionsUiDeps(); const [dataViewItems, setDataViewsItems] = useState(); const [dataViewPopoverOpen, setDataViewPopoverOpen] = useState(false); - const [selectedDataViewId, setSelectedDataViewId] = useState(initialDataViewId); - const [selectedTitle, setSelectedTitle] = useState(initialDataViewTitle); + const closeDataViewEditor = useRef<() => void | undefined>(); + + const loadDataViews = useCallback(async () => { + const fetchedDataViewItems = await data.dataViews.getIdsWithTitle(); + setDataViewsItems(fetchedDataViewItems); + }, [setDataViewsItems, data.dataViews]); + + const closeDataViewPopover = useCallback(() => setDataViewPopoverOpen(false), []); + + const createDataView = useMemo( + () => + dataViewEditor?.userPermissions.editDataView() + ? () => { + closeDataViewEditor.current = dataViewEditor.openEditor({ + onSave: async (createdDataView) => { + if (createdDataView.id) { + await onSelectDataView(createdDataView.id); + await loadDataViews(); + } + }, + }); + } + : undefined, + [dataViewEditor, onSelectDataView, loadDataViews] + ); useEffect(() => { - const initDataViews = async () => { - const fetchedDataViewItems = await data.dataViews.getIdsWithTitle(); - setDataViewsItems(fetchedDataViewItems); + return () => { + // Make sure to close the editor when unmounting + if (closeDataViewEditor.current) { + closeDataViewEditor.current(); + } }; - initDataViews(); - }, [data.dataViews]); + }, []); - const closeDataViewPopover = useCallback(() => setDataViewPopoverOpen(false), []); + useEffect(() => { + loadDataViews(); + }, [loadDataViews]); if (!dataViewItems) { return null; @@ -63,7 +91,7 @@ export const DataViewSelectPopover: React.FunctionComponent { setDataViewPopoverOpen(true); }} - isInvalid={!selectedTitle} + isInvalid={!dataViewId} /> } isOpen={dataViewPopoverOpen} @@ -107,18 +135,31 @@ export const DataViewSelectPopover: React.FunctionComponent { - setSelectedDataViewId(newId); - const newTitle = dataViewItems?.find(({ id }) => id === newId)?.title; - if (newTitle) { - setSelectedTitle(newTitle); - } - onSelectDataView(newId); closeDataViewPopover(); }} - currentDataViewId={selectedDataViewId} + currentDataViewId={dataViewId} /> + {createDataView && ( + + { + closeDataViewPopover(); + createDataView(); + }} + > + {i18n.translate( + 'xpack.stackAlerts.components.ui.alertParams.dataViewPopover.createDataViewButton', + { + defaultMessage: 'Create a data view', + } + )} + + + )} ); diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 506745286ffec..1b681bb05aae2 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -203,12 +203,12 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp - {dataViews.length > 0 && ( + {Boolean(dataView?.id) && ( <> 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 703570ad5faae..2202dbeebe26b 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 @@ -9,6 +9,7 @@ import { RuleTypeParams } from '@kbn/alerting-plugin/common'; import { SerializedSearchSourceFields } from '@kbn/data-plugin/common'; import { EuiComboBoxOptionOption } from '@elastic/eui'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { EXPRESSION_ERRORS } from './constants'; export interface Comparator { @@ -53,4 +54,5 @@ export type ErrorKey = keyof ExpressionErrors & unknown; export interface TriggersAndActionsUiDeps { data: DataPublicPluginStart; + dataViewEditor: DataViewEditorStart; } diff --git a/x-pack/plugins/triggers_actions_ui/kibana.json b/x-pack/plugins/triggers_actions_ui/kibana.json index a872ad6fab5c0..1458d37834800 100644 --- a/x-pack/plugins/triggers_actions_ui/kibana.json +++ b/x-pack/plugins/triggers_actions_ui/kibana.json @@ -8,7 +8,7 @@ "server": true, "ui": true, "optionalPlugins": ["cloud", "features", "home", "spaces"], - "requiredPlugins": ["management", "charts", "data", "kibanaReact", "kibanaUtils", "savedObjects", "unifiedSearch", "dataViews", "alerting", "actions"], + "requiredPlugins": ["management", "charts", "data", "kibanaReact", "kibanaUtils", "savedObjects", "unifiedSearch", "dataViews", "dataViewEditor", "alerting", "actions"], "configPath": ["xpack", "trigger_actions_ui"], "extraPublicDirs": ["public/common", "public/common/constants"], "requiredBundles": ["alerting", "esUiShared", "kibanaReact", "kibanaUtils", "actions"] diff --git a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx index d47529c47c19d..e63999edf31a9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/app.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/app.tsx @@ -17,6 +17,7 @@ import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { PluginStartContract as AlertingStart } from '@kbn/alerting-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; @@ -45,6 +46,7 @@ export interface TriggersAndActionsUiServices extends CoreStart { actions: ActionsPublicPluginSetup; data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; + dataViewEditor: DataViewEditorStart; charts: ChartsPluginStart; alerting?: AlertingStart; spaces?: SpacesPluginStart; diff --git a/x-pack/plugins/triggers_actions_ui/public/plugin.ts b/x-pack/plugins/triggers_actions_ui/public/plugin.ts index f830488a1ecdb..7311299a2598b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/public/plugin.ts @@ -19,6 +19,7 @@ import { PluginStartContract as AlertingStart } from '@kbn/alerting-plugin/publi import { ActionsPublicPluginSetup } from '@kbn/actions-plugin/public'; import { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; @@ -119,6 +120,7 @@ interface PluginsSetup { interface PluginsStart { data: DataPublicPluginStart; dataViews: DataViewsPublicPluginStart; + dataViewEditor: DataViewEditorStart; charts: ChartsPluginStart; alerting?: AlertingStart; spaces?: SpacesPluginStart; @@ -211,6 +213,7 @@ export class Plugin actions: plugins.actions, data: pluginsStart.data, dataViews: pluginsStart.dataViews, + dataViewEditor: pluginsStart.dataViewEditor, charts: pluginsStart.charts, alerting: pluginsStart.alerting, spaces: pluginsStart.spaces, diff --git a/x-pack/plugins/triggers_actions_ui/tsconfig.json b/x-pack/plugins/triggers_actions_ui/tsconfig.json index a2113a3a230fb..8618be6c9c285 100644 --- a/x-pack/plugins/triggers_actions_ui/tsconfig.json +++ b/x-pack/plugins/triggers_actions_ui/tsconfig.json @@ -19,6 +19,7 @@ { "path": "../features/tsconfig.json" }, { "path": "../rule_registry/tsconfig.json" }, { "path": "../../../src/plugins/data/tsconfig.json" }, + { "path": "../../../src/plugins/data_view_editor/tsconfig.json" }, { "path": "../../../src/plugins/saved_objects/tsconfig.json" }, { "path": "../../../src/plugins/home/tsconfig.json" }, { "path": "../../../src/plugins/charts/tsconfig.json" }, From 396503271cb9f648833ec47a69a519365e3e83cf Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 11:27:38 +0200 Subject: [PATCH 27/52] [Alerting] Fix lint issue --- .../public/common/lib/kibana/kibana_react.mock.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/kibana_react.mock.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/kibana_react.mock.ts index a19643a8f51bd..c6b8a8376183a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/kibana_react.mock.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/kibana_react.mock.ts @@ -18,6 +18,7 @@ import { ActionTypeRegistryContract, AlertsTableConfigurationRegistryContract, } from '../../../types'; +import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; export const createStartServicesMock = (): TriggersAndActionsUiServices => { const core = coreMock.createStart(); @@ -41,6 +42,9 @@ export const createStartServicesMock = (): TriggersAndActionsUiServices => { setBreadcrumbs: jest.fn(), data: dataPluginMock.createStartContract(), dataViews: dataViewPluginMocks.createStartContract(), + dataViewEditor: { + openEditor: jest.fn(), + } as unknown as DataViewEditorStart, unifiedSearch: unifiedSearchPluginMock.createStartContract(), actionTypeRegistry: { has: jest.fn(), From 5f66599bfca41fdcf05e3dd8ece638c525e101c5 Mon Sep 17 00:00:00 2001 From: Dzmitry Tamashevich Date: Tue, 28 Jun 2022 12:55:10 +0300 Subject: [PATCH 28/52] [Discover] fix management and discover views --- .../es_query/expression/expression.tsx | 43 +++++++------------ 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index c827000bcb548..dd4efa03026c6 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import React, { memo, PropsWithChildren, useCallback } from 'react'; -import { i18n } from '@kbn/i18n'; +import React, { memo, PropsWithChildren, useCallback, useRef } from 'react'; import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; import { EuiCallOut, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; @@ -37,6 +36,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< > = (props) => { const { ruleParams, errors, setRuleProperty, setRuleParams } = props; const isSearchSource = isSearchSourceAlert(ruleParams); + const isManagementPage = useRef(!Object.keys(ruleParams).length).current; const formTypeSelected = useCallback( (searchType: SearchType | null) => { @@ -50,7 +50,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< [setRuleParams, setRuleProperty] ); - const hasExpressionErrors = Object.keys(errors).some((errorKey) => { + const errorParam = Object.keys(errors).find((errorKey) => { return ( EXPRESSION_ERROR_KEYS.includes(errorKey as ErrorKey) && errors[errorKey].length >= 1 && @@ -58,16 +58,9 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); }); - const expressionErrorMessage = i18n.translate( - 'xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage', - { - defaultMessage: 'Expression contains errors.', - } - ); - - const expressionError = hasExpressionErrors && ( + const expressionError = !!errorParam && ( <> - + ); @@ -76,28 +69,22 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< <> {expressionError} - {ruleParams.searchType ? ( - <> - {/* Showing the selected type */} - - - {isSearchSource ? ( - - ) : ( - - )} - - ) : ( - // Choosing a rule type from Stack Management page + {/* Showing the selected type */} + {isManagementPage && ( )} + {ruleParams.searchType && isSearchSource && ( + + )} + + {ruleParams.searchType && !isSearchSource && ( + + )} + ); From 757157733e1f316042fa8966b82f9a976f5a2ea2 Mon Sep 17 00:00:00 2001 From: Dzmitry Tamashevich Date: Tue, 28 Jun 2022 12:58:49 +0300 Subject: [PATCH 29/52] [Discover] remove redundant prop --- .../es_query/expression/search_source_expression.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx index 14a55f0cf428a..b00176288b751 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.tsx @@ -18,16 +18,13 @@ import { DEFAULT_VALUES } from '../constants'; export type SearchSourceExpressionProps = RuleTypeParamsExpressionProps< EsQueryAlertParams -> & { - shouldResetSearchConfiguration?: boolean; -}; +>; export const SearchSourceExpression = ({ ruleParams, errors, setRuleParams, setRuleProperty, - shouldResetSearchConfiguration, }: SearchSourceExpressionProps) => { const { thresholdComparator, @@ -82,7 +79,7 @@ export const SearchSourceExpression = ({ initSearchSource(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data.search.searchSource, data.dataViews, shouldResetSearchConfiguration]); + }, [data.search.searchSource, data.dataViews]); useEffect(() => { if (savedQueryId) { From 660cb6f5f5d44031e7cb41d54ccca963db2179d4 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 11:59:35 +0200 Subject: [PATCH 30/52] [Alerting] Add validation message when query type is not selected yet --- .../public/alert_types/es_query/constants.ts | 1 + .../alert_types/es_query/expression/expression.tsx | 4 +++- .../es_query/expression/query_form_type_chooser.tsx | 11 +++++++++++ .../public/alert_types/es_query/validation.ts | 11 +++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts index da85c878f3281..91b48d8b38c4c 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/constants.ts @@ -31,6 +31,7 @@ export const EXPRESSION_ERRORS = { thresholdComparator: new Array(), timeWindowSize: new Array(), searchConfiguration: new Array(), + searchType: new Array(), }; export const EXPRESSION_ERROR_KEYS = Object.keys(EXPRESSION_ERRORS) as ErrorKey[]; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index febdb9e17ff01..a739413e5b529 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -80,12 +80,13 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); // Creating a rule from Stack Management page - if ((!ruleParams || !Object.keys(ruleParams).length) && !activeQueryFormType) { + if (!ruleParams.searchType && !activeQueryFormType) { // Showing the type chooser return ( ); } @@ -99,6 +100,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< )} diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx index 49093f0f25f16..242b0d71ff05f 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/query_form_type_chooser.tsx @@ -18,6 +18,7 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; +import { IErrorObject } from '@kbn/triggers-actions-ui-plugin/public'; export enum QueryFormType { KQL_OR_LUCENE = 'kql_or_lucene', @@ -60,11 +61,13 @@ const FORM_TYPE_ITEMS: Array<{ formType: QueryFormType; label: string; descripti export interface QueryFormTypeProps { activeFormType: QueryFormType | null; + errors: IErrorObject; onFormTypeSelect: (formType: QueryFormType | null) => void; } export const QueryFormTypeChooser: React.FC = ({ activeFormType, + errors, onFormTypeSelect, }) => { if (activeFormType) { @@ -111,6 +114,14 @@ export const QueryFormTypeChooser: React.FC = ({ />
+ {errors.searchType?.length > 0 && ( + + + + )} {FORM_TYPE_ITEMS.map((item) => ( 0 && !ruleParams.searchType) { + errors.searchType.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchType', { + defaultMessage: 'Select query type', + }) + ); + + return validationResult; + } + if (!threshold || threshold.length === 0 || threshold[0] === undefined) { errors.threshold0.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredThreshold0Text', { From 5a2c1547f98843b39ac417b6d46556140b08b033 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 13:30:54 +0200 Subject: [PATCH 31/52] [Alerting] Update validations --- .../public/alert_types/es_query/validation.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 bbfe705745b0e..ca0ba647db74c 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 @@ -18,7 +18,7 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe const errors: ExpressionErrors = defaultsDeep({}, EXPRESSION_ERRORS); validationResult.errors = errors; - if (Object.keys(ruleParams).length > 0 && !ruleParams.searchType) { + if (!ruleParams.searchType) { errors.searchType.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchType', { defaultMessage: 'Query is required.', @@ -94,6 +94,12 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe } ) ); + } else if (!ruleParams.searchConfiguration.index) { + errors.index.push( + i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredDataViewText', { + defaultMessage: 'Data view is required.', + }) + ); } return validationResult; } From d5fd714a2359c12fc8637fbe9430c74427fe8771 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 13:58:44 +0200 Subject: [PATCH 32/52] [Alerting] Update tests --- .../es_query/expression/expression.test.tsx | 65 ++++++++++++------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.test.tsx index 61a4fe8130cd4..e26bfb48ff8b5 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.test.tsx @@ -7,13 +7,13 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import 'brace'; -import React from 'react'; +import React, { useState } from 'react'; import { docLinksServiceMock } from '@kbn/core/public/mocks'; import { httpServiceMock } from '@kbn/core/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; -import { EsQueryAlertParams, SearchType } from '../types'; +import { CommonAlertParams, EsQueryAlertParams, SearchType } from '../types'; import { EsQueryAlertTypeExpression } from './expression'; import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { Subject } from 'rxjs'; @@ -33,6 +33,7 @@ const defaultEsQueryRuleParams: EsQueryAlertParams = { index: ['test-index'], timeField: '@timestamp', esQuery: `{\n \"query\":{\n \"match_all\" : {}\n }\n}`, + searchType: SearchType.esQuery, }; const defaultSearchSourceRuleParams: EsQueryAlertParams = { size: 100, @@ -114,9 +115,10 @@ dataMock.query.savedQueries.findSavedQueries = jest.fn(() => ); (httpMock.post as jest.Mock).mockImplementation(() => Promise.resolve({ fields: [] })); -const setup = ( - ruleParams: EsQueryAlertParams | EsQueryAlertParams -) => { +const Wrapper: React.FC<{ + ruleParams: EsQueryAlertParams | EsQueryAlertParams; +}> = ({ ruleParams }) => { + const [currentRuleParams, setCurrentRuleParams] = useState(ruleParams); const errors = { index: [], esQuery: [], @@ -124,8 +126,37 @@ const setup = ( timeField: [], timeWindowSize: [], searchConfiguration: [], + searchType: [], }; + return ( + { + setCurrentRuleParams((params) => ({ ...params, [name]: value })); + }} + setRuleProperty={(name, params) => { + if (name === 'params') { + setCurrentRuleParams(params as CommonAlertParams); + } + }} + errors={errors} + unifiedSearch={unifiedSearchMock} + data={dataMock} + dataViews={dataViewPluginMock} + defaultActionGroupId="" + actionGroups={[]} + charts={chartsStartMock} + /> + ); +}; + +const setup = ( + ruleParams: EsQueryAlertParams | EsQueryAlertParams +) => { return mountWithIntl( - + ); }; @@ -158,15 +175,15 @@ describe('EsQueryAlertTypeExpression', () => { test('should render options by default', async () => { const wrapper = setup({} as EsQueryAlertParams); expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeTruthy(); - expect(findTestSubject(wrapper, 'queryFormType_kql_or_lucene').exists()).toBeTruthy(); - expect(findTestSubject(wrapper, 'queryFormType_query_dsl').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormType_searchSource').exists()).toBeTruthy(); + expect(findTestSubject(wrapper, 'queryFormType_esQuery').exists()).toBeTruthy(); expect(findTestSubject(wrapper, 'queryFormTypeChooserCancel').exists()).toBeFalsy(); }); test('should switch to QueryDSL form type on selection and return back on cancel', async () => { let wrapper = setup({} as EsQueryAlertParams); await act(async () => { - findTestSubject(wrapper, 'queryFormType_query_dsl').simulate('click'); + findTestSubject(wrapper, 'queryFormType_esQuery').simulate('click'); }); wrapper = await wrapper.update(); @@ -185,7 +202,7 @@ describe('EsQueryAlertTypeExpression', () => { test('should switch to KQL or Lucene form type on selection and return back on cancel', async () => { let wrapper = setup({} as EsQueryAlertParams); await act(async () => { - findTestSubject(wrapper, 'queryFormType_kql_or_lucene').simulate('click'); + findTestSubject(wrapper, 'queryFormType_searchSource').simulate('click'); }); wrapper = await wrapper.update(); expect(findTestSubject(wrapper, 'queryFormTypeChooserTitle').exists()).toBeFalsy(); From 763da9955f684551fb755c4e7dcfb3e8c0d51ce7 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 14:10:50 +0200 Subject: [PATCH 33/52] [Alerting] Update tests --- .../public/alert_types/es_query/validation.test.ts | 7 +++++++ .../stack_alerts/public/alert_types/es_query/validation.ts | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) 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 be0ebb9388129..c09297c023358 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 @@ -9,6 +9,13 @@ import { EsQueryAlertParams, SearchType } from './types'; import { validateExpression, hasExpressionValidationErrors } from './validation'; describe('expression params validation', () => { + test('if params are not set should return a proper error message', () => { + const initialParams: EsQueryAlertParams = + {} as EsQueryAlertParams; + expect(validateExpression(initialParams).errors.searchType.length).toBeGreaterThan(0); + expect(validateExpression(initialParams).errors.searchType[0]).toBe('Query is required.'); + }); + test('if index property is invalid should return proper error message', () => { const initialParams: EsQueryAlertParams = { index: [], 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 ca0ba647db74c..e070646443057 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 @@ -18,7 +18,7 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe const errors: ExpressionErrors = defaultsDeep({}, EXPRESSION_ERRORS); validationResult.errors = errors; - if (!ruleParams.searchType) { + if (!('index' in ruleParams) && !ruleParams.searchType) { errors.searchType.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchType', { defaultMessage: 'Query is required.', From 6bff7223bcd11a7445a249795888a835cbcac70d Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 14:30:38 +0200 Subject: [PATCH 34/52] [Alerting] Update tests --- .../search_source_expression.test.tsx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx index ff8f9b4019028..fa15cd1e6a43b 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression.test.tsx @@ -37,7 +37,13 @@ const defaultSearchSourceExpressionParams: EsQueryAlertParams Promise.resolve([])); +dataMock.dataViews.getDefaultDataView = jest.fn(() => Promise.resolve(null)); (dataMock.query.savedQueries.getSavedQuery as jest.Mock).mockImplementation(() => Promise.resolve(savedQueryMock) ); @@ -152,6 +159,17 @@ describe('SearchSourceAlertTypeExpression', () => { expect(findTestSubject(wrapper, 'thresholdExpression')).toBeTruthy(); }); + test('should disable Test Query button if data view is not selected yet', async () => { + let wrapper = setup({ ...defaultSearchSourceExpressionParams, searchConfiguration: undefined }); + await act(async () => { + await nextTick(); + }); + wrapper = await wrapper.update(); + + const testButton = findTestSubject(wrapper, 'testQuery'); + expect(testButton.prop('disabled')).toBeTruthy(); + }); + test('should show success message if Test Query is successful', async () => { let wrapper = setup(defaultSearchSourceExpressionParams); await act(async () => { @@ -159,7 +177,9 @@ describe('SearchSourceAlertTypeExpression', () => { }); wrapper = await wrapper.update(); await act(async () => { - findTestSubject(wrapper, 'testQuery').simulate('click'); + const testButton = findTestSubject(wrapper, 'testQuery'); + expect(testButton.prop('disabled')).toBeFalsy(); + testButton.simulate('click'); wrapper.update(); }); wrapper = await wrapper.update(); From 8d9daec027d5ffc54d6b3cf1f2e48a1e2d506710 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 14:40:44 +0200 Subject: [PATCH 35/52] [Alerting] Prioritize index errors --- .../alert_types/es_query/expression/expression.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index dd4efa03026c6..fad18e514d601 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -10,7 +10,7 @@ import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; import { EuiCallOut, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; -import { ErrorKey, EsQueryAlertParams, SearchType } from '../types'; +import { EsQueryAlertParams, SearchType } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; import { EsQueryExpression } from './es_query_expression'; import { QueryFormTypeChooser } from './query_form_type_chooser'; @@ -50,12 +50,8 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< [setRuleParams, setRuleProperty] ); - const errorParam = Object.keys(errors).find((errorKey) => { - return ( - EXPRESSION_ERROR_KEYS.includes(errorKey as ErrorKey) && - errors[errorKey].length >= 1 && - ruleParams[errorKey] !== undefined - ); + const errorParam = EXPRESSION_ERROR_KEYS.find((errorKey) => { + return errors[errorKey].length >= 1 && ruleParams[errorKey] !== undefined; }); const expressionError = !!errorParam && ( From 79fefd07a72205470c0157abfc1b91635cfac7de Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 15:07:05 +0200 Subject: [PATCH 36/52] [Alerting] Fix size validation --- .../es_query/expression/expression.tsx | 18 +++++++++++++++++- .../public/common/expression_items/value.tsx | 1 + 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index fad18e514d601..d2f2c103d3acb 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -9,6 +9,7 @@ import React, { memo, PropsWithChildren, useCallback, useRef } from 'react'; import deepEqual from 'fast-deep-equal'; import 'brace/theme/github'; import { EuiCallOut, EuiHorizontalRule, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { EsQueryAlertParams, SearchType } from '../types'; import { SearchSourceExpression, SearchSourceExpressionProps } from './search_source_expression'; @@ -50,13 +51,28 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< [setRuleParams, setRuleProperty] ); + const expressionGenericErrorMessage = i18n.translate( + 'xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage', + { + defaultMessage: 'Expression contains errors.', + } + ); + const errorParam = EXPRESSION_ERROR_KEYS.find((errorKey) => { return errors[errorKey].length >= 1 && ruleParams[errorKey] !== undefined; }); const expressionError = !!errorParam && ( <> - + ); 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 index a66d91987e3b2..5259fdf0b5d82 100644 --- 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 @@ -59,6 +59,7 @@ export const ValueExpression = ({ onClick={() => { setValuePopoverOpen(true); }} + isInvalid={errors.length > 0} /> } isOpen={valuePopoverOpen} From b6dd854ff12018b8bfcc150dd5fc97427fa20579 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 15:16:12 +0200 Subject: [PATCH 37/52] [Alerting] Fix timeWindowSize validation --- .../public/common/expression_items/for_the_last.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx index d99de651a57e6..9f287f5f066f2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/common/expression_items/for_the_last.tsx @@ -67,7 +67,7 @@ export const ForLastExpression = ({ } )} data-test-subj="forLastExpression" - value={`${timeWindowSize} ${getTimeUnitLabel( + value={`${timeWindowSize ?? '?'} ${getTimeUnitLabel( timeWindowUnit as TIME_UNITS, (timeWindowSize ?? '').toString() )}`} @@ -97,13 +97,10 @@ export const ForLastExpression = ({ - 0 && timeWindowSize !== undefined} - error={errors.timeWindowSize} - > + 0} error={errors.timeWindowSize}> 0 && timeWindowSize !== undefined} + isInvalid={errors.timeWindowSize.length > 0} min={0} value={timeWindowSize || ''} onChange={(e) => { From b174aaab6ba06a62c6d6101460f1b2a699f848e7 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Tue, 28 Jun 2022 16:08:24 +0200 Subject: [PATCH 38/52] [Alerting] Address CI issues --- .../public/alert_types/es_query/expression/expression.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx index d2f2c103d3acb..8a56fdc4f41e3 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/expression.tsx @@ -59,7 +59,7 @@ export const EsQueryAlertTypeExpression: React.FunctionComponent< ); const errorParam = EXPRESSION_ERROR_KEYS.find((errorKey) => { - return errors[errorKey].length >= 1 && ruleParams[errorKey] !== undefined; + return errors[errorKey]?.length >= 1 && ruleParams[errorKey] !== undefined; }); const expressionError = !!errorParam && ( From 36ac0223ca80d10e4b156fd9cd9ed9586515b1ec Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 29 Jun 2022 12:44:18 +0200 Subject: [PATCH 39/52] Address plugins concurrency effect on sample data server API --- .../services/sample_data/routes/list.ts | 3 ++- test/api_integration/apis/home/sample_data.ts | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/plugins/home/server/services/sample_data/routes/list.ts b/src/plugins/home/server/services/sample_data/routes/list.ts index a83ee7a57c432..fb5c9549fefd5 100644 --- a/src/plugins/home/server/services/sample_data/routes/list.ts +++ b/src/plugins/home/server/services/sample_data/routes/list.ts @@ -6,6 +6,7 @@ * Side Public License, v 1. */ +import { sortBy } from 'lodash'; import type { IRouter, Logger, RequestHandlerContext } from '@kbn/core/server'; import type { AppLinkData, SampleDatasetSchema } from '../lib/sample_dataset_registry_types'; import { createIndexName } from '../lib/create_index_name'; @@ -55,7 +56,7 @@ export const createListRoute = ( previewImagePath: sampleDataset.previewImagePath, darkPreviewImagePath: sampleDataset.darkPreviewImagePath, overviewDashboard: findObjectId('dashboard', sampleDataset.overviewDashboard), - appLinks, + appLinks: sortBy(appLinks, 'order'), defaultIndex: findObjectId('index-pattern', sampleDataset.defaultIndex), dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })), ...sampleDataStatus, diff --git a/test/api_integration/apis/home/sample_data.ts b/test/api_integration/apis/home/sample_data.ts index 6636a490118b4..da33f5322e8b7 100644 --- a/test/api_integration/apis/home/sample_data.ts +++ b/test/api_integration/apis/home/sample_data.ts @@ -21,6 +21,10 @@ export default function ({ getService }: FtrProviderContext) { const FLIGHTS_CANVAS_APPLINK_PATH = '/app/canvas#/workpad/workpad-a474e74b-aedc-47c3-894a-db77e62c41e0'; // includes default ID of the flights canvas applink path + const includesPathInAppLinks = (appLinks: Array<{ path: string }>, path: string): boolean => { + return appLinks.some((item) => item.path === path); + }; + describe('sample data apis', () => { before(async () => { await esArchiver.emptyKibanaIndex(); @@ -41,7 +45,9 @@ export default function ({ getService }: FtrProviderContext) { // Check and make sure the sample dataset reflects the default object IDs, because no sample data objects exist. // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(flightsData.appLinks[0].path).to.be(FLIGHTS_CANVAS_APPLINK_PATH); + expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( + true + ); }); }); @@ -109,11 +115,15 @@ export default function ({ getService }: FtrProviderContext) { // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. if (space === 'default') { expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(flightsData.appLinks[0].path).to.be(FLIGHTS_CANVAS_APPLINK_PATH); + expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( + true + ); } else { // the sample data objects installed in the 'other' space had their IDs regenerated upon import expect(flightsData.overviewDashboard).not.to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(flightsData.appLinks[0].path).not.to.be(FLIGHTS_CANVAS_APPLINK_PATH); + expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( + false + ); } }); }); @@ -145,7 +155,9 @@ export default function ({ getService }: FtrProviderContext) { // Check and make sure the sample dataset reflects the default object IDs, because no sample data objects exist. // Instead of checking each object ID, we check the dashboard and canvas app link as representatives. expect(flightsData.overviewDashboard).to.be(FLIGHTS_OVERVIEW_DASHBOARD_ID); - expect(flightsData.appLinks[0].path).to.be(FLIGHTS_CANVAS_APPLINK_PATH); + expect(includesPathInAppLinks(flightsData.appLinks, FLIGHTS_CANVAS_APPLINK_PATH)).to.be( + true + ); }); }); } From 7b3e2553e43683b1e06953aeed31772d9c16b1fb Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 13:51:47 +0200 Subject: [PATCH 40/52] [Alerting] Remove deprecated strings --- x-pack/plugins/translations/translations/fr-FR.json | 2 -- x-pack/plugins/translations/translations/ja-JP.json | 2 -- x-pack/plugins/translations/translations/zh-CN.json | 2 -- 3 files changed, 6 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 4184d7da54335..acec24fb028a8 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28963,10 +28963,8 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "La recherche correspond à {count} documents dans le/la/les dernier(s)/dernière(s) {window}.", "xpack.stackAlerts.esQuery.ui.queryEditor": "Éditeur de recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryError": "Erreur lors du test de la recherche : {message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "Définir la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Documentation DSL sur la recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Recherche Elasticsearch", - "xpack.stackAlerts.esQuery.ui.selectIndex": "Sélectionner un index et une taille", "xpack.stackAlerts.esQuery.ui.sizeExpression": "Taille", "xpack.stackAlerts.esQuery.ui.testQuery": "Tester la recherche", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "La requête a été exécutée.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 53cb6d9f861f7..2d5565bf64ce0 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28946,10 +28946,8 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "前回の{window}でクエリが{count}個のドキュメントと一致しました。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearchクエリエディター", "xpack.stackAlerts.esQuery.ui.queryError": "クエリのテストエラー:{message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "Elasticsearchクエリを定義", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "ElasticsearchクエリDSLドキュメント", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch クエリ", - "xpack.stackAlerts.esQuery.ui.selectIndex": "インデックスとサイズを選択", "xpack.stackAlerts.esQuery.ui.sizeExpression": "サイズ", "xpack.stackAlerts.esQuery.ui.testQuery": "クエリのテスト", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "クエリが実行されます。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index fa69fb3a84edd..ba8241b2a5a45 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28972,10 +28972,8 @@ "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "查询在过去 {window} 匹配 {count} 个文档。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearch 查询编辑器", "xpack.stackAlerts.esQuery.ui.queryError": "测试查询时出错:{message}", - "xpack.stackAlerts.esQuery.ui.queryPrompt": "定义 Elasticsearch 查询", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Elasticsearch 查询 DSL 文档", "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch 查询", - "xpack.stackAlerts.esQuery.ui.selectIndex": "选择索引和大小", "xpack.stackAlerts.esQuery.ui.sizeExpression": "大小", "xpack.stackAlerts.esQuery.ui.testQuery": "测试查询", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "已执行查询。", From 6c4aaee4baf90abfd59abba0b216da575d4599d2 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 14:36:37 +0200 Subject: [PATCH 41/52] [Alerting] Update copy and spacing --- .../expression/es_query_expression.tsx | 21 +++++++------ .../expression/query_form_type_chooser.tsx | 5 ++-- .../search_source_expression_form.tsx | 20 ++++++++----- .../public/alert_types/es_query/index.ts | 4 +-- .../rule_common_expressions.tsx | 30 +++++-------------- .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 8 files changed, 36 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index 74cbf66ccf239..f05b402c17e89 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -144,8 +144,8 @@ export const EsQueryExpression: React.FC<
@@ -183,15 +183,18 @@ export const EsQueryExpression: React.FC< + +
+ +
+
+ - } isInvalid={errors.esQuery.length > 0} error={errors.esQuery} helpText={ @@ -220,7 +223,7 @@ export const EsQueryExpression: React.FC< /> - +
@@ -211,15 +210,20 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp {Boolean(dataView?.id) && ( <> - + +
+ +
+
+ )} - + docLinks.links.alerting.esQuery, diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx index effa3fc6ed48f..8970fc247aa41 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -54,28 +54,14 @@ export const RuleCommonExpressions: React.FC = ({ }) => { return ( <> - - - -
- -
-
-
- - +
+ - - +
+ = ({ type="questionInCircle" content={i18n.translate('xpack.stackAlerts.esQuery.ui.selectSizePrompt.toolTip', { defaultMessage: - 'Specifies the number of documents to pass to the configured actions when the threshold condition is met.', + 'Specify the number of documents to pass to the configured actions when the threshold condition is met.', })} />
diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index acec24fb028a8..6037dee4543c8 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28957,7 +28957,6 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery] : doit contenir \"query\"", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "L'expression contient des erreurs.", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "L'alerte de recherche Elasticsearch \"\\{\\{alertName\\}\\}\" est active :\n\n- Valeur : \\{\\{context.value\\}\\}\n- Conditions remplies : \\{\\{context.conditions\\}\\} sur \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- Horodatage : \\{\\{context.date\\}\\}\n- Lien : \\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "Alerte lorsque des correspondances sont trouvées au cours de la dernière exécution de la requête.", "xpack.stackAlerts.esQuery.ui.conditionPrompt": "Lorsque le nombre de correspondances", "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "La fenêtre temporelle définie ci-dessous s'applique uniquement à la première vérification de règle.", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "La recherche correspond à {count} documents dans le/la/les dernier(s)/dernière(s) {window}.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2d5565bf64ce0..7c29d93ee3e15 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28940,7 +28940,6 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:「query」を含む必要があります", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearchクエリアラート'\\{\\{alertName\\}\\}'が有効です。\n\n- 値:\\{\\{context.value\\}\\}\n- 満たされた条件:\\{\\{context.conditions\\}\\} over \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- タイムスタンプ:\\{\\{context.date\\}\\}\n- リンク:\\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "前回のクエリ実行中に一致が見つかったときにアラートを発行します。", "xpack.stackAlerts.esQuery.ui.conditionPrompt": "一致数", "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "以下で定義された時間枠は最初のルールチェックにのみ適用されます。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "前回の{window}でクエリが{count}個のドキュメントと一致しました。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index ba8241b2a5a45..8e0ef4aad1f71 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28966,7 +28966,6 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:必须包含“query”", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearch 查询告警“\\{\\{alertName\\}\\}”处于活动状态:\n\n- 值:\\{\\{context.value\\}\\}\n- 满足的条件:\\{\\{context.conditions\\}\\} 超过 \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- 时间戳:\\{\\{context.date\\}\\}\n- 链接:\\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "在运行最新查询期间找到匹配项时告警。", "xpack.stackAlerts.esQuery.ui.conditionPrompt": "当匹配数目", "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "下面定义的时间窗口仅适用于第一次规则检查。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "查询在过去 {window} 匹配 {count} 个文档。", From 79d7ee926ca31ec16ce0277717775ab84ce0c242 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 14:43:01 +0200 Subject: [PATCH 42/52] [Alerting] Cleanup translations --- x-pack/plugins/translations/translations/fr-FR.json | 8 -------- x-pack/plugins/translations/translations/ja-JP.json | 8 -------- x-pack/plugins/translations/translations/zh-CN.json | 8 -------- 3 files changed, 24 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 6037dee4543c8..2f139e749e313 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28957,13 +28957,10 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery] : doit contenir \"query\"", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "L'expression contient des erreurs.", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "L'alerte de recherche Elasticsearch \"\\{\\{alertName\\}\\}\" est active :\n\n- Valeur : \\{\\{context.value\\}\\}\n- Conditions remplies : \\{\\{context.conditions\\}\\} sur \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- Horodatage : \\{\\{context.date\\}\\}\n- Lien : \\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.conditionPrompt": "Lorsque le nombre de correspondances", - "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "La fenêtre temporelle définie ci-dessous s'applique uniquement à la première vérification de règle.", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "La recherche correspond à {count} documents dans le/la/les dernier(s)/dernière(s) {window}.", "xpack.stackAlerts.esQuery.ui.queryEditor": "Éditeur de recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryError": "Erreur lors du test de la recherche : {message}", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Documentation DSL sur la recherche Elasticsearch", - "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.sizeExpression": "Taille", "xpack.stackAlerts.esQuery.ui.testQuery": "Tester la recherche", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "La requête a été exécutée.", @@ -29038,11 +29035,6 @@ "xpack.stackAlerts.indexThreshold.alertTypeTitle": "Seuil de l'index", "xpack.stackAlerts.indexThreshold.invalidComparatorErrorMessage": "thresholdComparator spécifié non valide : {comparator}", "xpack.stackAlerts.indexThreshold.invalidThreshold2ErrorMessage": "[threshold] : requiert deux éléments pour le comparateur \"{thresholdComparator}\"", - "xpack.stackAlerts.searchSource.ui.conditionPrompt": "Lorsque le nombre de correspondances", - "xpack.stackAlerts.searchSource.ui.searchQuery": "Requête de recherche", - "xpack.stackAlerts.searchSource.ui.selectSizePrompt": "Sélectionner une taille", - "xpack.stackAlerts.searchSource.ui.sizeExpression": "Taille", - "xpack.stackAlerts.searchThreshold.ui.conditionPrompt": "Lorsque le nombre de documents correspond à", "xpack.stackAlerts.threshold.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "L'expression contient des erreurs.", "xpack.stackAlerts.threshold.ui.alertType.defaultActionMessage": "l'alerte \"\\{\\{alertName\\}\\}\" est active pour le groupe \"\\{\\{context.group\\}\\}\" :\n\n- Valeur : \\{\\{context.value\\}\\}\n- Conditions remplies : \\{\\{context.conditions\\}\\} sur \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- Horodatage : \\{\\{context.date\\}\\}", "xpack.stackAlerts.threshold.ui.alertType.descriptionText": "Alerte lorsqu'une recherche agrégée atteint le seuil.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7c29d93ee3e15..59df268da12b9 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28940,13 +28940,10 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:「query」を含む必要があります", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearchクエリアラート'\\{\\{alertName\\}\\}'が有効です。\n\n- 値:\\{\\{context.value\\}\\}\n- 満たされた条件:\\{\\{context.conditions\\}\\} over \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- タイムスタンプ:\\{\\{context.date\\}\\}\n- リンク:\\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.conditionPrompt": "一致数", - "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "以下で定義された時間枠は最初のルールチェックにのみ適用されます。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "前回の{window}でクエリが{count}個のドキュメントと一致しました。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearchクエリエディター", "xpack.stackAlerts.esQuery.ui.queryError": "クエリのテストエラー:{message}", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "ElasticsearchクエリDSLドキュメント", - "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch クエリ", "xpack.stackAlerts.esQuery.ui.sizeExpression": "サイズ", "xpack.stackAlerts.esQuery.ui.testQuery": "クエリのテスト", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "クエリが実行されます。", @@ -29021,11 +29018,6 @@ "xpack.stackAlerts.indexThreshold.alertTypeTitle": "インデックスしきい値", "xpack.stackAlerts.indexThreshold.invalidComparatorErrorMessage": "無効な thresholdComparator が指定されました:{comparator}", "xpack.stackAlerts.indexThreshold.invalidThreshold2ErrorMessage": "[threshold]:「{thresholdComparator}」比較子の場合には2つの要素が必要です", - "xpack.stackAlerts.searchSource.ui.conditionPrompt": "一致数", - "xpack.stackAlerts.searchSource.ui.searchQuery": "検索クエリ", - "xpack.stackAlerts.searchSource.ui.selectSizePrompt": "サイズを選択", - "xpack.stackAlerts.searchSource.ui.sizeExpression": "サイズ", - "xpack.stackAlerts.searchThreshold.ui.conditionPrompt": "ドキュメント数が一致するとき", "xpack.stackAlerts.threshold.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。", "xpack.stackAlerts.threshold.ui.alertType.defaultActionMessage": "アラート '\\{\\{alertName\\}\\}' はグループ '\\{\\{context.group\\}\\}' でアクティブです:\n\n- 値:\\{\\{context.value\\}\\}\n- 満たされた条件:\\{\\{context.conditions\\}\\} over \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- タイムスタンプ:\\{\\{context.date\\}\\}", "xpack.stackAlerts.threshold.ui.alertType.descriptionText": "アグリゲーションされたクエリがしきい値に達したときにアラートを発行します。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 8e0ef4aad1f71..4ec8dd8bf1a82 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28966,13 +28966,10 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:必须包含“query”", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearch 查询告警“\\{\\{alertName\\}\\}”处于活动状态:\n\n- 值:\\{\\{context.value\\}\\}\n- 满足的条件:\\{\\{context.conditions\\}\\} 超过 \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- 时间戳:\\{\\{context.date\\}\\}\n- 链接:\\{\\{context.link\\}\\}", - "xpack.stackAlerts.esQuery.ui.conditionPrompt": "当匹配数目", - "xpack.stackAlerts.esQuery.ui.conditionPrompt.toolTip": "下面定义的时间窗口仅适用于第一次规则检查。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "查询在过去 {window} 匹配 {count} 个文档。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearch 查询编辑器", "xpack.stackAlerts.esQuery.ui.queryError": "测试查询时出错:{message}", "xpack.stackAlerts.esQuery.ui.queryPrompt.help": "Elasticsearch 查询 DSL 文档", - "xpack.stackAlerts.esQuery.ui.queryPrompt.label": "Elasticsearch 查询", "xpack.stackAlerts.esQuery.ui.sizeExpression": "大小", "xpack.stackAlerts.esQuery.ui.testQuery": "测试查询", "xpack.stackAlerts.esQuery.ui.testQueryIsExecuted": "已执行查询。", @@ -29047,11 +29044,6 @@ "xpack.stackAlerts.indexThreshold.alertTypeTitle": "索引阈值", "xpack.stackAlerts.indexThreshold.invalidComparatorErrorMessage": "指定的 thresholdComparator 无效:{comparator}", "xpack.stackAlerts.indexThreshold.invalidThreshold2ErrorMessage": "[threshold]:对于“{thresholdComparator}”比较运算符,必须包含两个元素", - "xpack.stackAlerts.searchSource.ui.conditionPrompt": "当匹配数目", - "xpack.stackAlerts.searchSource.ui.searchQuery": "搜索查询", - "xpack.stackAlerts.searchSource.ui.selectSizePrompt": "选择大小", - "xpack.stackAlerts.searchSource.ui.sizeExpression": "大小", - "xpack.stackAlerts.searchThreshold.ui.conditionPrompt": "文档数量匹配时", "xpack.stackAlerts.threshold.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。", "xpack.stackAlerts.threshold.ui.alertType.defaultActionMessage": "组“\\{\\{context.group\\}\\}”的告警“\\{\\{alertName\\}\\}”处于活动状态:\n\n- 值:\\{\\{context.value\\}\\}\n- 满足的条件:\\{\\{context.conditions\\}\\} 超过 \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- 时间戳:\\{\\{context.date\\}\\}", "xpack.stackAlerts.threshold.ui.alertType.descriptionText": "聚合查询达到阈值时告警。", From 9452d3d486205851a15de01e53c986ae45ff39b2 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 14:50:08 +0200 Subject: [PATCH 43/52] [Alerting] Unify labels key --- .../alert_types/es_query/expression/es_query_expression.tsx | 4 ++-- .../es_query/expression/search_source_expression_form.tsx | 4 ++-- .../rule_common_expressions/rule_common_expressions.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index f05b402c17e89..ca3dbf73fc038 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -144,7 +144,7 @@ export const EsQueryExpression: React.FC<
@@ -186,7 +186,7 @@ export const EsQueryExpression: React.FC<
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 33d47abe5c443..9553877d75df3 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -193,7 +193,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
@@ -213,7 +213,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx index 8970fc247aa41..4ba4992386bd4 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -57,7 +57,7 @@ export const RuleCommonExpressions: React.FC = ({
From e20272512154a6c86939b7abea654483e22f9b6a Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 14:56:31 +0200 Subject: [PATCH 44/52] [Alerting] Update copy --- .../alert_types/es_query/expression/es_query_expression.tsx | 4 ++-- .../rule_common_expressions/rule_common_expressions.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx index ca3dbf73fc038..6432ba9a324a8 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/es_query_expression.tsx @@ -145,7 +145,7 @@ export const EsQueryExpression: React.FC<
@@ -187,7 +187,7 @@ export const EsQueryExpression: React.FC<
diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx index 4ba4992386bd4..187d539025eb3 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -90,7 +90,7 @@ export const RuleCommonExpressions: React.FC = ({
From f5a8a311b58c299483331cd35d45add77295ee5b Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 15:13:13 +0200 Subject: [PATCH 45/52] [Alerting] Update copy key --- .../es_query/expression/search_source_expression_form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 9553877d75df3..fc8b5e30a7b84 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -193,7 +193,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
@@ -213,7 +213,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp
From 0aae0128b27a8b5927c894bc8b5fef8aa8491fca Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 30 Jun 2022 16:37:56 +0200 Subject: [PATCH 46/52] [Alerting] Bring back the original label --- .../plugins/stack_alerts/public/alert_types/es_query/index.ts | 4 ++-- x-pack/plugins/translations/translations/fr-FR.json | 1 + x-pack/plugins/translations/translations/ja-JP.json | 1 + x-pack/plugins/translations/translations/zh-CN.json | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts b/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts index 476b8d6c27956..fe57801150526 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/index.ts @@ -21,8 +21,8 @@ export function getAlertType(alerting: AlertingSetup): RuleTypeModel docLinks.links.alerting.esQuery, diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 2f139e749e313..d1b8fb2d34eef 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -28957,6 +28957,7 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery] : doit contenir \"query\"", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "L'expression contient des erreurs.", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "L'alerte de recherche Elasticsearch \"\\{\\{alertName\\}\\}\" est active :\n\n- Valeur : \\{\\{context.value\\}\\}\n- Conditions remplies : \\{\\{context.conditions\\}\\} sur \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- Horodatage : \\{\\{context.date\\}\\}\n- Lien : \\{\\{context.link\\}\\}", + "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "Alerte lorsque des correspondances sont trouvées au cours de la dernière exécution de la requête.", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "La recherche correspond à {count} documents dans le/la/les dernier(s)/dernière(s) {window}.", "xpack.stackAlerts.esQuery.ui.queryEditor": "Éditeur de recherche Elasticsearch", "xpack.stackAlerts.esQuery.ui.queryError": "Erreur lors du test de la recherche : {message}", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 59df268da12b9..9bee4c17bc844 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -28940,6 +28940,7 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:「query」を含む必要があります", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "下の表現のエラーを修正してください。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearchクエリアラート'\\{\\{alertName\\}\\}'が有効です。\n\n- 値:\\{\\{context.value\\}\\}\n- 満たされた条件:\\{\\{context.conditions\\}\\} over \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- タイムスタンプ:\\{\\{context.date\\}\\}\n- リンク:\\{\\{context.link\\}\\}", + "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "前回のクエリ実行中に一致が見つかったときにアラートを発行します。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "前回の{window}でクエリが{count}個のドキュメントと一致しました。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearchクエリエディター", "xpack.stackAlerts.esQuery.ui.queryError": "クエリのテストエラー:{message}", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 4ec8dd8bf1a82..489968d735b76 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -28966,6 +28966,7 @@ "xpack.stackAlerts.esQuery.missingEsQueryErrorMessage": "[esQuery]:必须包含“query”", "xpack.stackAlerts.esQuery.ui.alertParams.fixErrorInExpressionBelowValidationMessage": "表达式包含错误。", "xpack.stackAlerts.esQuery.ui.alertType.defaultActionMessage": "Elasticsearch 查询告警“\\{\\{alertName\\}\\}”处于活动状态:\n\n- 值:\\{\\{context.value\\}\\}\n- 满足的条件:\\{\\{context.conditions\\}\\} 超过 \\{\\{params.timeWindowSize\\}\\}\\{\\{params.timeWindowUnit\\}\\}\n- 时间戳:\\{\\{context.date\\}\\}\n- 链接:\\{\\{context.link\\}\\}", + "xpack.stackAlerts.esQuery.ui.alertType.descriptionText": "在运行最新查询期间找到匹配项时告警。", "xpack.stackAlerts.esQuery.ui.numQueryMatchesText": "查询在过去 {window} 匹配 {count} 个文档。", "xpack.stackAlerts.esQuery.ui.queryEditor": "Elasticsearch 查询编辑器", "xpack.stackAlerts.esQuery.ui.queryError": "测试查询时出错:{message}", From 4adac034a28c362d61f19becd83f185b5f0677de Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 4 Jul 2022 14:04:10 +0200 Subject: [PATCH 47/52] [Alerting] Update after the merge --- .../es_query/expression/search_source_expression_form.tsx | 1 + .../rule_common_expressions/rule_common_expressions.tsx | 8 +++++++- .../es_query/test_query_row/test_query_row.tsx | 6 +++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx index 80a0fc73b7746..1a6ad28eea9fe 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/expression/search_source_expression_form.tsx @@ -274,6 +274,7 @@ export const SearchSourceExpressionForm = (props: SearchSourceExpressionFormProp errors={errors} hasValidationErrors={hasExpressionValidationErrors(ruleParams) || !dataView} onTestFetch={onTestFetch} + onCopyQuery={onCopyQuery} /> diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx index 187d539025eb3..684b340170139 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/rule_common_expressions/rule_common_expressions.tsx @@ -35,6 +35,7 @@ export interface RuleCommonExpressionsProps { onChangeWindowUnit: Parameters[0]['onChangeWindowUnit']; onChangeSizeValue: Parameters[0]['onChangeSelectedValue']; onTestFetch: TestQueryRowProps['fetch']; + onCopyQuery?: TestQueryRowProps['copyQuery']; } export const RuleCommonExpressions: React.FC = ({ @@ -51,6 +52,7 @@ export const RuleCommonExpressions: React.FC = ({ onChangeWindowUnit, onChangeSizeValue, onTestFetch, + onCopyQuery, }) => { return ( <> @@ -120,7 +122,11 @@ export const RuleCommonExpressions: React.FC = ({ onChangeSelectedValue={onChangeSizeValue} /> - + ); }; diff --git a/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx index a603771fdb73e..04eeb86945cb3 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/es_query/test_query_row/test_query_row.tsx @@ -24,7 +24,11 @@ export interface TestQueryRowProps { hasValidationErrors: boolean; } -export const TestQueryRow: React.FC = ({ fetch, copyQuery, hasValidationErrors }) => { +export const TestQueryRow: React.FC = ({ + fetch, + copyQuery, + hasValidationErrors, +}) => { const { onTestQuery, testQueryResult, testQueryError, testQueryLoading } = useTestQuery(fetch); const [copiedMessage, setCopiedMessage] = useState(null); From 20a2ad3f94153483cf1a364fbb46ad3fffb3eb43 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 4 Jul 2022 14:36:16 +0200 Subject: [PATCH 48/52] [Alerting] Update validation message --- .../stack_alerts/public/alert_types/es_query/validation.test.ts | 2 +- .../stack_alerts/public/alert_types/es_query/validation.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 c09297c023358..9c485455cf19c 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,7 +13,7 @@ describe('expression params validation', () => { const initialParams: EsQueryAlertParams = {} as EsQueryAlertParams; expect(validateExpression(initialParams).errors.searchType.length).toBeGreaterThan(0); - expect(validateExpression(initialParams).errors.searchType[0]).toBe('Query is required.'); + expect(validateExpression(initialParams).errors.searchType[0]).toBe('Query type is required.'); }); test('if index property is invalid should return proper error message', () => { 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 e070646443057..9e1e0df84052c 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 @@ -21,7 +21,7 @@ export const validateExpression = (ruleParams: EsQueryAlertParams): ValidationRe if (!('index' in ruleParams) && !ruleParams.searchType) { errors.searchType.push( i18n.translate('xpack.stackAlerts.esQuery.ui.validation.error.requiredSearchType', { - defaultMessage: 'Query is required.', + defaultMessage: 'Query type is required.', }) ); From 12ec63edb65247c74cf7eb29ab92ddb4d868c780 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 4 Jul 2022 14:54:25 +0200 Subject: [PATCH 49/52] [Alerting] Update styles for Create a data view button --- .../alert_types/components/data_view_select_popover.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index 58c054081660d..03c9459cadc8d 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -17,6 +17,7 @@ import { EuiPopover, EuiPopoverFooter, EuiPopoverTitle, + useEuiPaddingCSS, } from '@elastic/eui'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; import { DataViewListItem } from '@kbn/data-views-plugin/public'; @@ -76,6 +77,8 @@ export const DataViewSelectPopover: React.FunctionComponent
{createDataView && ( - + { From 27451c23c59897b06ee80cd59fa8d6bf6387edd2 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Mon, 4 Jul 2022 15:26:27 +0200 Subject: [PATCH 50/52] [Alerting] Add message about missing privilieges --- .../components/data_view_select_popover.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index 03c9459cadc8d..bd6259dd3095a 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -7,6 +7,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButtonEmpty, EuiButtonIcon, @@ -17,6 +18,7 @@ import { EuiPopover, EuiPopoverFooter, EuiPopoverTitle, + EuiText, useEuiPaddingCSS, } from '@elastic/eui'; import { DataViewsList } from '@kbn/unified-search-plugin/public'; @@ -144,7 +146,7 @@ export const DataViewSelectPopover: React.FunctionComponent
- {createDataView && ( + {createDataView ? ( + ) : ( + + + + + )} From fd61f430a72c243b98fdcbc40d0f23da2a53bf3e Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Wed, 6 Jul 2022 10:53:08 +0200 Subject: [PATCH 51/52] [Alerting] Reduce padding in data view selector --- .../components/data_view_select_popover.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index bd6259dd3095a..e615ba33befc0 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -136,7 +136,15 @@ export const DataViewSelectPopover: React.FunctionComponent
- + { From 5c27116c5ade3c53736253babc22c16559419fd6 Mon Sep 17 00:00:00 2001 From: Julia Rechkunova Date: Thu, 7 Jul 2022 09:22:23 +0200 Subject: [PATCH 52/52] [Alerting] Update copy --- .../public/alert_types/components/data_view_select_popover.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx index e615ba33befc0..fad3230e57f1e 100644 --- a/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/alert_types/components/data_view_select_popover.tsx @@ -178,7 +178,7 @@ export const DataViewSelectPopover: React.FunctionComponent