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

[Session View] jumpToEntityId / investigatedAlertId behavior fixed. #129275

Merged
merged 26 commits into from
Apr 5, 2022
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
462adf2
Fix for process event pagination in session view
Mar 23, 2022
4b04f14
Merge branch 'main' of github.com:mitodrummer/kibana
Mar 28, 2022
f4229ea
Merge branch 'elastic:main' into main
mitodrummer Mar 28, 2022
60a3626
Merge branch 'elastic:main' into main
mitodrummer Mar 29, 2022
cbe4ffb
Merge branch 'elastic:main' into main
mitodrummer Mar 29, 2022
845cd5d
Merge branch 'elastic:main' into main
mitodrummer Mar 30, 2022
40bd685
Merge branch 'elastic:main' into main
mitodrummer Mar 31, 2022
ef424f6
Merge branch 'elastic:main' into main
mitodrummer Mar 31, 2022
812bd3a
plumbing work to get a few more props to session view when loaded via…
Apr 1, 2022
0c46a84
session config plumbing work done
Apr 1, 2022
616ed74
jump to event kinks worked out.
Apr 2, 2022
014c600
tests fixed
Apr 2, 2022
18baf5f
test fix
Apr 2, 2022
193b186
Merge branch 'main' into session_view_config
mitodrummer Apr 3, 2022
6a21be6
build error fixes
Apr 4, 2022
697ef93
Merge branch 'session_view_config' of github.com:mitodrummer/kibana i…
Apr 4, 2022
386db33
Merge branch 'main' into session_view_config
mitodrummer Apr 4, 2022
2c66f7f
addressed PR comments. cleanup
Apr 4, 2022
15499a5
addressed PR comments. cleanup
Apr 4, 2022
5ae911e
Merge branch 'elastic:main' into main
mitodrummer Apr 4, 2022
1f2eba0
Merge branch 'main' into session_view_config
Apr 4, 2022
821d42a
post merge fixes
Apr 4, 2022
64661e5
Merge branch 'main' into session_view_config
mitodrummer Apr 4, 2022
b931b0e
pr comments addressed
Apr 5, 2022
543e73c
Merge branch 'session_view_config' of github.com:mitodrummer/kibana i…
Apr 5, 2022
d1d14fa
Merge branch 'main' into session_view_config
mitodrummer Apr 5, 2022
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 @@ -105,7 +105,7 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({
itemsPerPage,
itemsPerPageOptions,
kqlMode,
sessionViewId,
sessionViewConfig,
showCheckboxes,
sort,
} = defaultModel,
Expand Down Expand Up @@ -164,11 +164,11 @@ const StatefulEventsViewerComponent: React.FC<Props> = ({

const graphOverlay = useMemo(() => {
const shouldShowOverlay =
(graphEventId != null && graphEventId.length > 0) || sessionViewId !== null;
(graphEventId != null && graphEventId.length > 0) || sessionViewConfig;
return shouldShowOverlay ? (
<GraphOverlay timelineId={id} SessionView={SessionView} Navigation={Navigation} />
) : null;
}, [graphEventId, id, sessionViewId, SessionView, Navigation]);
}, [graphEventId, id, sessionViewConfig, SessionView, Navigation]);
const setQuery = useCallback(
(inspect, loading, refetch) => {
dispatch(inputsActions.setQuery({ id, inputId: 'global', inspect, loading, refetch }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ const GraphOverlayComponent: React.FC<GraphOverlayProps> = ({
const graphEventId = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).graphEventId
);
const sessionViewId = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewId
const sessionViewConfig = useDeepEqualSelector(
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).sessionViewConfig
);

const getStartSelector = useMemo(() => startSelector(), []);
Expand Down Expand Up @@ -134,7 +134,7 @@ const GraphOverlayComponent: React.FC<GraphOverlayProps> = ({
[defaultDataView.patternList, isInTimeline, timelinePatterns]
);

if (!isInTimeline && sessionViewId !== null) {
if (!isInTimeline && sessionViewConfig) {
if (fullScreen) {
return (
<FullScreenOverlayContainer data-test-subj="overlayContainer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { useShallowEqualSelector } from '../../../../../common/hooks/use_selecto
import {
setActiveTabTimeline,
updateTimelineGraphEventId,
updateTimelineSessionViewSessionId,
updateTimelineSessionViewConfig,
} from '../../../../store/timeline/actions';
import {
useGlobalFullScreen,
Expand Down Expand Up @@ -129,34 +129,48 @@ 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 && entryLeaderIds.length > 0) {
return entryLeaderIds[0];
} else {
const sessionViewConfig = useMemo(() => {
const { process, _id, timestamp } = ecsData;
const sessionEntityId = process?.entry_leader?.entity_id?.[0];

if (sessionEntityId === undefined) {
return null;
}
}, [ecsData]);

const jumpToEntityId = process?.entity_id?.[0];
const investigatedAlertId = eventType === 'signal' ? _id : undefined;

let jumpToCursor = timestamp;
if (investigatedAlertId) {
jumpToCursor = ecsData.kibana?.alert.original_time?.[0];
}

return {
sessionEntityId,
jumpToEntityId,
jumpToCursor,
investigatedAlertId,
};
}, [ecsData, eventType]);

const openSessionView = useCallback(() => {
const dataGridIsFullScreen = document.querySelector('.euiDataGrid--fullScreen');
if (timelineId === TimelineId.active) {
if (dataGridIsFullScreen) {
setTimelineFullScreen(true);
}
if (entryLeader !== null) {
if (sessionViewConfig !== null) {
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.session }));
}
} else {
if (dataGridIsFullScreen) {
setGlobalFullScreen(true);
}
}
if (entryLeader !== null) {
dispatch(updateTimelineSessionViewSessionId({ id: timelineId, eventId: entryLeader }));
if (sessionViewConfig !== null) {
dispatch(updateTimelineSessionViewConfig({ id: timelineId, sessionViewConfig }));
}
}, [dispatch, timelineId, entryLeader, setGlobalFullScreen, setTimelineFullScreen]);
}, [dispatch, timelineId, sessionViewConfig, setGlobalFullScreen, setTimelineFullScreen]);

return (
<ActionsContainer>
Expand Down Expand Up @@ -250,7 +264,7 @@ const ActionsComponent: React.FC<ActionProps> = ({
</EventsTdContent>
</div>
) : null}
{entryLeader !== null ? (
{sessionViewConfig !== null ? (
<div>
<EventsTdContent textAlign="center" width={DEFAULT_ACTION_BUTTON_WIDTH}>
<EuiToolTip data-test-subj="expand-event-tool-tip" content={i18n.OPEN_SESSION_VIEW}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,19 @@ import {
} from '../../../../common/containers/use_full_screen';
import {
updateTimelineGraphEventId,
updateTimelineSessionViewSessionId,
updateTimelineSessionViewConfig,
setActiveTabTimeline,
} from '../../../../timelines/store/timeline/actions';
import { detectionsTimelineIds } from '../../../containers/helpers';
import * as i18n from './translations';

export interface SessionViewConfig {
sessionEntityId: string;
jumpToEntityId?: string;
jumpToCursor?: string;
investigatedAlertId?: string;
}

const FullScreenButtonIcon = styled(EuiButtonIcon)`
margin: 4px 0 4px 0;
`;
Expand Down Expand Up @@ -105,7 +112,7 @@ export const useSessionView = ({
const { globalFullScreen, setGlobalFullScreen } = useGlobalFullScreen();
const { timelineFullScreen, setTimelineFullScreen } = useTimelineFullScreen();

const { graphEventId, sessionViewId, activeTab, prevActiveTab } = useDeepEqualSelector(
const { graphEventId, sessionViewConfig, activeTab, prevActiveTab } = useDeepEqualSelector(
(state) => getTimeline(state, timelineId) ?? timelineDefaults
);
const onCloseOverlay = useCallback(() => {
Expand All @@ -126,15 +133,15 @@ export const useSessionView = ({
}
if (timelineId !== TimelineId.active) {
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: '' }));
dispatch(updateTimelineSessionViewSessionId({ id: timelineId, eventId: null }));
dispatch(updateTimelineSessionViewConfig({ id: timelineId, sessionViewConfig: null }));
} else {
if (activeTab === TimelineTabs.graph) {
dispatch(updateTimelineGraphEventId({ id: timelineId, graphEventId: '' }));
if (prevActiveTab === TimelineTabs.session && !sessionViewId) {
if (prevActiveTab === TimelineTabs.session && !sessionViewConfig) {
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.query }));
}
} else if (activeTab === TimelineTabs.session) {
dispatch(updateTimelineSessionViewSessionId({ id: timelineId, eventId: null }));
dispatch(updateTimelineSessionViewConfig({ id: timelineId, sessionViewConfig: null }));
if (prevActiveTab === TimelineTabs.graph && !graphEventId) {
dispatch(setActiveTabTimeline({ id: timelineId, activeTab: TimelineTabs.query }));
} else {
Expand All @@ -150,7 +157,7 @@ export const useSessionView = ({
activeTab,
prevActiveTab,
graphEventId,
sessionViewId,
sessionViewConfig,
]);
const fullScreen = useMemo(
() => isFullScreen({ globalFullScreen, timelineId, timelineFullScreen }),
Expand Down Expand Up @@ -187,13 +194,13 @@ export const useSessionView = ({
});

const sessionViewComponent = useMemo(() => {
return sessionViewId !== null
return sessionViewConfig
? sessionView.getSessionView({
sessionEntityId: sessionViewId,
...sessionViewConfig,
loadAlertDetails: openDetailsPanel,
})
: null;
}, [openDetailsPanel, sessionView, sessionViewId]);
}, [openDetailsPanel, sessionView, sessionViewConfig]);

const navigation = useMemo(() => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export {
upsertColumn,
} from '../../../../../timelines/public';
import { ResolveTimelineConfig } from '../../components/open_timeline/types';
import { SessionViewConfig } from '../../components/timeline/session_tab_content/use_session_view';

const actionCreator = actionCreatorFactory('x-pack/security_solution/local/timeline');

Expand Down Expand Up @@ -81,10 +82,10 @@ export const updateTimelineGraphEventId = actionCreator<{ id: string; graphEvent
'UPDATE_TIMELINE_GRAPH_EVENT_ID'
);

export const updateTimelineSessionViewSessionId = actionCreator<{
export const updateTimelineSessionViewConfig = actionCreator<{
id: string;
eventId: string | null;
}>('UPDATE_TIMELINE_SESSION_VIEW_SESSION_ID');
sessionViewConfig: SessionViewConfig | null;
}>('UPDATE_TIMELINE_SESSION_VIEW_CONFIG');

export const unPinEvent = actionCreator<{ id: string; eventId: string }>('UN_PIN_EVENT');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
} from '../../components/timeline/body/constants';
import { activeTimeline } from '../../containers/active_timeline_context';
import { ResolveTimelineConfig } from '../../components/open_timeline/types';

import { SessionViewConfig } from '../../components/timeline/session_tab_content/use_session_view';
export const isNotNull = <T>(value: T | null): value is T => value !== null;

interface AddTimelineHistoryParams {
Expand Down Expand Up @@ -287,13 +287,13 @@ export const updateGraphEventId = ({
};
};

export const updateSessionViewSessionId = ({
export const updateSessionViewConfig = ({
id,
eventId,
sessionViewConfig,
timelineById,
}: {
id: string;
eventId: string | null;
sessionViewConfig: SessionViewConfig | null;
timelineById: TimelineById;
}): TimelineById => {
const timeline = timelineById[id];
Expand All @@ -302,7 +302,7 @@ export const updateSessionViewSessionId = ({
...timelineById,
[id]: {
...timeline,
sessionViewId: eventId,
sessionViewConfig,
},
};
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type {
import { PinnedEvent } from '../../../../common/types/timeline/pinned_event';
import type { TGridModelForTimeline } from '../../../../../timelines/public';
import { ResolveTimelineConfig } from '../../components/open_timeline/types';
import type { SessionViewConfig } from '../../components/timeline/session_tab_content/use_session_view';

export const DEFAULT_PAGE_COUNT = 2; // Eui Pager will not render unless this is a minimum of 2 pages
export type KqlMode = 'filter' | 'search';
Expand Down Expand Up @@ -63,7 +64,7 @@ export type TimelineModel = TGridModelForTimeline & {
resolveTimelineConfig?: ResolveTimelineConfig;
showSaveModal?: boolean;
savedQueryId?: string | null;
sessionViewId: string | null;
sessionViewConfig: SessionViewConfig | null;
/** When true, show the timeline flyover */
show: boolean;
/** status: active | draft */
Expand Down Expand Up @@ -119,7 +120,7 @@ export type SubsetTimelineModel = Readonly<
| 'dateRange'
| 'selectAll'
| 'selectedEventIds'
| 'sessionViewId'
| 'sessionViewConfig'
| 'show'
| 'showCheckboxes'
| 'sort'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
updateTimeline,
updateTimelineGraphEventId,
updateTitleAndDescription,
updateTimelineSessionViewSessionId,
updateTimelineSessionViewConfig,
toggleModalSaveTimeline,
updateEqlOptions,
setTimelineUpdatedAt,
Expand Down Expand Up @@ -78,7 +78,7 @@ import {
updateGraphEventId,
updateFilters,
updateTimelineEventType,
updateSessionViewSessionId,
updateSessionViewConfig,
} from './helpers';

import { TimelineState, EMPTY_TIMELINE_BY_ID } from './types';
Expand Down Expand Up @@ -148,9 +148,13 @@ export const timelineReducer = reducerWithInitialState(initialTimelineState)
...state,
timelineById: updateGraphEventId({ id, graphEventId, timelineById: state.timelineById }),
}))
.case(updateTimelineSessionViewSessionId, (state, { id, eventId }) => ({
.case(updateTimelineSessionViewConfig, (state, { id, sessionViewConfig }) => ({
...state,
timelineById: updateSessionViewSessionId({ id, eventId, timelineById: state.timelineById }),
timelineById: updateSessionViewConfig({
id,
sessionViewConfig,
timelineById: state.timelineById,
}),
}))
.case(pinEvent, (state, { id, eventId }) => ({
...state,
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/session_view/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const PROCESS_EVENTS_INDEX = 'logs-endpoint.events.process-default';
export const PREVIEW_ALERTS_INDEX = '.preview.alerts-security.alerts-default';
export const ENTRY_SESSION_ENTITY_ID_PROPERTY = 'process.entry_leader.entity_id';
export const ALERT_UUID_PROPERTY = 'kibana.alert.uuid';
export const KIBANA_DATE_FORMAT = 'MMM DD, YYYY @ hh:mm:ss.SSS';
export const KIBANA_DATE_FORMAT = 'MMM DD, YYYY @ hh:mm:ss.SSSSSS';
export const ALERT_STATUS = {
OPEN: 'open',
ACKNOWLEDGED: 'acknowledged',
Expand All @@ -33,7 +33,7 @@ export const ALERT_STATUS = {
// if not 100s of thousands of events, and to be required to page through these sessions to find more search matches is not a great experience. Future iterations of the
// search functionality will instead use a separate ES backend search to avoid this.
// 3. Fewer round trips to the backend!
export const PROCESS_EVENTS_PER_PAGE = 1000;
export const PROCESS_EVENTS_PER_PAGE = 2000;

// As an initial approach, we won't be implementing pagination for alerts.
// Instead we will load this fixed amount of alerts as a maximum for a session.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ export const mockAlerts: ProcessEvent[] = [
status: 'active',
workflow_status: 'open',
reason: 'process event created low alert cmd test alert.',
original_time: new Date('2021-11-23T15:25:04.218Z'),
original_time: '2021-11-23T15:25:04.218Z',
original_event: {
action: 'exec',
},
Expand Down Expand Up @@ -844,7 +844,7 @@ export const mockAlerts: ProcessEvent[] = [
status: 'active',
workflow_status: 'open',
reason: 'process event created low alert cmd test alert.',
original_time: new Date('2021-11-23T15:25:05.202Z'),
original_time: '2021-11-23T15:25:05.202Z',
original_event: {
action: 'exit',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export interface ProcessEventAlert {
reason: string;
workflow_status: string;
status: string;
original_time: Date;
original_time: string;
original_event: {
action: string;
};
Expand Down
16 changes: 9 additions & 7 deletions x-pack/plugins/session_view/common/utils/sort_processes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
import { Process } from '../types/process_tree';

export const sortProcesses = (a: Process, b: Process) => {
const eventAStartTime = new Date(a.getDetails().process.start);
const eventBStartTime = new Date(b.getDetails().process.start);
const eventAStartTime = a.getDetails()?.process.start;
const eventBStartTime = b.getDetails()?.process.start;

if (eventAStartTime < eventBStartTime) {
return -1;
}
if (eventAStartTime && eventBStartTime) {
if (eventAStartTime < eventBStartTime) {
return -1;
}

if (eventAStartTime > eventBStartTime) {
return 1;
if (eventAStartTime > eventBStartTime) {
return 1;
}
}

return 0;
Expand Down
Loading