-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[Security Solution] Use session view plugin to render session viewer in alerts, events and timeline #127520
[Security Solution] Use session view plugin to render session viewer in alerts, events and timeline #127520
Changes from 2 commits
af077cd
0abc22b
821c0c2
21889d3
86aa348
c3e7708
d7cbe6a
dd9452c
19ad8df
fa00f8b
b6d2b49
c811902
8e9c818
a8d9d13
608f7c8
638bcfe
9b18ccd
ebe4d56
63d2a5d
e99a71b
9b592b5
169e9d0
794efea
545cddd
83502cd
678fdc6
5293a14
bf284c6
bac80f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,12 +28,17 @@ import { | |
useGlobalFullScreen, | ||
useTimelineFullScreen, | ||
} from '../../../common/containers/use_full_screen'; | ||
import { useKibana } from '../../../common/lib/kibana'; | ||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector'; | ||
import { TimelineId } from '../../../../common/types/timeline'; | ||
import { timelineSelectors } from '../../store/timeline'; | ||
import { timelineDefaults } from '../../store/timeline/defaults'; | ||
import { isFullScreen } from '../timeline/body/column_headers'; | ||
import { updateTimelineGraphEventId } from '../../../timelines/store/timeline/actions'; | ||
import { | ||
updateTimelineGraphEventId, | ||
updateTimelineSessionViewEventId, | ||
updateTimelineSessionViewSessionId, | ||
} from '../../../timelines/store/timeline/actions'; | ||
import { inputsActions } from '../../../common/store/actions'; | ||
import { Resolver } from '../../../resolver/view'; | ||
import { | ||
|
@@ -70,6 +75,12 @@ const FullScreenButtonIcon = styled(EuiButtonIcon)` | |
margin: 4px 0 4px 0; | ||
`; | ||
|
||
const ScrollableFlexItem = styled(EuiFlexItem)` | ||
${({ theme }) => `margin: 0 ${theme.eui.euiSizeM};`} | ||
overflow: hidden; | ||
width: 100%; | ||
`; | ||
|
||
interface OwnProps { | ||
timelineId: TimelineId; | ||
} | ||
|
@@ -131,6 +142,14 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => { | |
const graphEventId = useDeepEqualSelector( | ||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).graphEventId | ||
); | ||
const { sessionView } = useKibana().services; | ||
const sessionViewId = useDeepEqualSelector( | ||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewId | ||
); | ||
const sessionViewMain = useMemo(() => { | ||
return sessionViewId !== null ? sessionView.getSessionView(sessionViewId) : null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any situation where it can be undefined? Would we want |
||
}, [sessionView, sessionViewId]); | ||
|
||
const getStartSelector = useMemo(() => startSelector(), []); | ||
const getEndSelector = useMemo(() => endSelector(), []); | ||
const getIsLoadingSelector = useMemo(() => isLoadingSelector(), []); | ||
|
@@ -180,6 +199,8 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => { | |
} | ||
} | ||
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: '' })); | ||
dispatch(updateTimelineSessionViewEventId({ id: timelineId, eventId: null })); | ||
dispatch(updateTimelineSessionViewSessionId({ id: timelineId, eventId: null })); | ||
}, [dispatch, timelineId, setTimelineFullScreen, setGlobalFullScreen]); | ||
|
||
useEffect(() => { | ||
|
@@ -219,7 +240,18 @@ const GraphOverlayComponent: React.FC<OwnProps> = ({ timelineId }) => { | |
[defaultDataView.patternList, isInTimeline, timelinePatterns] | ||
); | ||
|
||
if (fullScreen && !isInTimeline) { | ||
if (!isInTimeline && sessionViewId !== null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How it should behave in the fullScreen mode? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. like analyzer i think, which it does, we just have a small issue with the hard coded unless specified height of 500px coming from here https://github.com/elastic/kibana/blob/main/x-pack/plugins/session_view/public/components/session_view/styles.ts#L16 @zizhouW @mitodrummer @opauloh I think we should change the styles here so that the search bar/detail panel button take up as much space as the constituent components need, and then the process tree grows to fill the remaining part of a top level container. Passing a height will be buggy/hard for no reason with the full screen functionality in data grid/timeline I think. What do y'all think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so, the current way it works, it can't have auto height, because of infinite scrolling, so in order to enable full screen you would need to manually change the sessionView.getSessionView({
sessionEntityId,
height: fullScreen ? 'calc(100vh - 118px)' : '500px'
}) but having to know the height of the SessionView's search bar (118px), and the default height of the session view (500px) isn't ideal, so we are willing to change later to something more like this sessionView.getSessionView({
sessionEntityId,
isFullScreen: fullScreen
}) |
||
return ( | ||
<EuiFlexGroup alignItems="flexStart" gutterSize="none" direction="column"> | ||
<EuiFlexItem grow={false}> | ||
<EuiButtonEmpty iconType="cross" onClick={onCloseOverlay} size="xs"> | ||
{i18n.CLOSE_SESSION} | ||
</EuiButtonEmpty> | ||
</EuiFlexItem> | ||
<ScrollableFlexItem grow={2}>{sessionViewMain}</ScrollableFlexItem> | ||
</EuiFlexGroup> | ||
); | ||
} else if (fullScreen && !isInTimeline) { | ||
return ( | ||
<FullScreenOverlayContainer data-test-subj="overlayContainer"> | ||
<EuiHorizontalRule margin="none" /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,8 @@ import { useShallowEqualSelector } from '../../../../../common/hooks/use_selecto | |
import { | ||
setActiveTabTimeline, | ||
updateTimelineGraphEventId, | ||
updateTimelineSessionViewSessionId, | ||
updateTimelineSessionViewEventId, | ||
} from '../../../../store/timeline/actions'; | ||
import { | ||
useGlobalFullScreen, | ||
|
@@ -128,6 +130,24 @@ const ActionsComponent: React.FC<ActionProps> = ({ | |
} | ||
}, [dispatch, ecsData._id, timelineId, setGlobalFullScreen, setTimelineFullScreen]); | ||
|
||
const entryLeader = useMemo(() => { | ||
const { process } = ecsData; | ||
const entryLeaderIds = process?.entry_leader?.entity_id; | ||
if (entryLeaderIds !== undefined) { | ||
return entryLeaderIds[0]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always going to be the first one? And it's guaranteed to be an array of 1? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, but that's exactly why I wanted to get ecs changes in and then use real endpoint data to verify first. Seems to be the case so far. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to check array length at least. |
||
} else { | ||
return null; | ||
} | ||
}, [ecsData]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't expect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree, the better is to have a more specific to check. |
||
|
||
const openSessionView = useCallback(() => { | ||
if (entryLeader !== null) { | ||
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.session })); | ||
dispatch(updateTimelineSessionViewSessionId({ id: timelineId, eventId: entryLeader })); | ||
dispatch(updateTimelineSessionViewEventId({ id: timelineId, eventId: entryLeader })); | ||
} | ||
}, [dispatch, timelineId, entryLeader]); | ||
|
||
return ( | ||
<ActionsContainer> | ||
{showCheckboxes && !tGridEnabled && ( | ||
|
@@ -220,6 +240,21 @@ const ActionsComponent: React.FC<ActionProps> = ({ | |
</EventsTdContent> | ||
</div> | ||
) : null} | ||
{entryLeader !== null ? ( | ||
<div> | ||
<EventsTdContent textAlign="center" width={DEFAULT_ACTION_BUTTON_WIDTH}> | ||
<EuiToolTip data-test-subj="expand-event-tool-tip" content={i18n.OPEN_SESSION_VIEW}> | ||
<EuiButtonIcon | ||
aria-label={i18n.VIEW_DETAILS_FOR_ROW({ ariaRowindex, columnValues })} | ||
data-test-subj="session-view-button" | ||
iconType="console" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any word on when they expect the icon in the mocks to be added to eui? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the Icons are merged in Eui, and it seems we will have a quick release today 🤞 or at most tomorrow There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pr here #128313 |
||
onClick={openSessionView} | ||
size="s" | ||
/> | ||
</EuiToolTip> | ||
</EventsTdContent> | ||
</div> | ||
) : null} | ||
</> | ||
</ActionsContainer> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; | ||
import React, { useMemo } from 'react'; | ||
import styled from 'styled-components'; | ||
import { timelineSelectors } from '../../../store/timeline'; | ||
import { useKibana } from '../../../../common/lib/kibana'; | ||
import { TimelineId } from '../../../../../common/types/timeline'; | ||
import { timelineDefaults } from '../../../../timelines/store/timeline/defaults'; | ||
import { useDeepEqualSelector } from '../../../../common/hooks/use_selector'; | ||
|
||
const FullWidthFlexGroup = styled(EuiFlexGroup)` | ||
margin: 0; | ||
width: 100%; | ||
overflow: hidden; | ||
`; | ||
|
||
const ScrollableFlexItem = styled(EuiFlexItem)` | ||
${({ theme }) => `margin: 0 ${theme.eui.euiSizeM};`} | ||
overflow: hidden; | ||
`; | ||
|
||
interface Props { | ||
timelineId: TimelineId; | ||
} | ||
|
||
const SessionTabContent: React.FC<Props> = ({ timelineId }) => { | ||
const { sessionView } = useKibana().services; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if you can just have a |
||
|
||
const getTimeline = useMemo(() => timelineSelectors.getTimelineByIdSelector(), []); | ||
|
||
const sessionViewId = useDeepEqualSelector( | ||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewId | ||
); | ||
const sessionViewMain = useMemo(() => { | ||
return sessionViewId !== null ? sessionView.getSessionView(sessionViewId) : null; | ||
}, [sessionView, sessionViewId]); | ||
|
||
return <ScrollableFlexItem grow={2}>{sessionViewMain}</ScrollableFlexItem>; | ||
}; | ||
|
||
// eslint-disable-next-line import/no-default-export | ||
export default SessionTabContent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need
graphEventId.length > 0
? Can we get away withshouldShowOverlay = graphEventId ?? sessionViewId?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we unify the
!=
and!==
approach in this statement just to use one? Could begraphEventId
orsessionViewId
asundefined
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm nervous to change it, for whatever reason, graph event id is set to empty string sometimes and is undefined at other times