Skip to content

Commit

Permalink
Ram 145739 use bulk enable disable in UI (#145928)
Browse files Browse the repository at this point in the history
Resolves: #145739

## Summary

In this PR I am enabling Enable and Disable in menu when Select all is
chosen. And trigger new bulk enable/disable API when Enable/Disable
option will be chosen.

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
guskovaue and kibanamachine authored Nov 28, 2022
1 parent 19413b7 commit c5f2072
Show file tree
Hide file tree
Showing 16 changed files with 847 additions and 174 deletions.
2 changes: 0 additions & 2 deletions x-pack/plugins/translations/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -32393,8 +32393,6 @@
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.disableAllTitle": "Désactiver",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.enableAllTitle": "Activer",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDeleteRulesMessage": "Impossible de supprimer la ou les règles",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDisableRulesMessage": "Impossible de désactiver la ou les règles",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToEnableRulesMessage": "Impossible d'activer la ou les règles",
"xpack.triggersActionsUI.sections.rulesList.cancelSnooze": "Annuler la répétition",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmCallout": "Seule l'occurrence actuelle d'un calendrier sera annulée.",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmText": "Reprenez la notification lorsque des alertes sont générées comme défini dans les actions de la règle.",
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -32367,8 +32367,6 @@
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.disableAllTitle": "無効にする",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.enableAllTitle": "有効にする",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDeleteRulesMessage": "ルールを削除できませんでした",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDisableRulesMessage": "ルールを無効にできませんでした",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToEnableRulesMessage": "ルールを有効にできませんでした",
"xpack.triggersActionsUI.sections.rulesList.cancelSnooze": "スヌーズをキャンセル",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmCallout": "スケジュールの最新の発生のみがキャンセルされます。",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmText": "ルールアクションの定義に従ってアラートが生成されるときに通知を再開します。",
Expand Down
2 changes: 0 additions & 2 deletions x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -32404,8 +32404,6 @@
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.disableAllTitle": "禁用",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.enableAllTitle": "启用",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDeleteRulesMessage": "无法删除规则",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToDisableRulesMessage": "无法禁用规则",
"xpack.triggersActionsUI.sections.rulesList.bulkActionPopover.failedToEnableRulesMessage": "无法启用规则",
"xpack.triggersActionsUI.sections.rulesList.cancelSnooze": "取消暂停",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmCallout": "只会取消当前发生的计划。",
"xpack.triggersActionsUI.sections.rulesList.cancelSnoozeConfirmText": "根据规则操作中的定义生成告警时恢复通知。",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export function useBulkEditSelect(props: UseBulkEditSelectProps) {

return useMemo(() => {
return {
selectedIds: state.selectedIds,
selectedIds: [...state.selectedIds],
isAllSelected: state.isAllSelected,
isPageSelected,
numberOfSelectedItems,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,41 @@ import React, { useCallback, useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
import { toMountPoint } from '@kbn/kibana-react-plugin/public';
import type { BulkOperationError } from '@kbn/alerting-plugin/server';
import { useKibana } from '../../common/lib/kibana';
import { BulkDeleteResponse } from '../../types';
import {
getSuccessfulDeletionNotificationText,
getFailedDeletionNotificationText,
getPartialSuccessDeletionNotificationText,
getPartialSuccessEnablingNotificationText,
getPartialSuccessDisablingNotificationText,
getFailedEnablingNotificationText,
getFailedDisablingNotificationText,
getSuccessfulEnablingNotificationText,
getSuccessfulDisablingNotificationText,
SINGLE_RULE_TITLE,
MULTIPLE_RULE_TITLE,
} from '../sections/rules_list/translations';

export const useBulkDeleteResponse = ({
const actionToToastMapping = {
DELETE: {
getSuccessfulNotificationText: getSuccessfulDeletionNotificationText,
getFailedNotificationText: getFailedDeletionNotificationText,
getPartialSuccessNotificationText: getPartialSuccessDeletionNotificationText,
},
ENABLE: {
getSuccessfulNotificationText: getSuccessfulEnablingNotificationText,
getFailedNotificationText: getFailedEnablingNotificationText,
getPartialSuccessNotificationText: getPartialSuccessEnablingNotificationText,
},
DISABLE: {
getSuccessfulNotificationText: getSuccessfulDisablingNotificationText,
getFailedNotificationText: getFailedDisablingNotificationText,
getPartialSuccessNotificationText: getPartialSuccessDisablingNotificationText,
},
};

export const useBulkOperationToast = ({
onSearchPopulate,
}: {
onSearchPopulate?: (filter: string) => void;
Expand All @@ -28,26 +52,26 @@ export const useBulkDeleteResponse = ({
} = useKibana().services;

const onSearchPopulateInternal = useCallback(
(response: BulkDeleteResponse) => {
(errors: BulkOperationError[]) => {
if (!onSearchPopulate) {
return;
}
const filter = response.errors.map((error) => error.rule.name).join(',');
const filter = errors.map((error) => error.rule.name).join(',');
onSearchPopulate(filter);
},
[onSearchPopulate]
);

const renderToastErrorBody = useCallback(
(response: BulkDeleteResponse, messageType: 'warning' | 'danger') => {
(errors: BulkOperationError[], messageType: 'warning' | 'danger') => {
return (
<EuiFlexGroup justifyContent="flexEnd" gutterSize="xs">
{onSearchPopulate && (
<EuiFlexItem grow={false}>
<EuiButton
color={messageType}
size="s"
onClick={() => onSearchPopulateInternal(response)}
onClick={() => onSearchPopulateInternal(errors)}
data-test-subj="bulkDeleteResponseFilterErrors"
>
<FormattedMessage
Expand All @@ -64,16 +88,22 @@ export const useBulkDeleteResponse = ({
);

const showToast = useCallback(
(response: BulkDeleteResponse) => {
const { errors, total } = response;

({
action,
errors,
total,
}: {
action: 'DELETE' | 'ENABLE' | 'DISABLE';
errors: BulkOperationError[];
total: number;
}) => {
const numberOfSuccess = total - errors.length;
const numberOfErrors = errors.length;

// All success
if (!numberOfErrors) {
toasts.addSuccess(
getSuccessfulDeletionNotificationText(
actionToToastMapping[action].getSuccessfulNotificationText(
numberOfSuccess,
SINGLE_RULE_TITLE,
MULTIPLE_RULE_TITLE
Expand All @@ -85,25 +115,25 @@ export const useBulkDeleteResponse = ({
// All failure
if (numberOfErrors === total) {
toasts.addDanger({
title: getFailedDeletionNotificationText(
title: actionToToastMapping[action].getFailedNotificationText(
numberOfErrors,
SINGLE_RULE_TITLE,
MULTIPLE_RULE_TITLE
),
text: toMountPoint(renderToastErrorBody(response, 'danger')),
text: toMountPoint(renderToastErrorBody(errors, 'danger')),
});
return;
}

// Some failure
toasts.addWarning({
title: getPartialSuccessDeletionNotificationText(
title: actionToToastMapping[action].getPartialSuccessNotificationText(
numberOfSuccess,
numberOfErrors,
SINGLE_RULE_TITLE,
MULTIPLE_RULE_TITLE
),
text: toMountPoint(renderToastErrorBody(response, 'warning')),
text: toMountPoint(renderToastErrorBody(errors, 'warning')),
});
},
[toasts, renderToastErrorBody]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { HttpSetup } from '@kbn/core/public';
import { KueryNode } from '@kbn/es-query';
import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants';
import { BulkDisableResponse } from '../../../types';

export const bulkDisableRules = async ({
filter,
ids,
http,
}: {
filter?: KueryNode | null;
ids?: string[];
http: HttpSetup;
}): Promise<BulkDisableResponse> => {
try {
const body = JSON.stringify({
ids: ids?.length ? ids : undefined,
...(filter ? { filter: JSON.stringify(filter) } : {}),
});

return http.patch(`${INTERNAL_BASE_ALERTING_API_PATH}/rules/_bulk_disable`, { body });
} catch (e) {
throw new Error(`Unable to parse bulk disable params: ${e}`);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* 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 { HttpSetup } from '@kbn/core/public';
import { KueryNode } from '@kbn/es-query';
import { INTERNAL_BASE_ALERTING_API_PATH } from '../../constants';
import { BulkEnableResponse } from '../../../types';

export const bulkEnableRules = async ({
filter,
ids,
http,
}: {
filter?: KueryNode | null;
ids?: string[];
http: HttpSetup;
}): Promise<BulkEnableResponse> => {
try {
const body = JSON.stringify({
ids: ids?.length ? ids : undefined,
...(filter ? { filter: JSON.stringify(filter) } : {}),
});

return http.patch(`${INTERNAL_BASE_ALERTING_API_PATH}/rules/_bulk_enable`, { body });
} catch (e) {
throw new Error(`Unable to parse bulk enable params: ${e}`);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ export type { BulkUpdateAPIKeyProps } from './update_api_key';
export { updateAPIKey, bulkUpdateAPIKey } from './update_api_key';
export { runSoon } from './run_soon';
export { bulkDeleteRules } from './bulk_delete';
export { bulkEnableRules } from './bulk_enable';
export { bulkDisableRules } from './bulk_disable';
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ describe('rule_quick_edit_buttons', () => {
selectedItems={[mockRule]}
onPerformingAction={() => {}}
onActionPerformed={() => {}}
onEnable={async () => {}}
onDisable={async () => {}}
setRulesToDelete={() => {}}
setRulesToDeleteFilter={() => {}}
setRulesToUpdateAPIKey={() => {}}
Expand All @@ -62,8 +64,8 @@ describe('rule_quick_edit_buttons', () => {
/>
);

expect(wrapper.find('[data-test-subj="enableAll"]').exists()).toBeFalsy();
expect(wrapper.find('[data-test-subj="disableAll"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkEnable"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkDisable"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="updateAPIKeys"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkDelete"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkSnooze"]').exists()).toBeTruthy();
Expand All @@ -85,6 +87,8 @@ describe('rule_quick_edit_buttons', () => {
selectedItems={[mockRule]}
onPerformingAction={() => {}}
onActionPerformed={() => {}}
onEnable={async () => {}}
onDisable={async () => {}}
setRulesToDelete={() => {}}
setRulesToDeleteFilter={() => {}}
setRulesToUpdateAPIKey={() => {}}
Expand All @@ -100,8 +104,8 @@ describe('rule_quick_edit_buttons', () => {
/>
);

expect(wrapper.find('[data-test-subj="enableAll"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="disableAll"]').exists()).toBeFalsy();
expect(wrapper.find('[data-test-subj="bulkEnable"]').exists()).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkDisable"]').exists()).toBeTruthy();
});

it('disables the disable/enable/delete bulk actions if in select all mode', async () => {
Expand All @@ -117,6 +121,8 @@ describe('rule_quick_edit_buttons', () => {
selectedItems={[mockRule]}
onPerformingAction={() => {}}
onActionPerformed={() => {}}
onEnable={async () => {}}
onDisable={async () => {}}
setRulesToDelete={() => {}}
setRulesToDeleteFilter={() => {}}
setRulesToUpdateAPIKey={() => {}}
Expand All @@ -132,7 +138,7 @@ describe('rule_quick_edit_buttons', () => {
/>
);

expect(wrapper.find('[data-test-subj="disableAll"]').first().prop('isDisabled')).toBeTruthy();
expect(wrapper.find('[data-test-subj="bulkEnable"]').first().prop('isDisabled')).toBeFalsy();
expect(wrapper.find('[data-test-subj="bulkDelete"]').first().prop('isDisabled')).toBeFalsy();
expect(wrapper.find('[data-test-subj="updateAPIKeys"]').first().prop('isDisabled')).toBeFalsy();
expect(wrapper.find('[data-test-subj="bulkSnooze"]').first().prop('isDisabled')).toBeFalsy();
Expand All @@ -159,6 +165,8 @@ describe('rule_quick_edit_buttons', () => {
selectedItems={[mockRule]}
onPerformingAction={() => {}}
onActionPerformed={() => {}}
onEnable={async () => {}}
onDisable={async () => {}}
setRulesToDelete={() => {}}
setRulesToDeleteFilter={() => {}}
setRulesToSnooze={setRulesToSnooze}
Expand Down Expand Up @@ -210,6 +218,8 @@ describe('rule_quick_edit_buttons', () => {
selectedItems={[mockRule]}
onPerformingAction={() => {}}
onActionPerformed={() => {}}
onEnable={async () => {}}
onDisable={async () => {}}
setRulesToDelete={() => {}}
setRulesToDeleteFilter={() => {}}
setRulesToSnooze={setRulesToSnooze}
Expand Down
Loading

0 comments on commit c5f2072

Please sign in to comment.