diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts deleted file mode 100644 index 5879e2a256cc..000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act, renderHook } from '@testing-library/react-hooks'; -import { useSetFieldValueWithCallback } from './use_set_field_value_cb'; - -const initialValue = 'initial value'; -const newValue = 'new value'; -const callback = jest.fn(); -const initialProps = { field: 'theField', setFieldValue: () => {}, value: initialValue }; - -describe('set field value callback', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it('invokes the callback after value is set', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender({ ...initialProps, value: newValue }); - expect(callback).toHaveBeenCalled(); - }); - it('invokes the callback after value is set to equal value', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(initialValue, callback); - }); - rerender(); - expect(callback).toHaveBeenCalled(); - }); - it('does not invoke the callback if value does not update', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender(); - expect(callback).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts deleted file mode 100644 index c067e1747b4f..000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -export const useSetFieldValueWithCallback = ({ - field, - setFieldValue, - value, -}: { - field: string; - value: unknown; - setFieldValue: FormHook['setFieldValue']; -}) => { - const isWaitingRef = useRef(false); - const valueRef = useRef(); - const [callback, setCallback] = useState<() => void>(() => null); - - useEffect(() => { - if (isWaitingRef.current && value === valueRef.current) { - isWaitingRef.current = false; - valueRef.current = undefined; - callback(); - } - }, [value, callback]); - - return useCallback( - (v: unknown, cb: () => void) => { - setFieldValue(field, v); - - setCallback(() => cb); - valueRef.current = v; - isWaitingRef.current = true; - }, - [field, setFieldValue] - ); -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx index e2a43a85433c..530405d12724 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx @@ -13,10 +13,10 @@ import type { FieldConfig } from '../../../../shared_imports'; import { UseField } from '../../../../shared_imports'; import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import { QueryBarField } from '../../../rule_creation_ui/components/query_bar_field'; +import { esqlQueryRequiredValidatorFactory } from './validators/esql_query_required_validator_factory'; import { esqlQueryValidatorFactory } from './validators/esql_query_validator_factory'; import { EsqlInfoIcon } from './esql_info_icon'; import * as i18n from './translations'; -import { esqlQueryRequiredValidatorFactory } from './validators/esql_query_required_validator_factory'; interface EsqlQueryEditProps { path: string; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx index 2793bb80eb97..21754747918c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx @@ -26,7 +26,6 @@ import type { FieldSpec } from '@kbn/data-plugin/common'; import type { SavedQuery } from '@kbn/data-plugin/public'; import type { DataViewBase } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useSetFieldValueWithCallback } from '../../../../common/utils/use_set_field_value_cb'; import type { SetRuleQuery } from '../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { useRuleFromTimeline } from '../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; @@ -196,12 +195,6 @@ const StepDefineRuleComponent: FC = ({ const alertSuppressionUpsellingMessage = useUpsellingMessage('alert_suppression_rule_form'); const { getFields, reset, setFieldValue } = form; - const setRuleTypeCallback = useSetFieldValueWithCallback({ - field: 'ruleType', - value: ruleType, - setFieldValue, - }); - // Callback for when user toggles between Data Views and Index Patterns const onChangeDataSource = useCallback( (optionId: string) => { @@ -258,19 +251,26 @@ const StepDefineRuleComponent: FC = ({ const handleSetRuleFromTimeline = useCallback( ({ index: timelineIndex, queryBar: timelineQueryBar, eqlOptions }) => { const setQuery = () => { + setPersistentEqlQuery(timelineQueryBar); setFieldValue('index', timelineIndex); setFieldValue('queryBar', timelineQueryBar); }; if (timelineQueryBar.query.language === 'eql') { - setPersistentEqlQuery(timelineQueryBar); - setPersistentEqlOptions(eqlOptions ?? {}); - setRuleTypeCallback('eql', setQuery); - setFieldValue('eqlOptions', eqlOptions ?? {}); + setFieldValue('ruleType', 'eql'); + + // Forms needs to be re-rendered with a new rule type first + // setTimeout is used to delay setting rule type specific values. + // Without that form turns out in an "impossible" state. + setTimeout(() => { + setPersistentEqlOptions(eqlOptions ?? {}); + setQuery(); + setFieldValue('eqlOptions', eqlOptions ?? {}); + }); } else { setQuery(); } }, - [setFieldValue, setRuleTypeCallback, setPersistentEqlQuery, setPersistentEqlOptions] + [setFieldValue, setPersistentEqlQuery, setPersistentEqlOptions] ); const { onOpenTimeline, loading: timelineQueryLoading } = @@ -620,20 +620,17 @@ const StepDefineRuleComponent: FC = ({ <> {isEqlRule(ruleType) ? ( - <> - - + ) : isEsqlRule(ruleType) ? (