Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RAC][Security Solution] Make analyzer work with EuiDataGrid full screen #110913

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useGlobalHeaderPortal } from '../../../../common/hooks/use_global_heade

const StyledStickyWrapper = styled.div`
position: sticky;
z-index: ${(props) => props.theme.eui.euiZLevel2};
z-index: ${(props) => props.theme.eui.euiZHeaderBelowDataGrid};
// TOP location is declared in src/public/rendering/_base.scss to keep in line with Kibana Chrome
`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ const EventsViewerComponent: React.FC<Props> = ({
refetch={refetch}
/>

{graphEventId && <GraphOverlay isEventViewer={true} timelineId={id} />}
{graphEventId && <GraphOverlay timelineId={id} />}
<FullWidthFlexGroup $visible={!graphEventId} gutterSize="none">
<ScrollableFlexItem grow={1}>
<StatefulBody
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
const trailingControlColumns: ControlColumnProps[] = EMPTY_CONTROL_COLUMNS;
const graphOverlay = useMemo(
() =>
graphEventId != null && graphEventId.length > 0 ? (
<GraphOverlay isEventViewer={true} timelineId={id} />
) : null,
graphEventId != null && graphEventId.length > 0 ? <GraphOverlay timelineId={id} /> : null,
[graphEventId, id]
);
const setQuery = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export const resetScroll = () => {
}
}, 0);
};

interface GlobalFullScreen {
globalFullScreen: boolean;
setGlobalFullScreen: (fullScreen: boolean) => void;
Expand All @@ -46,10 +45,10 @@ export const useGlobalFullScreen = (): GlobalFullScreen => {
const setGlobalFullScreen = useCallback(
(fullScreen: boolean) => {
if (fullScreen) {
document.body.classList.add(SCROLLING_DISABLED_CLASS_NAME);
document.body.classList.add(SCROLLING_DISABLED_CLASS_NAME, 'euiDataGrid__restrictBody');
resetScroll();
} else {
document.body.classList.remove(SCROLLING_DISABLED_CLASS_NAME);
document.body.classList.remove(SCROLLING_DISABLED_CLASS_NAME, 'euiDataGrid__restrictBody');
resetScroll();
}

Copy link
Contributor

@angorayc angorayc Sep 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we able to dispatch setFullScreen for global full screen as well? I could find some style issue due to incorrect global full screen status? Although it seems that the toggle fullscreen button for events table is coming from data grid?
Screenshot 2021-09-02 at 13 58 04

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ya this is an unrelated z-index issue that was/will be fixed by upgrading eui, #109926 via elastic/eui#5054 I think

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: turns out it was not fixed, but fixed in this commit 0c1da5a

Expand All @@ -71,9 +70,15 @@ export const useTimelineFullScreen = (): TimelineFullScreen => {
const dispatch = useDispatch();
const timelineFullScreen =
useShallowEqualSelector(inputsSelectors.timelineFullScreenSelector) ?? false;

const setTimelineFullScreen = useCallback(
(fullScreen: boolean) => dispatch(inputsActions.setFullScreen({ id: 'timeline', fullScreen })),
(fullScreen: boolean) => {
if (fullScreen) {
document.body.classList.add('euiDataGrid__restrictBody');
} else {
document.body.classList.remove('euiDataGrid__restrictBody');
}
dispatch(inputsActions.setFullScreen({ id: 'timeline', fullScreen }));
},
[dispatch]
);
const memoizedReturn = useMemo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import {
setActiveTabTimeline,
updateTimelineGraphEventId,
} from '../../../../timelines/store/timeline/actions';
import {
useGlobalFullScreen,
useTimelineFullScreen,
} from '../../../../common/containers/use_full_screen';
import { TimelineId, TimelineTabs } from '../../../../../common';
import { ACTION_INVESTIGATE_IN_RESOLVER } from '../../../../timelines/components/timeline/body/translations';
import { Ecs } from '../../../../../common/ecs';
Expand All @@ -35,13 +39,23 @@ export const useInvestigateInResolverContextItem = ({
}: InvestigateInResolverProps) => {
const dispatch = useDispatch();
const isDisabled = useMemo(() => !isInvestigateInResolverActionEnabled(ecsData), [ecsData]);
const { setGlobalFullScreen } = useGlobalFullScreen();
const { setTimelineFullScreen } = useTimelineFullScreen();
const handleClick = useCallback(() => {
const dataGridIsFullScreen = document.querySelector('.euiDataGrid--fullScreen');
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: ecsData._id }));
if (timelineId === TimelineId.active) {
if (dataGridIsFullScreen) {
setTimelineFullScreen(true);
}
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.graph }));
} else {
if (dataGridIsFullScreen) {
setGlobalFullScreen(true);
}
}
onClose();
}, [dispatch, ecsData._id, onClose, timelineId]);
}, [dispatch, ecsData._id, onClose, timelineId, setGlobalFullScreen, setTimelineFullScreen]);
return isDisabled
? []
: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,10 @@ describe('GraphOverlay', () => {
});

