mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Security Solution][Detections] Fixes Alerts Table 'Select all [x] alerts' action (#75945)
## Summary Resolves https://github.com/elastic/kibana/issues/75194 Fixes issue where the `Select all [x] alerts` feature would not select the checkboxes within the Alerts Table. Also resolves issue where bulk actions wouldn't work with Building Block Alerts. ##### Select All Before <p align="center"> <img width="700" src="https://user-images.githubusercontent.com/2946766/91266588-d2d66800-e72e-11ea-8c57-c91bd80a8f0e.gif" /> </p> ##### Select All After <p align="center"> <img width="700" src="https://user-images.githubusercontent.com/2946766/91266573-cc47f080-e72e-11ea-9812-67e7182f90f3.gif" /> </p> ##### Building Block Query Before <p align="center"> <img width="700" src="https://user-images.githubusercontent.com/2946766/91266516-af132200-e72e-11ea-9088-63de64d2774e.gif" /> </p> ##### Building Block Query After <p align="center"> <img width="700" src="https://user-images.githubusercontent.com/2946766/91266531-bb977a80-e72e-11ea-8071-904b355856f7.gif" /> </p>
This commit is contained in:
parent
2946e68581
commit
638df5820c
3 changed files with 53 additions and 17 deletions
|
@ -105,7 +105,6 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
updateTimelineIsLoading,
|
||||
}) => {
|
||||
const dispatch = useDispatch();
|
||||
const [selectAll, setSelectAll] = useState(false);
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const [showClearSelectionAction, setShowClearSelectionAction] = useState(false);
|
||||
|
@ -120,6 +119,12 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
);
|
||||
const kibana = useKibana();
|
||||
const [, dispatchToaster] = useStateToaster();
|
||||
const {
|
||||
initializeTimeline,
|
||||
setSelectAll,
|
||||
setTimelineRowActions,
|
||||
setIndexToAdd,
|
||||
} = useManageTimeline();
|
||||
|
||||
const getGlobalQuery = useCallback(
|
||||
(customFilters: Filter[]) => {
|
||||
|
@ -141,8 +146,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
}
|
||||
return null;
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[browserFields, globalFilters, globalQuery, indexPatterns, kibana, to, from]
|
||||
[browserFields, defaultFilters, globalFilters, globalQuery, indexPatterns, kibana, to, from]
|
||||
);
|
||||
|
||||
// Callback for creating a new timeline -- utilized by row/batch actions
|
||||
|
@ -240,12 +244,15 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
|
||||
// Catches state change isSelectAllChecked->false upon user selection change to reset utility bar
|
||||
useEffect(() => {
|
||||
if (!isSelectAllChecked) {
|
||||
setShowClearSelectionAction(false);
|
||||
if (isSelectAllChecked) {
|
||||
setSelectAll({
|
||||
id: timelineId,
|
||||
selectAll: false,
|
||||
});
|
||||
} else {
|
||||
setSelectAll(false);
|
||||
setShowClearSelectionAction(false);
|
||||
}
|
||||
}, [isSelectAllChecked]);
|
||||
}, [isSelectAllChecked, setSelectAll, timelineId]);
|
||||
|
||||
// Callback for when open/closed filter changes
|
||||
const onFilterGroupChangedCallback = useCallback(
|
||||
|
@ -261,17 +268,23 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
// Callback for clearing entire selection from utility bar
|
||||
const clearSelectionCallback = useCallback(() => {
|
||||
clearSelected!({ id: timelineId });
|
||||
setSelectAll(false);
|
||||
setSelectAll({
|
||||
id: timelineId,
|
||||
selectAll: false,
|
||||
});
|
||||
setShowClearSelectionAction(false);
|
||||
}, [clearSelected, setSelectAll, setShowClearSelectionAction, timelineId]);
|
||||
|
||||
// Callback for selecting all events on all pages from utility bar
|
||||
// Dispatches to stateful_body's selectAll via TimelineTypeContext props
|
||||
// as scope of response data required to actually set selectedEvents
|
||||
const selectAllCallback = useCallback(() => {
|
||||
setSelectAll(true);
|
||||
const selectAllOnAllPagesCallback = useCallback(() => {
|
||||
setSelectAll({
|
||||
id: timelineId,
|
||||
selectAll: true,
|
||||
});
|
||||
setShowClearSelectionAction(true);
|
||||
}, [setSelectAll, setShowClearSelectionAction]);
|
||||
}, [setSelectAll, setShowClearSelectionAction, timelineId]);
|
||||
|
||||
const updateAlertsStatusCallback: UpdateAlertsStatusCallback = useCallback(
|
||||
async (
|
||||
|
@ -314,7 +327,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
clearSelection={clearSelectionCallback}
|
||||
hasIndexWrite={hasIndexWrite}
|
||||
currentFilter={filterGroup}
|
||||
selectAll={selectAllCallback}
|
||||
selectAll={selectAllOnAllPagesCallback}
|
||||
selectedEventIds={selectedEventIds}
|
||||
showBuildingBlockAlerts={showBuildingBlockAlerts}
|
||||
onShowBuildingBlockAlertsChanged={onShowBuildingBlockAlertsChanged}
|
||||
|
@ -332,7 +345,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
showBuildingBlockAlerts,
|
||||
onShowBuildingBlockAlertsChanged,
|
||||
loadingEventIds.length,
|
||||
selectAllCallback,
|
||||
selectAllOnAllPagesCallback,
|
||||
selectedEventIds,
|
||||
showClearSelectionAction,
|
||||
updateAlertsStatusCallback,
|
||||
|
@ -384,7 +397,6 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
}
|
||||
}, [defaultFilters, filterGroup]);
|
||||
const { filterManager } = useKibana().services.data.query;
|
||||
const { initializeTimeline, setTimelineRowActions, setIndexToAdd } = useManageTimeline();
|
||||
|
||||
useEffect(() => {
|
||||
initializeTimeline({
|
||||
|
@ -395,7 +407,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
|
|||
id: timelineId,
|
||||
indexToAdd: defaultIndices,
|
||||
loadingText: i18n.LOADING_ALERTS,
|
||||
selectAll: canUserCRUD ? selectAll : false,
|
||||
selectAll: false,
|
||||
timelineRowActions: () => [getInvestigateInResolverAction({ dispatch, timelineId })],
|
||||
title: '',
|
||||
});
|
||||
|
|
|
@ -71,6 +71,11 @@ type ActionManageTimeline =
|
|||
id: string;
|
||||
payload: string[];
|
||||
}
|
||||
| {
|
||||
type: 'SET_SELECT_ALL';
|
||||
id: string;
|
||||
payload: boolean;
|
||||
}
|
||||
| {
|
||||
type: 'SET_TIMELINE_ACTIONS';
|
||||
id: string;
|
||||
|
@ -116,6 +121,14 @@ const reducerManageTimeline = (
|
|||
indexToAdd: action.payload,
|
||||
},
|
||||
} as ManageTimelineById;
|
||||
case 'SET_SELECT_ALL':
|
||||
return {
|
||||
...state,
|
||||
[action.id]: {
|
||||
...state[action.id],
|
||||
selectAll: action.payload,
|
||||
},
|
||||
} as ManageTimelineById;
|
||||
case 'SET_TIMELINE_ACTIONS':
|
||||
return {
|
||||
...state,
|
||||
|
@ -145,6 +158,7 @@ export interface UseTimelineManager {
|
|||
isManagedTimeline: (id: string) => boolean;
|
||||
setIndexToAdd: (indexToAddArgs: { id: string; indexToAdd: string[] }) => void;
|
||||
setIsTimelineLoading: (isLoadingArgs: { id: string; isLoading: boolean }) => void;
|
||||
setSelectAll: (selectAllArgs: { id: string; selectAll: boolean }) => void;
|
||||
setTimelineRowActions: (actionsArgs: {
|
||||
id: string;
|
||||
queryFields?: string[];
|
||||
|
@ -205,6 +219,14 @@ export const useTimelineManager = (
|
|||
});
|
||||
}, []);
|
||||
|
||||
const setSelectAll = useCallback(({ id, selectAll }: { id: string; selectAll: boolean }) => {
|
||||
dispatch({
|
||||
type: 'SET_SELECT_ALL',
|
||||
id,
|
||||
payload: selectAll,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const getTimelineFilterManager = useCallback(
|
||||
(id: string): FilterManager | undefined => state[id]?.filterManager,
|
||||
[state]
|
||||
|
@ -238,6 +260,7 @@ export const useTimelineManager = (
|
|||
isManagedTimeline,
|
||||
setIndexToAdd,
|
||||
setIsTimelineLoading,
|
||||
setSelectAll,
|
||||
setTimelineRowActions,
|
||||
};
|
||||
};
|
||||
|
@ -250,6 +273,7 @@ const init = {
|
|||
isManagedTimeline: () => false,
|
||||
setIndexToAdd: () => undefined,
|
||||
setIsTimelineLoading: () => noop,
|
||||
setSelectAll: () => noop,
|
||||
setTimelineRowActions: () => noop,
|
||||
};
|
||||
|
||||
|
|
|
@ -169,10 +169,10 @@ const StatefulBodyComponent = React.memo<StatefulBodyComponentProps>(
|
|||
|
||||
// Sync to selectAll so parent components can select all events
|
||||
useEffect(() => {
|
||||
if (selectAll) {
|
||||
if (selectAll && !isSelectAllChecked) {
|
||||
onSelectAll({ isSelected: true });
|
||||
}
|
||||
}, [onSelectAll, selectAll]);
|
||||
}, [isSelectAllChecked, onSelectAll, selectAll]);
|
||||
|
||||
const enabledRowRenderers = useMemo(() => {
|
||||
if (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue