mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Added timeline investigation, fixed coloring of events. Added node limit, removed unknown targets
This commit is contained in:
parent
c7fb622c2a
commit
117b2ad993
5 changed files with 62 additions and 21 deletions
|
@ -316,7 +316,7 @@ const determineEntityNodeShape = (
|
|||
return { shape: 'diamond', icon: 'globe' };
|
||||
}
|
||||
|
||||
return { shape: 'hexagon', icon: 'questionInCircle' };
|
||||
return { shape: 'hexagon', icon: '' };
|
||||
};
|
||||
|
||||
const sortNodes = (nodesMap: Record<string, NodeDataModel>) => {
|
||||
|
|
|
@ -44,15 +44,6 @@ export const GraphNodeExpandPopover: React.FC<GraphNodeExpandPopoverProps> = mem
|
|||
data-test-subj="graphNodeExpandPopover"
|
||||
>
|
||||
<EuiListGroup gutterSize="none" bordered={false} flush={true}>
|
||||
<ExpandPopoverListItem
|
||||
iconType="visTagCloud"
|
||||
label={i18n.translate(
|
||||
'xpack.securitySolution.flyout.documentDetails.left.graphNodeExpandPopover.exploreRelatedEntities',
|
||||
{ defaultMessage: 'Explore related entities' }
|
||||
)}
|
||||
onClick={onExploreRelatedEntitiesClick}
|
||||
data-test-subj={GRAPH_NODE_POPOVER_EXPLORE_RELATED_ITEM_ID}
|
||||
/>
|
||||
<ExpandPopoverListItem
|
||||
iconType="users"
|
||||
label={i18n.translate(
|
||||
|
@ -71,6 +62,15 @@ export const GraphNodeExpandPopover: React.FC<GraphNodeExpandPopoverProps> = mem
|
|||
onClick={onShowActionsOnEntityClick}
|
||||
data-test-subj={GRAPH_NODE_POPOVER_SHOW_ACTIONS_ON_ITEM_ID}
|
||||
/>
|
||||
<ExpandPopoverListItem
|
||||
iconType="visTagCloud"
|
||||
label={i18n.translate(
|
||||
'xpack.securitySolution.flyout.documentDetails.left.graphNodeExpandPopover.exploreRelatedEntities',
|
||||
{ defaultMessage: 'Explore related entities' }
|
||||
)}
|
||||
onClick={onExploreRelatedEntitiesClick}
|
||||
data-test-subj={GRAPH_NODE_POPOVER_EXPLORE_RELATED_ITEM_ID}
|
||||
/>
|
||||
</EuiListGroup>
|
||||
</GraphPopover>
|
||||
);
|
||||
|
|
|
@ -19,6 +19,10 @@ import {
|
|||
import type { Filter, Query, TimeRange, BoolQuery, PhraseFilter } from '@kbn/es-query';
|
||||
import { css } from '@emotion/css';
|
||||
import { getEsQueryConfig } from '@kbn/data-service';
|
||||
import dateMath from '@kbn/datemath';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { normalizeTimeRange } from '../../../../common/utils/normalize_time_range';
|
||||
import { InvestigateInTimelineButton } from '../../../../common/components/event_details/investigate_in_timeline_button';
|
||||
import { useGetScopedSourcererDataView } from '../../../../sourcerer/components/use_get_sourcerer_data_view';
|
||||
import { SourcererScopeName } from '../../../../sourcerer/store/model';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
|
@ -47,15 +51,22 @@ const useTimeRange = (timestamp: string) => {
|
|||
return { timeRange, setTimeRange, setPartialTimeRange };
|
||||
};
|
||||
|
||||
const useGraphData = (eventIds: string[], timeRange: TimeRange, filter: { bool: BoolQuery }) => {
|
||||
const useGraphData = (
|
||||
eventIds: string[],
|
||||
isAlert: boolean,
|
||||
timeRange: TimeRange,
|
||||
filter: { bool: BoolQuery }
|
||||
) => {
|
||||
const { data, refresh, isFetching } = useFetchGraphData({
|
||||
req: {
|
||||
query: {
|
||||
eventIds,
|
||||
eventIds: isAlert ? eventIds : [],
|
||||
esQuery: filter,
|
||||
start: timeRange.from,
|
||||
end: timeRange.to,
|
||||
},
|
||||
nodesLimit: 50,
|
||||
showUnknownTarget: false,
|
||||
},
|
||||
options: {
|
||||
refetchOnWindowFocus: false,
|
||||
|
@ -169,7 +180,7 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
});
|
||||
const [searchFilters, setSearchFilters] = useState<Filter[]>(() => []);
|
||||
const { getFieldsData, dataAsNestedObject } = useDocumentDetailsContext();
|
||||
const { eventIds, timestamp } = useGraphPreview({
|
||||
const { eventIds, isAlert, timestamp } = useGraphPreview({
|
||||
getFieldsData,
|
||||
ecsData: dataAsNestedObject,
|
||||
});
|
||||
|
@ -183,7 +194,9 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
buildEsQuery(
|
||||
dataView,
|
||||
[],
|
||||
[...searchFilters],
|
||||
isAlert
|
||||
? [...searchFilters]
|
||||
: addFilter(dataView?.id ?? '', searchFilters, 'event.id', eventIds[0]),
|
||||
getEsQueryConfig(uiSettings as Parameters<typeof getEsQueryConfig>[0])
|
||||
)
|
||||
);
|
||||
|
@ -193,11 +206,13 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
buildEsQuery(
|
||||
dataView,
|
||||
[],
|
||||
[...searchFilters],
|
||||
isAlert
|
||||
? [...searchFilters]
|
||||
: addFilter(dataView?.id ?? '', searchFilters, 'event.id', eventIds[0]),
|
||||
getEsQueryConfig(uiSettings as Parameters<typeof getEsQueryConfig>[0])
|
||||
)
|
||||
);
|
||||
}, [searchFilters, dataView, uiSettings]);
|
||||
}, [searchFilters, dataView, uiSettings, isAlert, eventIds]);
|
||||
|
||||
const { nodeExpandPopover, popoverOpenWrapper } = useGraphPopovers(
|
||||
dataView?.id ?? '',
|
||||
|
@ -206,8 +221,15 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
const expandButtonClickHandler = (...args: unknown[]) =>
|
||||
popoverOpenWrapper(nodeExpandPopover.onNodeExpandButtonClick, ...args);
|
||||
const isPopoverOpen = [nodeExpandPopover].some(({ state: { isOpen } }) => isOpen);
|
||||
const { data, refresh, isFetching } = useGraphData(eventIds, timeRange, query);
|
||||
const { data, refresh, isFetching } = useGraphData(eventIds, isAlert, timeRange, query);
|
||||
const nodes = useGraphNodes(data?.nodes ?? [], expandButtonClickHandler);
|
||||
const parsedTimeRange: TimeRange = useMemo(() => {
|
||||
return {
|
||||
...timeRange,
|
||||
from: dateMath.parse(timeRange.from),
|
||||
to: dateMath.parse(timeRange.to),
|
||||
};
|
||||
}, [timeRange]);
|
||||
|
||||
return (
|
||||
<div data-test-subj={GRAPH_VISUALIZATION_TEST_ID}>
|
||||
|
@ -223,8 +245,8 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
showQueryInput: false,
|
||||
isLoading: isFetching,
|
||||
isAutoRefreshDisabled: true,
|
||||
dateRangeFrom: timeRange.from.split('/')[0],
|
||||
dateRangeTo: timeRange.to.split('/')[0],
|
||||
dateRangeFrom: timeRange.from,
|
||||
dateRangeTo: timeRange.to,
|
||||
query: { query: '', language: 'kuery' },
|
||||
indexPatterns: [dataView],
|
||||
filters: searchFilters,
|
||||
|
@ -242,6 +264,19 @@ export const GraphVisualization: React.FC = memo(() => {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
<InvestigateInTimelineButton
|
||||
asEmptyButton
|
||||
dataProviders={[]}
|
||||
filters={addFilter(dataView?.id ?? '', searchFilters, 'event.id', eventIds[0])}
|
||||
keepDataView
|
||||
iconType={'timeline'}
|
||||
timeRange={{ ...normalizeTimeRange(parsedTimeRange), kind: 'absolute' }}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.flyout.documentDetails.left.graphVisualization.investigateInTimelineButtonLabel"
|
||||
defaultMessage="Investigate in Timeline"
|
||||
/>
|
||||
</InvestigateInTimelineButton>
|
||||
<React.Suspense fallback={null}>
|
||||
<GraphLazy
|
||||
css={css`
|
||||
|
|
|
@ -41,6 +41,7 @@ export const GraphPreviewContainer: React.FC = () => {
|
|||
eventIds,
|
||||
timestamp = new Date().toISOString(),
|
||||
isAuditLog,
|
||||
isAlert,
|
||||
} = useGraphPreview({
|
||||
getFieldsData,
|
||||
ecsData: dataAsNestedObject,
|
||||
|
@ -50,9 +51,10 @@ export const GraphPreviewContainer: React.FC = () => {
|
|||
const { isLoading, isError, data } = useFetchGraphData({
|
||||
req: {
|
||||
query: {
|
||||
eventIds,
|
||||
eventIds: isAlert ? eventIds : [],
|
||||
start: `${timestamp}||-30m`,
|
||||
end: `${timestamp}||+30m`,
|
||||
esQuery: !isAlert ? { bool: { filter: [{ terms: { 'event.id': eventIds } }] } } : undefined,
|
||||
},
|
||||
},
|
||||
options: {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import type { EcsSecurityExtension as Ecs } from '@kbn/securitysolution-ecs';
|
||||
import { ALERT_UUID } from '@kbn/rule-data-utils';
|
||||
import { get } from 'lodash/fp';
|
||||
import type { GetFieldsData } from './use_get_fields_data';
|
||||
import { getField, getFieldArray } from '../utils';
|
||||
|
@ -54,6 +55,8 @@ export interface UseGraphPreviewResult {
|
|||
* Boolean indicating if the event is an audit log (contains event ids, actor ids and action)
|
||||
*/
|
||||
isAuditLog: boolean;
|
||||
|
||||
isAlert: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,6 +80,7 @@ export const useGraphPreview = ({
|
|||
actorIds.length > 0 &&
|
||||
eventIds.length > 0 &&
|
||||
targetIds.length > 0;
|
||||
const isAlert = Boolean(getFieldsData(ALERT_UUID));
|
||||
|
||||
return { timestamp, eventIds, actorIds, action, targetIds, isAuditLog };
|
||||
return { timestamp, eventIds, actorIds, action, targetIds, isAuditLog, isAlert };
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue