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 6d4e4c6cb381b..06775dbe091b7 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 @@ -88,7 +88,7 @@ import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common import { DurationInput } from '../duration_input'; import { MINIMUM_LICENSE_FOR_SUPPRESSION } from '../../../../../common/detection_engine/constants'; import { useUpsellingMessage } from '../../../../common/hooks/use_upselling'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; +import { useAlertSuppression } from '../../../rule_management/hooks/use_alert_suppression'; const CommonUseField = getUseField({ component: Field }); @@ -178,6 +178,7 @@ const StepDefineRuleComponent: FC = ({ thresholdFields, enableThresholdSuppression, }) => { + const { isSuppressionEnabled } = useAlertSuppression(ruleType); const mlCapabilities = useMlCapabilities(); const [openTimelineSearch, setOpenTimelineSearch] = useState(false); const [indexModified, setIndexModified] = useState(false); @@ -186,10 +187,6 @@ const StepDefineRuleComponent: FC = ({ const esqlQueryRef = useRef(undefined); - const isAlertSuppressionForIndicatorMatchRuleEnabled = useIsExperimentalFeatureEnabled( - 'alertSuppressionForIndicatorMatchRuleEnabled' - ); - const isAlertSuppressionLicenseValid = license.isAtLeast(MINIMUM_LICENSE_FOR_SUPPRESSION); const isThresholdRule = getIsThresholdRule(ruleType); @@ -813,11 +810,6 @@ const StepDefineRuleComponent: FC = ({ [isUpdateView, mlCapabilities] ); - const isAlertSuppressionEnabled = - isQueryRule(ruleType) || - isThresholdRule || - (isAlertSuppressionForIndicatorMatchRuleEnabled && isThreatMatchRule(ruleType)); - return ( <> @@ -989,7 +981,7 @@ const StepDefineRuleComponent: FC = ({ - + = ({ = ({ = ({ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 80848da74c79c..475d2e0de69a3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -54,7 +54,7 @@ import { TechnicalPreviewBadge } from '../../../../common/components/technical_p import { BadgeList } from './badge_list'; import { DEFAULT_DESCRIPTION_LIST_COLUMN_WIDTHS } from './constants'; import * as i18n from './translations'; -import { useAlertSuppression } from './use_alert_suppression'; +import { useAlertSuppression } from '../../hooks/use_alert_suppression'; interface SavedQueryNameProps { savedQueryName: string; @@ -738,7 +738,7 @@ export const RuleDefinitionSection = ({ ruleType: rule.type, }); - const { isSuppressionEnabled } = useAlertSuppression(rule); + const { isSuppressionEnabled } = useAlertSuppression(rule.type); const definitionSectionListItems = prepareDefinitionSectionListItems( rule, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.test.tsx deleted file mode 100644 index 0c354286af408..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.test.tsx +++ /dev/null @@ -1,55 +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 { renderHook } from '@testing-library/react-hooks'; -import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; -import { SuppressibleAlertRules } from '../../../../../common/detection_engine/constants'; - -import { useAlertSuppression } from './use_alert_suppression'; -import type { RuleResponse } from '../../../../../common/api/detection_engine'; - -jest.mock('../../../../common/hooks/use_experimental_features', () => ({ - useIsExperimentalFeatureEnabled: (featureFlagName: string) => - featureFlagName === 'alertSuppressionForIndicatorMatchRuleEnabled', -})); - -describe('useAlertSuppression', () => { - it('should return the correct isSuppressionEnabled value if rule Type exists in SuppressibleAlertRules and Feature Flag is enabled', () => { - const rule: Partial = { - type: SuppressibleAlertRules.THREAT_MATCH, - }; - - const { result } = renderHook(() => useAlertSuppression(rule)); - - expect(result.current.isSuppressionEnabled).toBe(true); - }); - - it('should return the correct isSuppressionEnabled value if rule Type exists in SuppressibleAlertRules', () => { - const rule: Partial = { - type: SuppressibleAlertRules.QUERY, - }; - - const { result } = renderHook(() => useAlertSuppression(rule)); - - expect(result.current.isSuppressionEnabled).toBe(true); - }); - - it('should return false if rule type is not set', () => { - const rule: Partial = {}; - - const { result } = renderHook(() => useAlertSuppression(rule)); - expect(result.current.isSuppressionEnabled).toBe(false); - }); - - it('should return false if rule type is not THREAT_MATCH', () => { - const rule: Partial = { - type: 'OTHER_RULE_TYPE' as Type, - }; - const { result } = renderHook(() => useAlertSuppression(rule)); - - expect(result.current.isSuppressionEnabled).toBe(false); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.tsx deleted file mode 100644 index ad30f49fb64b2..0000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/use_alert_suppression.tsx +++ /dev/null @@ -1,34 +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 { useCallback } from 'react'; -import { isSuppressibleAlertRule } from '../../../../../common/detection_engine/utils'; -import { SuppressibleAlertRules } from '../../../../../common/detection_engine/constants'; -import type { ExperimentalFeatures } from '../../../../../common'; -import { useIsExperimentalFeatureEnabled } from '../../../../common/hooks/use_experimental_features'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; - -export interface UseAlertSuppressionReturn { - isSuppressionEnabled: boolean; -} - -export const useAlertSuppression = (rule: Partial): UseAlertSuppressionReturn => { - const IsRuleFeatureFlagEnabled = (ruleFFName: keyof ExperimentalFeatures) => - useIsExperimentalFeatureEnabled(ruleFFName); - - const isSuppressionEnabledForRuleType = useCallback(() => { - if (!rule.type) return false; - - if (rule.type === SuppressibleAlertRules.THREAT_MATCH) - return IsRuleFeatureFlagEnabled('alertSuppressionForIndicatorMatchRuleEnabled'); - - return isSuppressibleAlertRule(rule.type); - }, [rule.type]); - - return { - isSuppressionEnabled: isSuppressionEnabledForRuleType(), - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.test.tsx new file mode 100644 index 0000000000000..226f4b920b163 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.test.tsx @@ -0,0 +1,51 @@ +/* + * 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 { renderHook } from '@testing-library/react-hooks'; +import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { SuppressibleAlertRules } from '../../../../common/detection_engine/constants'; +import * as useIsExperimentalFeatureEnabledMock from '@kbn/security-solution-plugin/public/common/hooks/use_experimental_features'; +import { useAlertSuppression } from './use_alert_suppression'; + +describe('useAlertSuppression', () => { + it('should return the correct isSuppressionEnabled value if rule Type exists in SuppressibleAlertRules and Feature Flag is enabled', () => { + jest + .spyOn(useIsExperimentalFeatureEnabledMock, 'useIsExperimentalFeatureEnabled') + .mockImplementation((featureFlagName: string) => { + return featureFlagName === 'alertSuppressionForIndicatorMatchRuleEnabled'; + }); + const { result } = renderHook(() => useAlertSuppression(SuppressibleAlertRules.THREAT_MATCH)); + + expect(result.current.isSuppressionEnabled).toBe(true); + }); + it('should return the correct isSuppressionEnabled value if rule Type exists in SuppressibleAlertRules and Feature Flag is disabled', () => { + jest + .spyOn(useIsExperimentalFeatureEnabledMock, 'useIsExperimentalFeatureEnabled') + .mockImplementation((featureFlagName: string) => { + return featureFlagName !== 'alertSuppressionForIndicatorMatchRuleEnabled'; + }); + const { result } = renderHook(() => useAlertSuppression(SuppressibleAlertRules.THREAT_MATCH)); + + expect(result.current.isSuppressionEnabled).toBe(false); + }); + + it('should return the correct isSuppressionEnabled value if rule Type exists in SuppressibleAlertRules', () => { + const { result } = renderHook(() => useAlertSuppression(SuppressibleAlertRules.QUERY)); + + expect(result.current.isSuppressionEnabled).toBe(true); + }); + + it('should return false if rule type is not set', () => { + const { result } = renderHook(() => useAlertSuppression()); + expect(result.current.isSuppressionEnabled).toBe(false); + }); + + it('should return false if rule type is not THREAT_MATCH', () => { + const { result } = renderHook(() => useAlertSuppression('OTHER_RULE_TYPE' as Type)); + + expect(result.current.isSuppressionEnabled).toBe(false); + }); +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.tsx new file mode 100644 index 0000000000000..3cd487b8c628e --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/hooks/use_alert_suppression.tsx @@ -0,0 +1,32 @@ +/* + * 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 { useCallback } from 'react'; +import { Type } from '@kbn/securitysolution-io-ts-alerting-types'; +import { isSuppressibleAlertRule } from '../../../../common/detection_engine/utils'; +import { SuppressibleAlertRules } from '../../../../common/detection_engine/constants'; +import { useIsExperimentalFeatureEnabled } from '../../../common/hooks/use_experimental_features'; +export interface UseAlertSuppressionReturn { + isSuppressionEnabled: boolean; +} + +export const useAlertSuppression = (ruleType?: Type): UseAlertSuppressionReturn => { + const isThreatMatchRuleFFEnabled = useIsExperimentalFeatureEnabled( + 'alertSuppressionForIndicatorMatchRuleEnabled' + ); + + const isSuppressionEnabledForRuleType = useCallback(() => { + if (!ruleType) return false; + + if (ruleType === SuppressibleAlertRules.THREAT_MATCH) return isThreatMatchRuleFFEnabled; + + return isSuppressibleAlertRule(ruleType); + }, [ruleType]); + + return { + isSuppressionEnabled: isSuppressionEnabledForRuleType(), + }; +};