Skip to content

Commit

Permalink
[Security Solution][Detections] Fixes Alerts Table 'Select all [x] al…
Browse files Browse the repository at this point in the history
…erts' action (elastic#75945)

## Summary

Resolves elastic#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>
  • Loading branch information
spong committed Aug 26, 2020
1 parent d324c6d commit 12d6586
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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[]) => {
Expand All @@ -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
Expand Down Expand Up @@ -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(
Expand All @@ -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 (
Expand Down Expand Up @@ -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}
Expand All @@ -332,7 +345,7 @@ export const AlertsTableComponent: React.FC<AlertsTableComponentProps> = ({
showBuildingBlockAlerts,
onShowBuildingBlockAlertsChanged,
loadingEventIds.length,
selectAllCallback,
selectAllOnAllPagesCallback,
selectedEventIds,
showClearSelectionAction,
updateAlertsStatusCallback,
Expand Down Expand Up @@ -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({
Expand All @@ -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: '',
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ type ActionManageTimeline =
id: string;
payload: string[];
}
| {
type: 'SET_SELECT_ALL';
id: string;
payload: boolean;
}
| {
type: 'SET_TIMELINE_ACTIONS';
id: string;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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[];
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -238,6 +260,7 @@ export const useTimelineManager = (
isManagedTimeline,
setIndexToAdd,
setIsTimelineLoading,
setSelectAll,
setTimelineRowActions,
};
};
Expand All @@ -250,6 +273,7 @@ const init = {
isManagedTimeline: () => false,
setIndexToAdd: () => undefined,
setIsTimelineLoading: () => noop,
setSelectAll: () => noop,
setTimelineRowActions: () => noop,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down

0 comments on commit 12d6586

Please sign in to comment.