describe('when used in an events viewer (i.e. in the Detections view, or the Host > Events view)', () => {
const isEventViewer = true;

test('it has 100% width when isEventViewer is true and NOT in full screen mode', async () => {
test('it has 100% width when NOT in full screen mode', async () => {
const wrapper = mount(
<TestProviders>
<GraphOverlay timelineId={TimelineId.test} isEventViewer={isEventViewer} />
<GraphOverlay timelineId={TimelineId.test} />
</TestProviders>
);

Expand All @@ -59,9 +57,9 @@ describe('GraphOverlay', () => {
});
});

test('it has a calculated width that makes room for the Timeline flyout button when isEventViewer is true in full screen mode', async () => {
test('it has a fixed position when in full screen mode', async () => {
(useGlobalFullScreen as jest.Mock).mockReturnValue({
globalFullScreen: true, // <-- true when an events viewer is in full screen mode
globalFullScreen: true,
setGlobalFullScreen: jest.fn(),
});
(useTimelineFullScreen as jest.Mock).mockReturnValue({
Expand All @@ -71,25 +69,24 @@ describe('GraphOverlay', () => {

const wrapper = mount(
<TestProviders>
<GraphOverlay timelineId={TimelineId.test} isEventViewer={isEventViewer} />
<GraphOverlay timelineId={TimelineId.test} />
</TestProviders>
);

await waitFor(() => {
const overlayContainer = wrapper.find('[data-test-subj="overlayContainer"]').first();
expect(overlayContainer).toHaveStyleRule('width', 'calc(100% - 36px)');
expect(overlayContainer).toHaveStyleRule('position', 'fixed');
});
});
});

describe('when used in the active timeline', () => {
const isEventViewer = false;
const timelineId = TimelineId.active;

test('it has 100% width when isEventViewer is false and NOT in full screen mode', async () => {
test('it has 100% width when NOT in full screen mode', async () => {
const wrapper = mount(
<TestProviders>
<GraphOverlay timelineId={timelineId} isEventViewer={isEventViewer} />
<GraphOverlay timelineId={timelineId} />
</TestProviders>
);

Expand All @@ -99,7 +96,7 @@ describe('GraphOverlay', () => {
});
});

test('it has 100% width when isEventViewer is false and the active timeline is in full screen mode', async () => {
test('it has 100% width when the active timeline is in full screen mode', async () => {
(useGlobalFullScreen as jest.Mock).mockReturnValue({
globalFullScreen: false,
setGlobalFullScreen: jest.fn(),
Expand All @@ -111,7 +108,7 @@ describe('GraphOverlay', () => {

const wrapper = mount(
<TestProviders>
<GraphOverlay timelineId={timelineId} isEventViewer={isEventViewer} />
<GraphOverlay timelineId={timelineId} />
</TestProviders>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,19 @@ import {
import * as i18n from './translations';

const OverlayContainer = styled.div`
${({ $restrictWidth }: { $restrictWidth: boolean }) =>
`
display: flex;
flex-direction: column;
flex: 1;
width: ${$restrictWidth ? 'calc(100% - 36px)' : '100%'};
`}
display: flex;
flex-direction: column;
flex: 1;
width: 100%;
`;

const FullScreenOverlayContainer = styled.div`
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: ${(props) => props.theme.eui.euiZLevel3};
`;

const StyledResolver = styled(Resolver)`
Expand All @@ -59,7 +65,6 @@ const FullScreenButtonIcon = styled(EuiButtonIcon)`
`;

interface OwnProps {
isEventViewer: boolean;
timelineId: TimelineId;
}

Expand Down Expand Up @@ -111,18 +116,15 @@ NavigationComponent.displayName = 'NavigationComponent';

const Navigation = React.memo(NavigationComponent);

const GraphOverlayComponent: React.FC<OwnProps> = ({ isEventViewer, timelineId }) => {
const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => {
const dispatch = useDispatch();
const onCloseOverlay = useCallback(() => {
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: '' }));
}, [dispatch, timelineId]);
const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
const { timelineFullScreen, setTimelineFullScreen } = useTimelineFullScreen();

const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []);
const graphEventId = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).graphEventId
);

const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
const { timelineFullScreen, setTimelineFullScreen } = useTimelineFullScreen();
const getStartSelector = useMemo(() => startSelector(), []);
const getEndSelector = useMemo(() => endSelector(), []);
const getIsLoadingSelector = useMemo(() => isLoadingSelector(), []);
Expand Down Expand Up @@ -154,6 +156,16 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ isEventViewer, timelineId }
[globalFullScreen, timelineId, timelineFullScreen]
);

const isInTimeline = timelineId === TimelineId.active;
const onCloseOverlay = useCallback(() => {
if (timelineId === TimelineId.active) {
setTimelineFullScreen(false);
} else {
setGlobalFullScreen(false);
}
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: '' }));
}, [dispatch, timelineId, setTimelineFullScreen, setGlobalFullScreen]);

const toggleFullScreen = useCallback(() => {
if (timelineId === TimelineId.active) {
setTimelineFullScreen(!timelineFullScreen);
Expand All @@ -173,41 +185,71 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ isEventViewer, timelineId }
[]
);
const existingIndexNames = useDeepEqualSelector<string[]>(existingIndexNamesSelector);

return (
<OverlayContainer
data-test-subj="overlayContainer"
$restrictWidth={isEventViewer && fullScreen}
>
<EuiHorizontalRule margin="none" />
<EuiFlexGroup gutterSize="none" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<Navigation
fullScreen={fullScreen}
globalFullScreen={globalFullScreen}
onCloseOverlay={onCloseOverlay}
timelineId={timelineId}
timelineFullScreen={timelineFullScreen}
toggleFullScreen={toggleFullScreen}
if (fullScreen && !isInTimeline) {
return (
<FullScreenOverlayContainer data-test-subj="overlayContainer">
<EuiHorizontalRule margin="none" />
<EuiFlexGroup gutterSize="none" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<Navigation
fullScreen={fullScreen}
globalFullScreen={globalFullScreen}
onCloseOverlay={onCloseOverlay}
timelineId={timelineId}
timelineFullScreen={timelineFullScreen}
toggleFullScreen={toggleFullScreen}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule margin="none" />
{graphEventId !== undefined ? (
<StyledResolver
databaseDocumentID={graphEventId}
resolverComponentInstanceID={timelineId}
indices={existingIndexNames}
shouldUpdate={shouldUpdate}
filters={{ from, to }}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiHorizontalRule margin="none" />
{graphEventId !== undefined ? (
<StyledResolver
databaseDocumentID={graphEventId}
resolverComponentInstanceID={timelineId}
indices={existingIndexNames}
shouldUpdate={shouldUpdate}
filters={{ from, to }}
/>
) : (
<EuiFlexGroup alignItems="center" justifyContent="center" style={{ height: '100%' }}>
<EuiLoadingSpinner size="xl" />
) : (
<EuiFlexGroup alignItems="center" justifyContent="center" style={{ height: '100%' }}>
<EuiLoadingSpinner size="xl" />
</EuiFlexGroup>
)}
</FullScreenOverlayContainer>
);
} else {
return (
<OverlayContainer data-test-subj="overlayContainer">
<EuiHorizontalRule margin="none" />
<EuiFlexGroup gutterSize="none" justifyContent="spaceBetween">
<EuiFlexItem grow={false}>
<Navigation
fullScreen={fullScreen}
globalFullScreen={globalFullScreen}
onCloseOverlay={onCloseOverlay}
timelineId={timelineId}
timelineFullScreen={timelineFullScreen}
toggleFullScreen={toggleFullScreen}
/>
</EuiFlexItem>
</EuiFlexGroup>
)}
</OverlayContainer>
);
<EuiHorizontalRule margin="none" />
{graphEventId !== undefined ? (
<StyledResolver
databaseDocumentID={graphEventId}
resolverComponentInstanceID={timelineId}
indices={existingIndexNames}
shouldUpdate={shouldUpdate}
filters={{ from, to }}
/>
) : (
<EuiFlexGroup alignItems="center" justifyContent="center" style={{ height: '100%' }}>
<EuiLoadingSpinner size="xl" />
</EuiFlexGroup>
)}
</OverlayContainer>
);
}
};

export const GraphOverlay = React.memo(GraphOverlayComponent);
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const GraphTabContentComponent: React.FC<GraphTabContentProps> = ({ timelineId }
return null;
}

return <GraphOverlay isEventViewer={false} timelineId={timelineId} />;
return <GraphOverlay timelineId={timelineId} />;
};

GraphTabContentComponent.displayName = 'GraphTabContentComponent';
Expand Down
Loading