diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/common/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/common/translations.ts index 2ee4d99f193ce..92a6176d79296 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/common/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/common/translations.ts @@ -394,7 +394,7 @@ export const BULK_FILL_RULE_GAPS_CONFIRMATION_CONFIRM = i18n.translate( export const BULK_MANUAL_RULE_RUN_LIMIT_ERROR_TITLE = i18n.translate( 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkManualRuleRunLimitErrorMessage', { - defaultMessage: 'This action can only be applied', + defaultMessage: 'Cannot execute the bulk action', } ); @@ -415,6 +415,30 @@ export const BULK_MANUAL_RULE_RUN_LIMIT_ERROR_CLOSE_BUTTON = i18n.translate( } ); +export const BULK_FILL_RULE_GAPS_LIMIT_ERROR_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkFillRuleGapsRuleLimitErrorMessage', + { + defaultMessage: 'Cannot execute the bulk action', + } +); + +export const BULK_FILL_RULE_GAPS_LIMIT_ERROR_MESSAGE = (rulesCount: number) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkFillRuleGapsRuleLimitErrorTitle', + { + values: { rulesCount }, + defaultMessage: + 'Cannot schedule gap fills for more than {rulesCount, plural, =1 {# rule} other {# rules}}.', + } + ); + +export const BULK_FILL_RULE_GAPS_LIMIT_ERROR_CLOSE_BUTTON = i18n.translate( + 'xpack.securitySolution.detectionEngine.rules.allRules.bulkActions.bulkFillRuleGapsRuleLimitErrorCloseButton', + { + defaultMessage: 'Close', + } +); + export const BULK_EDIT_FLYOUT_FORM_SAVE = i18n.translate( 'xpack.securitySolution.detectionEngine.components.allRules.bulkActions.bulkEditFlyoutForm.saveButtonLabel', { diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/index.tsx index 6470989fc5747..6ce9f5a3d1602 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/index.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/index.tsx @@ -42,7 +42,7 @@ const BulkFillRuleGapsModalComponent = ({ , ]; if (rulesCount > 1) { diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/translations.ts b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/translations.ts index 3eab8e3f874c4..7e13b3f280577 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/translations.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_gaps/components/bulk_fill_rule_gaps/translations.ts @@ -37,7 +37,7 @@ export const BULK_FILL_RULE_GAPS_END_AT_TITLE = i18n.translate( export const BULK_FILL_RULE_GAPS_CONFIRM_BUTTON = i18n.translate( 'xpack.securitySolution.bulkFillRuleGapsModal.confirmButton', { - defaultMessage: 'Run', + defaultMessage: 'Schedule gap fills', } ); @@ -69,7 +69,7 @@ export const BULK_FILL_RULE_GAPS_START_DATE_OUT_OF_RANGE_ERROR = (maxDaysLookbac 'Rule gap fills cannot be scheduled earlier than {maxDaysLookback, plural, =1 {# day} other {# days}} ago', }); -export const BULK_FILL_RULE_GAPS_NOTIFIACTIONS_LIMITATIONS = i18n.translate( +export const BULK_FILL_RULE_GAPS_NOTIFICATIONS_LIMITATIONS = i18n.translate( 'xpack.securitySolution.bulkFillRuleGapsModal.notificationsLimitations', { defaultMessage: diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_limit_error_modal.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_limit_error_modal.tsx new file mode 100644 index 0000000000000..1e471b7c13815 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_action_rule_limit_error_modal.tsx @@ -0,0 +1,48 @@ +/* + * 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 { + EuiButton, + EuiModal, + EuiModalBody, + EuiModalFooter, + EuiModalHeader, + EuiModalHeaderTitle, +} from '@elastic/eui'; + +interface BulkManualRuleRunRulesLimitErrorModalProps { + onClose: () => void; + text: { + title: string; + message: string; + closeButton: string; + }; +} + +const BulkActionRuleLimitErrorModalComponent = ({ + onClose, + text, +}: BulkManualRuleRunRulesLimitErrorModalProps) => { + return ( + + + {text.title} + + {text.message} + + + {text.closeButton} + + + + ); +}; + +export const BulkActionRuleLimitErrorModal = React.memo(BulkActionRuleLimitErrorModalComponent); + +BulkActionRuleLimitErrorModal.displayName = 'BulkActionRuleLimitErrorModal'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_manual_rule_run_limit_error_modal.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_manual_rule_run_limit_error_modal.tsx index 6a4980c52061a..03cffedc9f9cb 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_manual_rule_run_limit_error_modal.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_manual_rule_run_limit_error_modal.tsx @@ -6,41 +6,24 @@ */ import React from 'react'; -import { - EuiButton, - EuiModal, - EuiModalBody, - EuiModalFooter, - EuiModalHeader, - EuiModalHeaderTitle, -} from '@elastic/eui'; - import { MAX_MANUAL_RULE_RUN_BULK_SIZE } from '../../../../../../common/constants'; import * as i18n from '../../../../common/translations'; +import { BulkActionRuleLimitErrorModal } from './bulk_action_rule_limit_error_modal'; interface BulkManualRuleRunRulesLimitErrorModalProps { onClose: () => void; } +const text = { + title: i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_TITLE, + message: i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_MESSAGE(MAX_MANUAL_RULE_RUN_BULK_SIZE), + closeButton: i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_CLOSE_BUTTON, +}; + const BulkManualRuleRunLimitErrorModalComponent = ({ onClose, }: BulkManualRuleRunRulesLimitErrorModalProps) => { - // if the amount of selected rules is more than the limit, modal window the appropriate error will be displayed - return ( - - - {i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_TITLE} - - - {i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_MESSAGE(MAX_MANUAL_RULE_RUN_BULK_SIZE)} - - - - {i18n.BULK_MANUAL_RULE_RUN_LIMIT_ERROR_CLOSE_BUTTON} - - - - ); + return ; }; export const BulkManualRuleRunLimitErrorModal = React.memo( diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_schedule_gap_fills_rule_limit_error_modal.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_schedule_gap_fills_rule_limit_error_modal.tsx new file mode 100644 index 0000000000000..853b9198e2ad7 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/bulk_schedule_gap_fills_rule_limit_error_modal.tsx @@ -0,0 +1,33 @@ +/* + * 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 { MAX_BULK_FILL_RULE_GAPS_BULK_SIZE } from '../../../../../../common/constants'; +import * as i18n from '../../../../common/translations'; +import { BulkActionRuleLimitErrorModal } from './bulk_action_rule_limit_error_modal'; + +interface BulkManualRuleRunRulesLimitErrorModalProps { + onClose: () => void; +} + +const text = { + title: i18n.BULK_FILL_RULE_GAPS_LIMIT_ERROR_TITLE, + message: i18n.BULK_FILL_RULE_GAPS_LIMIT_ERROR_MESSAGE(MAX_BULK_FILL_RULE_GAPS_BULK_SIZE), + closeButton: i18n.BULK_FILL_RULE_GAPS_LIMIT_ERROR_CLOSE_BUTTON, +}; + +const BulkFillRuleGapsRuleLimitErrorModalComponent = ({ + onClose, +}: BulkManualRuleRunRulesLimitErrorModalProps) => { + return ; +}; + +export const BulkFillRuleGapsRuleLimitErrorModal = React.memo( + BulkFillRuleGapsRuleLimitErrorModalComponent +); + +BulkFillRuleGapsRuleLimitErrorModal.displayName = 'BulkFillRuleGapsRuleLimitErrorModal'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx index 696f92f97ab57..d8a4b43f88474 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/bulk_actions/use_bulk_actions.tsx @@ -14,7 +14,10 @@ import { euiThemeVars } from '@kbn/ui-theme'; import React, { useCallback, useMemo } from 'react'; import { BulkFillRuleGapsEventTypes } from '../../../../../common/lib/telemetry/events/bulk_fill_rule_gaps/types'; import { ML_RULES_UNAVAILABLE } from './translations'; -import { MAX_MANUAL_RULE_RUN_BULK_SIZE } from '../../../../../../common/constants'; +import { + MAX_BULK_FILL_RULE_GAPS_BULK_SIZE, + MAX_MANUAL_RULE_RUN_BULK_SIZE, +} from '../../../../../../common/constants'; import type { TimeRange } from '../../../../rule_gaps/types'; import { useKibana } from '../../../../../common/lib/kibana'; import { useUserPrivileges } from '../../../../../common/components/user_privileges'; @@ -66,6 +69,7 @@ interface UseBulkActionsArgs { showManualRuleRunConfirmation: () => Promise; showBulkFillRuleGapsConfirmation: () => Promise; showManualRuleRunLimitError: () => void; + showBulkFillRuleGapsRuleLimitError: () => void; completeBulkEditForm: ( bulkActionEditType: BulkActionEditType ) => Promise; @@ -80,6 +84,7 @@ export const useBulkActions = ({ showManualRuleRunConfirmation, showBulkFillRuleGapsConfirmation, showManualRuleRunLimitError, + showBulkFillRuleGapsRuleLimitError, completeBulkEditForm, executeBulkActionsDryRun, }: UseBulkActionsArgs) => { @@ -314,8 +319,8 @@ export const useBulkActions = ({ setIsPreflightInProgress(false); - if ((dryRunResult?.succeededRulesCount ?? 0) > MAX_MANUAL_RULE_RUN_BULK_SIZE) { - showManualRuleRunLimitError(); + if ((dryRunResult?.succeededRulesCount ?? 0) > MAX_BULK_FILL_RULE_GAPS_BULK_SIZE) { + showBulkFillRuleGapsRuleLimitError(); return; } @@ -776,6 +781,7 @@ export const useBulkActions = ({ showBulkDuplicateConfirmation, showManualRuleRunConfirmation, showManualRuleRunLimitError, + showBulkFillRuleGapsRuleLimitError, clearRulesSelection, confirmDeletion, bulkExport, diff --git a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx index 212b446b506e4..ac0e93203c807 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx +++ b/x-pack/solutions/security/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_tables.tsx @@ -49,6 +49,7 @@ import { BulkEditDeleteAlertSuppressionConfirmation } from './bulk_actions/bulk_ import { BulkActionEditTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { BulkFillRuleGapsModal } from '../../../rule_gaps/components/bulk_fill_rule_gaps'; import { useBulkFillRuleGapsConfirmation } from '../../../rule_gaps/components/bulk_fill_rule_gaps/use_bulk_fill_rule_gaps_confirmation'; +import { BulkFillRuleGapsRuleLimitErrorModal } from './bulk_actions/bulk_schedule_gap_fills_rule_limit_error_modal'; const INITIAL_SORT_FIELD = 'enabled'; @@ -142,6 +143,12 @@ export const RulesTables = React.memo(({ selectedTab }) => { hideManualRuleRunLimitError, ] = useBoolState(); + const [ + isBulkFillRuleGapsRuleLimitErrorVisible, + showBulkFillRuleGapsRuleLimitError, + hideBulkFillRuleGapsRuleLimitError, + ] = useBoolState(); + const { bulkEditActionType, isBulkEditFlyoutVisible, @@ -160,6 +167,7 @@ export const RulesTables = React.memo(({ selectedTab }) => { showManualRuleRunConfirmation, showBulkFillRuleGapsConfirmation, showManualRuleRunLimitError, + showBulkFillRuleGapsRuleLimitError, completeBulkEditForm, executeBulkActionsDryRun, }); @@ -314,6 +322,9 @@ export const RulesTables = React.memo(({ selectedTab }) => { {isManualRuleRunLimitErrorVisible && ( )} + {isBulkFillRuleGapsRuleLimitErrorVisible && ( + + )} {isBulkActionConfirmationVisible && bulkAction && (