diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx
index 833688ae57993..6f77d15913d07 100644
--- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.test.tsx
@@ -50,6 +50,10 @@ const utilityBar = (refetch: inputsModel.Refetch, totalCount: number) => (
);
+const exceptionsModal = (refetch: inputsModel.Refetch) => (
+
+);
+
const eventsViewerDefaultProps = {
browserFields: {},
columns: [],
@@ -460,4 +464,42 @@ describe('EventsViewer', () => {
});
});
});
+
+ describe('exceptions modal', () => {
+ test('it renders exception modal if "exceptionsModal" callback exists', async () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ await waitFor(() => {
+ wrapper.update();
+
+ expect(wrapper.find(`[data-test-subj="mock-exceptions-modal"]`).exists()).toBeTruthy();
+ });
+ });
+
+ test('it does not render exception modal if "exceptionModal" callback does not exist', async () => {
+ const wrapper = mount(
+
+
+
+
+
+ );
+
+ await waitFor(() => {
+ wrapper.update();
+
+ expect(wrapper.find(`[data-test-subj="mock-exceptions-modal"]`).exists()).toBeFalsy();
+ });
+ });
+ });
});
diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx
index 436386077e725..ebda64efabf65 100644
--- a/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/events_viewer.tsx
@@ -109,6 +109,7 @@ interface Props {
utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode;
// If truthy, the graph viewer (Resolver) is showing
graphEventId: string | undefined;
+ exceptionsModal?: (refetch: inputsModel.Refetch) => React.ReactNode;
}
const EventsViewerComponent: React.FC = ({
@@ -134,6 +135,7 @@ const EventsViewerComponent: React.FC = ({
toggleColumn,
utilityBar,
graphEventId,
+ exceptionsModal,
}) => {
const { globalFullScreen } = useFullScreen();
const columnsHeader = isEmpty(columns) ? defaultHeaders : columns;
@@ -259,6 +261,7 @@ const EventsViewerComponent: React.FC = ({
)}
+ {exceptionsModal && exceptionsModal(refetch)}
{utilityBar && !resolverIsShowing(graphEventId) && (
{utilityBar?.(refetch, totalCountMinusDeleted)}
)}
@@ -335,5 +338,6 @@ export const EventsViewer = React.memo(
prevProps.start === nextProps.start &&
prevProps.sort === nextProps.sort &&
prevProps.utilityBar === nextProps.utilityBar &&
- prevProps.graphEventId === nextProps.graphEventId
+ prevProps.graphEventId === nextProps.graphEventId &&
+ prevProps.exceptionsModal === nextProps.exceptionsModal
);
diff --git a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx
index e4520dab4626a..ec56a3a1bd8d3 100644
--- a/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx
+++ b/x-pack/plugins/security_solution/public/common/components/events_viewer/index.tsx
@@ -43,6 +43,7 @@ export interface OwnProps {
headerFilterGroup?: React.ReactNode;
pageFilters?: Filter[];
utilityBar?: (refetch: inputsModel.Refetch, totalCount: number) => React.ReactNode;
+ exceptionsModal?: (refetch: inputsModel.Refetch) => React.ReactNode;
}
type Props = OwnProps & PropsFromRedux;
@@ -74,6 +75,7 @@ const StatefulEventsViewerComponent: React.FC = ({
utilityBar,
// If truthy, the graph viewer (Resolver) is showing
graphEventId,
+ exceptionsModal,
}) => {
const [
{ docValueFields, browserFields, indexPatterns, isLoading: isLoadingIndexPattern },
@@ -156,6 +158,7 @@ const StatefulEventsViewerComponent: React.FC = ({
toggleColumn={toggleColumn}
utilityBar={utilityBar}
graphEventId={graphEventId}
+ exceptionsModal={exceptionsModal}
/>
@@ -220,6 +223,7 @@ type PropsFromRedux = ConnectedProps;
export const StatefulEventsViewer = connector(
React.memo(
StatefulEventsViewerComponent,
+ // eslint-disable-next-line complexity
(prevProps, nextProps) =>
prevProps.id === nextProps.id &&
deepEqual(prevProps.columns, nextProps.columns) &&
@@ -240,6 +244,7 @@ export const StatefulEventsViewer = connector(
prevProps.showCheckboxes === nextProps.showCheckboxes &&
prevProps.start === nextProps.start &&
prevProps.utilityBar === nextProps.utilityBar &&
- prevProps.graphEventId === nextProps.graphEventId
+ prevProps.graphEventId === nextProps.graphEventId &&
+ prevProps.exceptionsModal === nextProps.exceptionsModal
)
);
diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
index 07e69d850f173..356cdfd84045e 100644
--- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
+++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx
@@ -220,28 +220,6 @@ export const AlertsTableComponent: React.FC = ({
[dispatchToaster]
);
- const openAddExceptionModalCallback = useCallback(
- ({
- ruleName,
- ruleIndices,
- ruleId,
- exceptionListType,
- alertData,
- }: AddExceptionModalBaseProps) => {
- if (alertData !== null && alertData !== undefined) {
- setShouldShowAddExceptionModal(true);
- setAddExceptionModalState({
- ruleName,
- ruleId,
- ruleIndices,
- exceptionListType,
- alertData,
- });
- }
- },
- [setShouldShowAddExceptionModal, setAddExceptionModalState]
- );
-
// Catches state change isSelectAllChecked->false upon user selection change to reset utility bar
useEffect(() => {
if (isSelectAllChecked) {
@@ -352,6 +330,74 @@ export const AlertsTableComponent: React.FC = ({
]
);
+ const closeAddExceptionModal = useCallback(() => {
+ setShouldShowAddExceptionModal(false);
+ setAddExceptionModalState(addExceptionModalInitialState);
+ }, [setShouldShowAddExceptionModal, setAddExceptionModalState]);
+
+ const onAddExceptionCancel = useCallback(() => {
+ closeAddExceptionModal();
+ }, [closeAddExceptionModal]);
+
+ const onAddExceptionConfirm = useCallback(
+ (refetch) => () => {
+ refetch();
+ closeAddExceptionModal();
+ },
+ [closeAddExceptionModal]
+ );
+
+ const openAddExceptionModalCallback = useCallback(
+ ({
+ ruleName,
+ ruleIndices,
+ ruleId,
+ exceptionListType,
+ alertData,
+ }: AddExceptionModalBaseProps) => {
+ if (alertData !== null && alertData !== undefined) {
+ setShouldShowAddExceptionModal(true);
+ setAddExceptionModalState({
+ ruleName,
+ ruleId,
+ ruleIndices,
+ exceptionListType,
+ alertData,
+ });
+ }
+ },
+ [setShouldShowAddExceptionModal, setAddExceptionModalState]
+ );
+
+ // Callback for creating the AddExceptionModal and allowing it
+ // access to the refetchQuery to update the page
+ const exceptionModalCallback = useCallback(
+ (refetchQuery: inputsModel.Refetch) => {
+ if (shouldShowAddExceptionModal) {
+ return (
+
+ );
+ } else {
+ return <>>;
+ }
+ },
+ [
+ addExceptionModalState,
+ filterGroup,
+ onAddExceptionCancel,
+ onAddExceptionConfirm,
+ shouldShowAddExceptionModal,
+ ]
+ );
// Send to Timeline / Update Alert Status Actions for each table row
const additionalActions = useMemo(
() => ({ ecsData, nonEcsData }: TimelineRowActionArgs) =>
@@ -378,13 +424,13 @@ export const AlertsTableComponent: React.FC = ({
createTimelineCallback,
dispatch,
hasIndexWrite,
- filterGroup,
- setEventsLoadingCallback,
+ onAlertStatusUpdateFailure,
+ onAlertStatusUpdateSuccess,
setEventsDeletedCallback,
+ setEventsLoadingCallback,
+ filterGroup,
timelineId,
updateTimelineIsLoading,
- onAlertStatusUpdateSuccess,
- onAlertStatusUpdateFailure,
openAddExceptionModalCallback,
]
);
@@ -432,19 +478,6 @@ export const AlertsTableComponent: React.FC = ({
[onFilterGroupChangedCallback]
);
- const closeAddExceptionModal = useCallback(() => {
- setShouldShowAddExceptionModal(false);
- setAddExceptionModalState(addExceptionModalInitialState);
- }, [setShouldShowAddExceptionModal, setAddExceptionModalState]);
-
- const onAddExceptionCancel = useCallback(() => {
- closeAddExceptionModal();
- }, [closeAddExceptionModal]);
-
- const onAddExceptionConfirm = useCallback(() => closeAddExceptionModal(), [
- closeAddExceptionModal,
- ]);
-
if (loading || indexPatternsLoading || isEmpty(signalsIndex)) {
return (
@@ -465,19 +498,8 @@ export const AlertsTableComponent: React.FC = ({
id={timelineId}
start={from}
utilityBar={utilityBarCallback}
+ exceptionsModal={exceptionModalCallback}
/>
- {shouldShowAddExceptionModal === true && addExceptionModalState.alertData !== null && (
-
- )}
>
);
};