mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution][Alert details] - move useBasicDataFromDetailsData hook to flyout folder (#190106)
This commit is contained in:
parent
d971c6a10e
commit
ac5d6921d0
30 changed files with 313 additions and 148 deletions
|
@ -8,12 +8,12 @@
|
|||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import { InvestigationGuideView } from './investigation_guide_view';
|
||||
import type { GetBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import type { UseBasicDataFromDetailsDataResult } from '../../../flyout/document_details/shared/hooks/use_basic_data_from_details_data';
|
||||
|
||||
const defaultProps = {
|
||||
basicData: {
|
||||
ruleId: 'rule-id',
|
||||
} as unknown as GetBasicDataFromDetailsData,
|
||||
} as unknown as UseBasicDataFromDetailsDataResult,
|
||||
ruleNote: 'test note',
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import { EuiSpacer, EuiTitle, EuiText } from '@elastic/eui';
|
||||
import React, { createContext } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import type { GetBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import type { UseBasicDataFromDetailsDataResult } from '../../../flyout/document_details/shared/hooks/use_basic_data_from_details_data';
|
||||
import * as i18n from './translations';
|
||||
import { MarkdownRenderer } from '../markdown_editor';
|
||||
import { LineClamp } from '../line_clamp';
|
||||
|
@ -18,13 +18,13 @@ export const Indent = styled.div`
|
|||
word-break: break-word;
|
||||
`;
|
||||
|
||||
export const BasicAlertDataContext = createContext<Partial<GetBasicDataFromDetailsData>>({});
|
||||
export const BasicAlertDataContext = createContext<Partial<UseBasicDataFromDetailsDataResult>>({});
|
||||
|
||||
interface InvestigationGuideViewProps {
|
||||
/**
|
||||
* An object of basic fields from the event details data
|
||||
*/
|
||||
basicData: GetBasicDataFromDetailsData;
|
||||
basicData: UseBasicDataFromDetailsDataResult;
|
||||
/**
|
||||
* The markdown text of rule.note
|
||||
*/
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { FC } from 'react';
|
|||
import React, { useCallback } from 'react';
|
||||
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
|
||||
import { DocumentDetailsRightPanelKey } from '../shared/constants/panel_keys';
|
||||
import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../shared/hooks/use_basic_data_from_details_data';
|
||||
import {
|
||||
EndpointIsolateSuccess,
|
||||
HostIsolationPanel,
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { FC } from 'react';
|
|||
import React, { useMemo } from 'react';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { getSourcererScopeId } from '../../../../helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { SecurityCellActionType } from '../../../../app/actions/constants';
|
||||
import {
|
||||
CellActionsMode,
|
||||
|
|
|
@ -15,9 +15,9 @@ import { useDocumentDetailsContext } from '../../shared/context';
|
|||
import { useInvestigationTimeEnrichment } from '../../shared/hooks/use_investigation_enrichment';
|
||||
import type { RouteSpyState } from '../../../../common/utils/route/types';
|
||||
import {
|
||||
type GetBasicDataFromDetailsData,
|
||||
type UseBasicDataFromDetailsDataResult,
|
||||
useBasicDataFromDetailsData,
|
||||
} from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
} from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { mockContextValue } from '../../shared/mocks/mock_context';
|
||||
|
||||
jest.mock('../../../../timelines/containers/details');
|
||||
|
@ -25,7 +25,7 @@ jest.mock('../../../../sourcerer/containers');
|
|||
jest.mock('../../../../common/utils/route/use_route_spy');
|
||||
jest.mock('../../shared/context');
|
||||
jest.mock('../../shared/hooks/use_investigation_enrichment');
|
||||
jest.mock('../../../../timelines/components/side_panel/event_details/helpers');
|
||||
jest.mock('../../shared/hooks/use_basic_data_from_details_data');
|
||||
|
||||
describe('useThreatIntelligenceDetails', () => {
|
||||
beforeEach(() => {
|
||||
|
@ -42,7 +42,7 @@ describe('useThreatIntelligenceDetails', () => {
|
|||
|
||||
jest
|
||||
.mocked(useBasicDataFromDetailsData)
|
||||
.mockReturnValue({ isAlert: true } as unknown as GetBasicDataFromDetailsData);
|
||||
.mockReturnValue({ isAlert: true } as unknown as UseBasicDataFromDetailsDataResult);
|
||||
|
||||
jest.mocked(useSourcererDataView).mockReturnValue({
|
||||
browserFields: {},
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||
import { SecurityPageName } from '@kbn/deeplinks-security';
|
||||
import type { RunTimeMappings } from '../../../../../common/api/search_strategy';
|
||||
import type { CtiEnrichment, EventFields } from '../../../../../common/search_strategy';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import {
|
||||
filterDuplicateEnrichments,
|
||||
getEnrichmentFields,
|
||||
|
|
|
@ -15,7 +15,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { useKibana } from '../../../../common/lib/kibana';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import {
|
||||
ALERT_DESCRIPTION_DETAILS_TEST_ID,
|
||||
ALERT_DESCRIPTION_TITLE_TEST_ID,
|
||||
|
|
|
@ -15,7 +15,7 @@ import { DocumentStatus } from './status';
|
|||
import { DocumentSeverity } from './severity';
|
||||
import { RiskScore } from './risk_score';
|
||||
import { useRefetchByScope } from '../hooks/use_refetch_by_scope';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { PreferenceFormattedDate } from '../../../../common/components/formatted_date';
|
||||
import { FLYOUT_ALERT_HEADER_TITLE_TEST_ID, ALERT_SUMMARY_PANEL_TEST_ID } from './test_ids';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { EuiSpacer } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FlyoutTitle } from '../../../shared/components/flyout_title';
|
||||
import { DocumentSeverity } from './severity';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
import { PreferenceFormattedDate } from '../../../../common/components/formatted_date';
|
||||
import { FLYOUT_EVENT_HEADER_TITLE_TEST_ID } from './test_ids';
|
||||
|
|
|
@ -11,7 +11,7 @@ import { EuiButtonIcon, EuiCopy, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { NewChatByTitle } from '@kbn/elastic-assistant';
|
||||
import { useGetAlertDetailsFlyoutLink } from '../../../../timelines/components/side_panel/event_details/use_get_alert_details_flyout_link';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { useAssistant } from '../hooks/use_assistant';
|
||||
import {
|
||||
ALERT_SUMMARY_CONVERSATION_ID,
|
||||
|
|
|
@ -12,7 +12,7 @@ import { EuiFlexGroup, EuiFlexItem, EuiInMemoryTable, EuiPanel, EuiTitle } from
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { convertHighlightedFieldsToTableRow } from '../../shared/utils/highlighted_fields_helpers';
|
||||
import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { HighlightedFieldsCell } from './highlighted_fields_cell';
|
||||
import { CellActions } from './cell_actions';
|
||||
import { HIGHLIGHTED_FIELDS_DETAILS_TEST_ID, HIGHLIGHTED_FIELDS_TITLE_TEST_ID } from './test_ids';
|
||||
|
|
|
@ -21,9 +21,11 @@ import { mockDataFormattedForFieldBrowser } from '../../shared/mocks/mock_data_f
|
|||
import { TestProvider } from '@kbn/expandable-flyout/src/test/provider';
|
||||
import { mockContextValue } from '../../shared/mocks/mock_context';
|
||||
import { useExpandSection } from '../hooks/use_expand_section';
|
||||
import { useHighlightedFields } from '../../shared/hooks/use_highlighted_fields';
|
||||
|
||||
jest.mock('../../../../detection_engine/rule_management/logic/use_rule_with_fallback');
|
||||
jest.mock('../hooks/use_expand_section');
|
||||
jest.mock('../../shared/hooks/use_highlighted_fields');
|
||||
|
||||
const panelContextValue = {
|
||||
...mockContextValue,
|
||||
|
@ -65,6 +67,7 @@ describe('<InvestigationSection />', () => {
|
|||
|
||||
it('should render the component expanded if value is true in local storage', () => {
|
||||
(useExpandSection as jest.Mock).mockReturnValue(true);
|
||||
(useHighlightedFields as jest.Mock).mockReturnValue([]);
|
||||
|
||||
const { getByTestId } = renderInvestigationSection();
|
||||
expect(getByTestId(INVESTIGATION_SECTION_CONTENT_TEST_ID)).toBeVisible();
|
||||
|
@ -72,6 +75,7 @@ describe('<InvestigationSection />', () => {
|
|||
|
||||
it('should render investigation guide and highlighted fields when document is signal', () => {
|
||||
(useExpandSection as jest.Mock).mockReturnValue(true);
|
||||
(useHighlightedFields as jest.Mock).mockReturnValue([]);
|
||||
|
||||
const { getByTestId } = renderInvestigationSection();
|
||||
expect(getByTestId(INVESTIGATION_GUIDE_TEST_ID)).toBeInTheDocument();
|
||||
|
@ -80,6 +84,7 @@ describe('<InvestigationSection />', () => {
|
|||
|
||||
it('should not render investigation guide when document is not signal', () => {
|
||||
(useExpandSection as jest.Mock).mockReturnValue(true);
|
||||
(useHighlightedFields as jest.Mock).mockReturnValue([]);
|
||||
|
||||
const mockGetFieldsData = (field: string) => {
|
||||
switch (field) {
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
REASON_DETAILS_TEST_ID,
|
||||
REASON_TITLE_TEST_ID,
|
||||
} from './test_ids';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import { useDocumentDetailsContext } from '../../shared/context';
|
||||
|
||||
export const ALERT_REASON_BANNER = {
|
||||
|
|
|
@ -11,12 +11,12 @@ import { renderReactTestingLibraryWithI18n as render } from '@kbn/test-jest-help
|
|||
import { PanelHeader } from './header';
|
||||
import { allThreeTabs } from './hooks/use_tabs';
|
||||
import { GuidedOnboardingTourStep } from '../../../common/components/guided_onboarding_tour/tour_step';
|
||||
import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../shared/hooks/use_basic_data_from_details_data';
|
||||
|
||||
jest.mock('../shared/context', () => ({
|
||||
useDocumentDetailsContext: jest.fn().mockReturnValue({ dataFormattedForFieldBrowser: [] }),
|
||||
}));
|
||||
jest.mock('../../../timelines/components/side_panel/event_details/helpers', () => ({
|
||||
jest.mock('../shared/hooks/use_basic_data_from_details_data', () => ({
|
||||
useBasicDataFromDetailsData: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../../common/components/guided_onboarding_tour/tour_step', () => ({
|
||||
|
|
|
@ -16,7 +16,7 @@ import { FlyoutHeaderTabs } from '../../shared/components/flyout_header_tabs';
|
|||
import { AlertHeaderTitle } from './components/alert_header_title';
|
||||
import { EventHeaderTitle } from './components/event_header_title';
|
||||
import { useDocumentDetailsContext } from '../shared/context';
|
||||
import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../shared/hooks/use_basic_data_from_details_data';
|
||||
import {
|
||||
AlertsCasesTourSteps,
|
||||
getTourAnchor,
|
||||
|
|
|
@ -81,7 +81,11 @@ describe('useAssistant', () => {
|
|||
|
||||
expect(await getPromptContext()).toEqual({
|
||||
'@timestamp': ['2023-01-01T01:01:01.000Z'],
|
||||
_id: ['_id'],
|
||||
_index: ['index'],
|
||||
'agent.id': ['agent.id'],
|
||||
'event.category': ['registry'],
|
||||
'host.name': ['host-name'],
|
||||
'kibana.alert.ancestors.id': ['ancestors-id'],
|
||||
'kibana.alert.rule.description': ['rule-description'],
|
||||
'kibana.alert.rule.indices': ['rule-indices'],
|
||||
|
@ -89,8 +93,10 @@ describe('useAssistant', () => {
|
|||
'kibana.alert.rule.parameters.index': ['rule-parameters-index'],
|
||||
'kibana.alert.rule.type': ['query'],
|
||||
'kibana.alert.rule.uuid': ['rule-uuid'],
|
||||
'kibana.alert.url': ['alert-url'],
|
||||
'kibana.alert.workflow_status': ['open'],
|
||||
'process.entity_id': ['process-entity_id'],
|
||||
'user.name': ['user-name'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,7 +9,7 @@ import { useMemo } from 'react';
|
|||
import { groupBy } from 'lodash';
|
||||
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
|
||||
import type { CtiEnrichment } from '../../../../../common/search_strategy';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
import {
|
||||
filterDuplicateEnrichments,
|
||||
getEnrichmentFields,
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('useSessionPreview', () => {
|
|||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
index: 'kibana.alert.ancestors.index',
|
||||
investigatedAlertId: 'id',
|
||||
investigatedAlertId: '_id',
|
||||
jumpToCursor: '2023-01-01T00:00:00.000Z',
|
||||
jumpToEntityId: 'process.entity_id',
|
||||
sessionEntityId: 'process.entry_leader.entity_id',
|
||||
|
@ -79,8 +79,8 @@ describe('useSessionPreview', () => {
|
|||
});
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
index: '.some-index',
|
||||
investigatedAlertId: 'id',
|
||||
index: 'index',
|
||||
investigatedAlertId: '_id',
|
||||
jumpToCursor: '2023-01-01T00:00:00.000Z',
|
||||
jumpToEntityId: 'process.entity_id',
|
||||
sessionEntityId: 'process.entry_leader.entity_id',
|
||||
|
|
|
@ -9,7 +9,7 @@ import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
|
|||
import type { SessionViewConfig } from '@kbn/securitysolution-data-table/common/types';
|
||||
import type { GetFieldsData } from '../../../../common/hooks/use_get_fields_data';
|
||||
import { getField } from '../../shared/utils';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../shared/hooks/use_basic_data_from_details_data';
|
||||
|
||||
export interface UseSessionPreviewParams {
|
||||
/**
|
||||
|
|
|
@ -13,7 +13,7 @@ import { useEventDetails } from './hooks/use_event_details';
|
|||
import { FlyoutError } from '../../shared/components/flyout_error';
|
||||
import { FlyoutLoading } from '../../shared/components/flyout_loading';
|
||||
import type { SearchHit } from '../../../../common/search_strategy';
|
||||
import { useBasicDataFromDetailsData } from '../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from './hooks/use_basic_data_from_details_data';
|
||||
import type { DocumentDetailsProps } from './types';
|
||||
import type { GetFieldsData } from '../../../common/hooks/use_get_fields_data';
|
||||
import { useRuleWithFallback } from '../../../detection_engine/rule_management/logic/use_rule_with_fallback';
|
||||
|
|
|
@ -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 { renderHook } from '@testing-library/react-hooks';
|
||||
import { useBasicDataFromDetailsData } from './use_basic_data_from_details_data';
|
||||
import { mockDataFormattedForFieldBrowser } from '../mocks/mock_data_formatted_for_field_browser';
|
||||
|
||||
describe('useBasicDataFromDetailsData', () => {
|
||||
it('should return all empty properties', () => {
|
||||
const hookResult = renderHook(() => useBasicDataFromDetailsData(null));
|
||||
|
||||
expect(hookResult.result.current.agentId).toEqual('');
|
||||
expect(hookResult.result.current.alertId).toEqual('');
|
||||
expect(hookResult.result.current.alertUrl).toEqual('');
|
||||
expect(hookResult.result.current.data).toEqual(null);
|
||||
expect(hookResult.result.current.hostName).toEqual('');
|
||||
expect(hookResult.result.current.indexName).toEqual('');
|
||||
expect(hookResult.result.current.isAlert).toEqual(false);
|
||||
expect(hookResult.result.current.ruleDescription).toEqual('');
|
||||
expect(hookResult.result.current.ruleId).toEqual('');
|
||||
expect(hookResult.result.current.ruleName).toEqual('');
|
||||
expect(hookResult.result.current.timestamp).toEqual('');
|
||||
expect(hookResult.result.current.userName).toEqual('');
|
||||
});
|
||||
|
||||
it('should return all properties', () => {
|
||||
const hookResult = renderHook(() =>
|
||||
useBasicDataFromDetailsData(mockDataFormattedForFieldBrowser)
|
||||
);
|
||||
|
||||
expect(hookResult.result.current.agentId).toEqual('agent.id');
|
||||
expect(hookResult.result.current.alertId).toEqual('_id');
|
||||
expect(hookResult.result.current.alertUrl).toEqual('alert-url');
|
||||
expect(hookResult.result.current.data).toEqual(mockDataFormattedForFieldBrowser);
|
||||
expect(hookResult.result.current.hostName).toEqual('host-name');
|
||||
expect(hookResult.result.current.indexName).toEqual('index');
|
||||
expect(hookResult.result.current.isAlert).toEqual(true);
|
||||
expect(hookResult.result.current.ruleDescription).toEqual('rule-description');
|
||||
expect(hookResult.result.current.ruleId).toEqual('rule-uuid');
|
||||
expect(hookResult.result.current.ruleName).toEqual('rule-name');
|
||||
expect(hookResult.result.current.timestamp).toEqual('2023-01-01T01:01:01.000Z');
|
||||
expect(hookResult.result.current.userName).toEqual('user-name');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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 { some } from 'lodash/fp';
|
||||
import { useMemo } from 'react';
|
||||
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
|
||||
import { getAlertDetailsFieldValue } from '../../../../common/lib/endpoint/utils/get_event_details_field_values';
|
||||
|
||||
export interface UseBasicDataFromDetailsDataResult {
|
||||
agentId: string;
|
||||
alertId: string;
|
||||
alertUrl: string;
|
||||
data: TimelineEventsDetailsItem[] | null;
|
||||
hostName: string;
|
||||
indexName: string;
|
||||
isAlert: boolean;
|
||||
ruleDescription: string;
|
||||
ruleId: string;
|
||||
ruleName: string;
|
||||
timestamp: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
export const useBasicDataFromDetailsData = (
|
||||
data: TimelineEventsDetailsItem[] | null
|
||||
): UseBasicDataFromDetailsDataResult => {
|
||||
const agentId = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'agent', field: 'agent.id' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const alertId = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: '_id', field: '_id' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const alertUrl = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.url' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const hostName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'host', field: 'host.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const indexName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: '_index', field: '_index' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const isAlert = some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data);
|
||||
|
||||
const ruleDescription = useMemo(
|
||||
() =>
|
||||
getAlertDetailsFieldValue(
|
||||
{ category: 'kibana', field: 'kibana.alert.rule.description' },
|
||||
data
|
||||
),
|
||||
[data]
|
||||
);
|
||||
|
||||
const ruleId = useMemo(
|
||||
() =>
|
||||
isAlert
|
||||
? getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data)
|
||||
: getAlertDetailsFieldValue({ category: 'signal', field: 'signal.rule.id' }, data),
|
||||
[isAlert, data]
|
||||
);
|
||||
|
||||
const ruleName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const timestamp = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'base', field: '@timestamp' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const userName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'user', field: 'user.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
agentId,
|
||||
alertId,
|
||||
alertUrl,
|
||||
data,
|
||||
hostName,
|
||||
indexName,
|
||||
isAlert,
|
||||
ruleDescription,
|
||||
ruleId,
|
||||
ruleName,
|
||||
timestamp,
|
||||
userName,
|
||||
}),
|
||||
[
|
||||
agentId,
|
||||
alertId,
|
||||
alertUrl,
|
||||
data,
|
||||
hostName,
|
||||
indexName,
|
||||
isAlert,
|
||||
ruleDescription,
|
||||
ruleId,
|
||||
ruleName,
|
||||
timestamp,
|
||||
userName,
|
||||
]
|
||||
);
|
||||
};
|
|
@ -23,9 +23,15 @@ describe('useHighlightedFields', () => {
|
|||
it('should return data', () => {
|
||||
const hookResult = renderHook(() => useHighlightedFields({ dataFormattedForFieldBrowser }));
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -63,9 +69,15 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -93,11 +105,17 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'agent.id': {
|
||||
values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'],
|
||||
values: ['agent.id'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -121,9 +139,15 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -143,9 +167,15 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -175,12 +205,18 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
[agentIdField]: {
|
||||
values: ['deb35a20-70f8-458e-a64a-c9e6f7575893'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -209,12 +245,18 @@ describe('useHighlightedFields', () => {
|
|||
);
|
||||
|
||||
expect(hookResult.result.current).toEqual({
|
||||
'host.name': {
|
||||
values: ['host-name'],
|
||||
},
|
||||
'kibana.alert.rule.type': {
|
||||
values: ['query'],
|
||||
},
|
||||
'device.id': {
|
||||
values: ['expectedCrowdstrikeAgentId'],
|
||||
},
|
||||
'user.name': {
|
||||
values: ['user-name'],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,12 +11,12 @@ import type {
|
|||
UseInvestigationGuideParams,
|
||||
UseInvestigationGuideResult,
|
||||
} from './use_investigation_guide';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from './use_basic_data_from_details_data';
|
||||
import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback';
|
||||
import { mockDataFormattedForFieldBrowser } from '../mocks/mock_data_formatted_for_field_browser';
|
||||
import { useInvestigationGuide } from './use_investigation_guide';
|
||||
|
||||
jest.mock('../../../../timelines/components/side_panel/event_details/helpers');
|
||||
jest.mock('./use_basic_data_from_details_data');
|
||||
jest.mock('../../../../detection_engine/rule_management/logic/use_rule_with_fallback');
|
||||
|
||||
const dataFormattedForFieldBrowser = mockDataFormattedForFieldBrowser;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
|
||||
import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common';
|
||||
import type { GetBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import { useBasicDataFromDetailsData } from '../../../../timelines/components/side_panel/event_details/helpers';
|
||||
import type { UseBasicDataFromDetailsDataResult } from './use_basic_data_from_details_data';
|
||||
import { useBasicDataFromDetailsData } from './use_basic_data_from_details_data';
|
||||
import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback';
|
||||
|
||||
export interface UseInvestigationGuideParams {
|
||||
|
@ -27,11 +27,11 @@ export interface UseInvestigationGuideResult {
|
|||
*/
|
||||
error: unknown;
|
||||
/**
|
||||
*
|
||||
* The basic alert fields and their value
|
||||
*/
|
||||
basicAlertData: GetBasicDataFromDetailsData;
|
||||
basicAlertData: UseBasicDataFromDetailsDataResult;
|
||||
/**
|
||||
*
|
||||
* The note from the rule
|
||||
*/
|
||||
ruleNote: string | undefined;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,20 @@ export const ruleTypeField: TimelineEventsDetailsItem = {
|
|||
};
|
||||
|
||||
export const baseFields: TimelineEventsDetailsItem[] = [
|
||||
{
|
||||
category: 'agent',
|
||||
field: 'agent.id',
|
||||
values: ['agent.id'],
|
||||
originalValue: ['agent.id'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: '_id',
|
||||
field: '_id',
|
||||
values: ['_id'],
|
||||
originalValue: ['_id'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: 'base',
|
||||
field: '@timestamp',
|
||||
|
@ -65,6 +79,13 @@ export const baseFields: TimelineEventsDetailsItem[] = [
|
|||
originalValue: ['rule-parameters-index'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: 'kibana',
|
||||
field: 'kibana.alert.url',
|
||||
values: ['alert-url'],
|
||||
originalValue: ['alert-url'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: 'kibana',
|
||||
field: 'kibana.alert.rule.uuid',
|
||||
|
@ -86,6 +107,27 @@ export const baseFields: TimelineEventsDetailsItem[] = [
|
|||
originalValue: ['process-entity_id'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: 'host',
|
||||
field: 'host.name',
|
||||
values: ['host-name'],
|
||||
originalValue: ['host-name'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: 'user',
|
||||
field: 'user.name',
|
||||
values: ['user-name'],
|
||||
originalValue: ['user-name'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
{
|
||||
category: '_index',
|
||||
field: '_index',
|
||||
values: ['index'],
|
||||
originalValue: ['index'],
|
||||
isObjectArray: false,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,121 +5,8 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { some } from 'lodash/fp';
|
||||
import { useMemo } from 'react';
|
||||
import { getAlertDetailsFieldValue } from '../../../../common/lib/endpoint/utils/get_event_details_field_values';
|
||||
import type { TimelineEventsDetailsItem } from '../../../../../common/search_strategy';
|
||||
import { DEFAULT_ALERTS_INDEX, DEFAULT_PREVIEW_INDEX } from '../../../../../common/constants';
|
||||
|
||||
export interface GetBasicDataFromDetailsData {
|
||||
agentId?: string;
|
||||
alertId: string;
|
||||
alertUrl?: string;
|
||||
data: TimelineEventsDetailsItem[] | null;
|
||||
hostName: string;
|
||||
indexName?: string;
|
||||
isAlert: boolean;
|
||||
ruleDescription: string;
|
||||
ruleId: string;
|
||||
ruleName: string;
|
||||
timestamp: string;
|
||||
userName: string;
|
||||
}
|
||||
|
||||
export const useBasicDataFromDetailsData = (
|
||||
data: TimelineEventsDetailsItem[] | null
|
||||
): GetBasicDataFromDetailsData => {
|
||||
const isAlert = some({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data);
|
||||
|
||||
const ruleId = useMemo(
|
||||
() =>
|
||||
isAlert
|
||||
? getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.uuid' }, data)
|
||||
: getAlertDetailsFieldValue({ category: 'signal', field: 'signal.rule.id' }, data),
|
||||
[isAlert, data]
|
||||
);
|
||||
|
||||
const ruleName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.rule.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const ruleDescription = useMemo(
|
||||
() =>
|
||||
getAlertDetailsFieldValue(
|
||||
{ category: 'kibana', field: 'kibana.alert.rule.description' },
|
||||
data
|
||||
),
|
||||
[data]
|
||||
);
|
||||
|
||||
const alertId = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: '_id', field: '_id' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const indexName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: '_index', field: '_index' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const alertUrl = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'kibana', field: 'kibana.alert.url' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const agentId = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'agent', field: 'agent.id' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const hostName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'host', field: 'host.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const userName = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'user', field: 'user.name' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
const timestamp = useMemo(
|
||||
() => getAlertDetailsFieldValue({ category: 'base', field: '@timestamp' }, data),
|
||||
[data]
|
||||
);
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
agentId,
|
||||
alertId,
|
||||
alertUrl,
|
||||
data,
|
||||
hostName,
|
||||
indexName,
|
||||
isAlert,
|
||||
ruleDescription,
|
||||
ruleId,
|
||||
ruleName,
|
||||
timestamp,
|
||||
userName,
|
||||
}),
|
||||
[
|
||||
agentId,
|
||||
alertId,
|
||||
alertUrl,
|
||||
data,
|
||||
hostName,
|
||||
indexName,
|
||||
isAlert,
|
||||
ruleDescription,
|
||||
ruleId,
|
||||
ruleName,
|
||||
timestamp,
|
||||
userName,
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
The referenced alert _index in the flyout uses the `.internal.` such as
|
||||
`.internal.alerts-security.alerts-spaceId` in the alert page flyout and
|
||||
|
|
|
@ -2544,6 +2544,11 @@
|
|||
"discover.embeddable.search.displayName": "rechercher",
|
||||
"discover.errorCalloutShowErrorMessage": "Afficher les détails",
|
||||
"discover.esqlMode.selectedColumnsCallout": "Affichage de {selectedColumnsNumber} champs sur {esqlQueryColumnsNumber}. Ajoutez-en d’autres depuis la liste des champs disponibles.",
|
||||
"discover.esqlToDataViewTransitionModal.closeButtonLabel": "Basculer sans sauvegarder",
|
||||
"discover.esqlToDataViewTransitionModal.dismissButtonLabel": "Ne plus afficher cet avertissement",
|
||||
"discover.esqlToDataViewTransitionModal.saveButtonLabel": "Sauvegarder et basculer",
|
||||
"discover.esqlToDataViewTransitionModal.title": "Votre requête sera supprimée",
|
||||
"discover.esqlToDataviewTransitionModalBody": "Modifier la vue de données supprime la requête ES|QL en cours. Sauvegardez cette recherche pour ne pas perdre de travail.",
|
||||
"discover.fieldChooser.availableFieldsTooltip": "Champs disponibles pour l'affichage dans le tableau.",
|
||||
"discover.fieldChooser.discoverField.addFieldTooltip": "Ajouter le champ en tant que colonne",
|
||||
"discover.fieldChooser.discoverField.removeFieldTooltip": "Supprimer le champ du tableau",
|
||||
|
|
|
@ -2544,6 +2544,11 @@
|
|||
"discover.embeddable.search.displayName": "検索",
|
||||
"discover.errorCalloutShowErrorMessage": "詳細を表示",
|
||||
"discover.esqlMode.selectedColumnsCallout": "{esqlQueryColumnsNumber}フィールド中{selectedColumnsNumber}フィールドを表示中です。利用可能なフィールドリストからさらに追加します。",
|
||||
"discover.esqlToDataViewTransitionModal.closeButtonLabel": "保存せずに切り替え",
|
||||
"discover.esqlToDataViewTransitionModal.dismissButtonLabel": "次回以降この警告を表示しない",
|
||||
"discover.esqlToDataViewTransitionModal.saveButtonLabel": "保存して切り替え",
|
||||
"discover.esqlToDataViewTransitionModal.title": "クエリは削除されます",
|
||||
"discover.esqlToDataviewTransitionModalBody": "データビューを切り替えると、現在のES|QLクエリが削除されます。この検索を保存すると、作業内容が失われないことが保証されます。",
|
||||
"discover.fieldChooser.availableFieldsTooltip": "フィールドをテーブルに表示できます。",
|
||||
"discover.fieldChooser.discoverField.addFieldTooltip": "フィールドを列として追加",
|
||||
"discover.fieldChooser.discoverField.removeFieldTooltip": "フィールドを表から削除",
|
||||
|
|
|
@ -2546,6 +2546,11 @@
|
|||
"discover.embeddable.search.displayName": "搜索",
|
||||
"discover.errorCalloutShowErrorMessage": "查看详情",
|
||||
"discover.esqlMode.selectedColumnsCallout": "正在显示 {selectedColumnsNumber} 个字段,共 {esqlQueryColumnsNumber} 个。从可用字段列表中添加更多字段。",
|
||||
"discover.esqlToDataViewTransitionModal.closeButtonLabel": "切换而不保存",
|
||||
"discover.esqlToDataViewTransitionModal.dismissButtonLabel": "不再显示此警告",
|
||||
"discover.esqlToDataViewTransitionModal.saveButtonLabel": "保存并切换",
|
||||
"discover.esqlToDataViewTransitionModal.title": "将移除您的查询",
|
||||
"discover.esqlToDataviewTransitionModalBody": "切换数据视图会移除当前的 ES|QL 查询。保存此搜索以确保不会丢失工作。",
|
||||
"discover.fieldChooser.availableFieldsTooltip": "适用于在表中显示的字段。",
|
||||
"discover.fieldChooser.discoverField.addFieldTooltip": "将字段添加为列",
|
||||
"discover.fieldChooser.discoverField.removeFieldTooltip": "从表中移除字段",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue