Skip to content

Commit

Permalink
Prevent duplicate items being added by bulk actions select all
Browse files Browse the repository at this point in the history
  • Loading branch information
kqualters-elastic committed Apr 29, 2024
1 parent 694acf7 commit 492f801
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { useBulkActions, useBulkAddToCaseActions, useBulkUntrackActions } from '
import { AppMockRenderer, createAppMockRenderer } from '../../test_utils';
import { createCasesServiceMock } from '../index.mock';
import { AlertsTableQueryContext } from '../contexts/alerts_table_context';
import { BulkActionsVerbs } from '../../../../types';

jest.mock('./apis/bulk_get_cases');
jest.mock('../../../../common/lib/kibana');
Expand Down Expand Up @@ -422,5 +423,45 @@ describe('bulk action hooks', () => {
]
`);
});

it('should not append duplicate items on rerender', async () => {
const onClick = () => {};
const items = [
{
label: 'test',
key: 'test',
'data-test-subj': 'test',
disableOnQuery: true,
disabledLabel: 'test',
onClick,
},
];
const customBulkActionConfig = [
{
id: 0,
items,
},
];
const useBulkActionsConfig = () => customBulkActionConfig;
const { result, rerender } = renderHook(
() => useBulkActions({ alerts: [], query: {}, casesConfig, refresh, useBulkActionsConfig }),
{
wrapper: appMockRender.AppWrapper,
}
);
const initialBulkActions = result.current.bulkActions[0].items
? [...result.current.bulkActions[0].items]
: [];
result.current.updateBulkActionsState({ action: BulkActionsVerbs.selectCurrentPage });
rerender();
result.current.updateBulkActionsState({ action: BulkActionsVerbs.clear });
rerender();
result.current.updateBulkActionsState({ action: BulkActionsVerbs.selectCurrentPage });
rerender();
result.current.updateBulkActionsState({ action: BulkActionsVerbs.selectAll });
rerender();
const newBulkActions = result.current.bulkActions[0].items;
expect(initialBulkActions).toEqual(newBulkActions);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
BulkActionsPanelConfig,
BulkActionsState,
BulkActionsVerbs,
BulkActionsReducerAction,
UseBulkActionsRegistry,
} from '../../../../types';
import {
Expand Down Expand Up @@ -50,6 +51,7 @@ export interface UseBulkActions {
bulkActions: BulkActionsPanelConfig[];
setIsBulkActionsLoading: (isLoading: boolean) => void;
clearSelection: () => void;
updateBulkActionsState: React.Dispatch<BulkActionsReducerAction>;
}

type UseBulkAddToCaseActionsProps = Pick<BulkActionsProps, 'casesConfig' | 'refresh'> &
Expand Down Expand Up @@ -90,7 +92,9 @@ const addItemsToInitialPanel = ({
}) => {
if (panels.length > 0) {
if (panels[0].items) {
panels[0].items.push(...items);
panels[0].items = [...panels[0].items, ...items].filter(
(item, index, self) => index === self.findIndex((newItem) => newItem.key === item.key)
);
}
return panels;
} else {
Expand Down Expand Up @@ -205,6 +209,33 @@ export const useBulkUntrackActions = ({
const hasUptimePermission = application?.capabilities.uptime?.show;
const hasSloPermission = application?.capabilities.slo?.show;
const hasObservabilityPermission = application?.capabilities.observability?.show;
const onClick = useCallback(
async (alerts?: TimelineItem[]) => {
if (!alerts) return;
const alertUuids = alerts.map((alert) => alert._id);
const indices = alerts.map((alert) => alert._index ?? '');
try {
setIsBulkActionsLoading(true);
if (isAllSelected) {
await untrackAlertsByQuery({ query, featureIds });
} else {
await untrackAlerts({ indices, alertUuids });
}
onSuccess();
} finally {
setIsBulkActionsLoading(false);
}
},
[
query,
featureIds,
isAllSelected,
onSuccess,
setIsBulkActionsLoading,
untrackAlerts,
untrackAlertsByQuery,
]
);

return useMemo(() => {
// Check if at least one Observability feature is enabled
Expand All @@ -225,39 +256,18 @@ export const useBulkUntrackActions = ({
disableOnQuery: false,
disabledLabel: MARK_AS_UNTRACKED,
'data-test-subj': 'mark-as-untracked',
onClick: async (alerts?: TimelineItem[]) => {
if (!alerts) return;
const alertUuids = alerts.map((alert) => alert._id);
const indices = alerts.map((alert) => alert._index ?? '');
try {
setIsBulkActionsLoading(true);
if (isAllSelected) {
await untrackAlertsByQuery({ query, featureIds });
} else {
await untrackAlerts({ indices, alertUuids });
}
onSuccess();
} finally {
setIsBulkActionsLoading(false);
}
},
onClick,
},
];
}, [
onSuccess,
setIsBulkActionsLoading,
untrackAlerts,
application?.capabilities,
hasApmPermission,
hasInfrastructurePermission,
hasLogsPermission,
hasUptimePermission,
hasSloPermission,
hasObservabilityPermission,
featureIds,
query,
isAllSelected,
untrackAlertsByQuery,
onClick,
]);
};

Expand Down

0 comments on commit 492f801

Please sign in to comment.