Skip to content

Commit

Permalink
[Security Solution] - remove old network details flyout and panel (el…
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeOberti authored Jul 18, 2024
1 parent e96625d commit 1684d37
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 701 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,7 @@ export type ExpandedEventType =
}
| EmptyObject;

export type ExpandedNetworkType =
| {
panelView?: 'networkDetail';
params?: {
ip: string;
flowTarget: FlowTargetSourceDest;
};
}
| EmptyObject;

export type ExpandedDetailType = ExpandedEventType | ExpandedNetworkType;
export type ExpandedDetailType = ExpandedEventType;

export enum TimelineTabs {
query = 'query',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import type { FlowTargetSourceDest } from '../../search_strategy';
import type { TimelineTabs } from '../timeline';

type EmptyObject = Record<string | number, never>;
Expand All @@ -21,17 +20,7 @@ export type ExpandedEventType =
}
| EmptyObject;

export type ExpandedNetworkType =
| {
panelView?: 'networkDetail';
params?: {
ip: string;
flowTarget: FlowTargetSourceDest;
};
}
| EmptyObject;

export type ExpandedDetailType = ExpandedEventType | ExpandedNetworkType;
export type ExpandedDetailType = ExpandedEventType;

export type ExpandedDetailTimeline = {
[tab in TimelineTabs]?: ExpandedDetailType;
Expand Down
6 changes: 6 additions & 0 deletions x-pack/plugins/security_solution/public/flyout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import React, { memo } from 'react';
import { ExpandableFlyout, type ExpandableFlyoutProps } from '@kbn/expandable-flyout';
import { useEuiTheme } from '@elastic/eui';
import type { NetworkExpandableFlyoutProps } from './network_details';
import { NetworkPanel, NetworkPanelKey } from './network_details';
import {
DocumentDetailsIsolateHostPanelKey,
DocumentDetailsLeftPanelKey,
Expand Down Expand Up @@ -124,6 +126,10 @@ const expandableFlyoutDocumentsPanels: ExpandableFlyoutProps['registeredPanels']
<HostPanel {...(props as HostPanelExpandableFlyoutProps).params} isPreviewMode />
),
},
{
key: NetworkPanelKey,
component: (props) => <NetworkPanel {...(props as NetworkExpandableFlyoutProps).params} />,
},
];

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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 React, { useCallback, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { getEsQueryConfig } from '@kbn/data-plugin/common';
import { InputsModelId } from '../../../common/store/inputs/constants';
import { useInvalidFilterQuery } from '../../../common/hooks/use_invalid_filter_query';
import type { FlowTargetSourceDest } from '../../../../common/search_strategy';
import { IpOverview } from '../../../explore/network/components/details';
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
import { useGlobalTime } from '../../../common/containers/use_global_time';
import { networkToCriteria } from '../../../common/components/ml/criteria/network_to_criteria';
import { scoreIntervalToDateTime } from '../../../common/components/ml/score/score_interval_to_datetime';
import { useKibana } from '../../../common/lib/kibana';
import { convertToBuildEsQuery } from '../../../common/lib/kuery';
import { inputsSelectors } from '../../../common/store';
import { setAbsoluteRangeDatePicker } from '../../../common/store/inputs/actions';
import { useSourcererDataView } from '../../../sourcerer/containers';
import { useNetworkDetails } from '../../../explore/network/containers/details';
import { networkModel } from '../../../explore/network/store';
import { useAnomaliesTableData } from '../../../common/components/ml/anomaly/use_anomalies_table_data';
import { useInstalledSecurityJobNameById } from '../../../common/components/ml/hooks/use_installed_security_jobs';
import { EmptyPrompt } from '../../../common/components/empty_prompt';

export interface NetworkDetailsProps {
/**
* IP value
*/
ip: string;
/**
* Destination or source information
*/
flowTarget: FlowTargetSourceDest;
}

/**
* Component rendering all the network details for the expandable flyout
*/
export const NetworkDetails = ({
ip,
flowTarget,
isDraggable,
}: NetworkDetailsProps & { isDraggable?: boolean }) => {
const dispatch = useDispatch();
const { to, from, isInitializing } = useGlobalTime();
const getGlobalQuerySelector = useMemo(() => inputsSelectors.globalQuerySelector(), []);
const getGlobalFiltersQuerySelector = useMemo(
() => inputsSelectors.globalFiltersQuerySelector(),
[]
);

const query = useDeepEqualSelector(getGlobalQuerySelector);
const filters = useDeepEqualSelector(getGlobalFiltersQuerySelector);

const type = networkModel.NetworkType.details;
const narrowDateRange = useCallback(
(score, interval) => {
const fromTo = scoreIntervalToDateTime(score, interval);
dispatch(
setAbsoluteRangeDatePicker({
id: InputsModelId.global,
from: fromTo.from,
to: fromTo.to,
})
);
},
[dispatch]
);
const {
services: { uiSettings },
} = useKibana();

const { indicesExist, indexPattern, selectedPatterns } = useSourcererDataView();
const [filterQuery, kqlError] = convertToBuildEsQuery({
config: getEsQueryConfig(uiSettings),
indexPattern,
queries: [query],
filters,
});

const [loading, { id, networkDetails }] = useNetworkDetails({
skip: isInitializing || filterQuery === undefined,
filterQuery,
indexNames: selectedPatterns,
ip,
});

useInvalidFilterQuery({ id, filterQuery, kqlError, query, startDate: from, endDate: to });
const { jobNameById } = useInstalledSecurityJobNameById();
const jobIds = useMemo(() => Object.keys(jobNameById), [jobNameById]);
const [isLoadingAnomaliesData, anomaliesData] = useAnomaliesTableData({
criteriaFields: networkToCriteria(ip, flowTarget),
startDate: from,
endDate: to,
skip: isInitializing,
jobIds,
aggregationInterval: 'auto',
});

return indicesExist ? (
<IpOverview
contextID={undefined}
id={id}
ip={ip}
data={networkDetails}
anomaliesData={anomaliesData}
loading={loading}
isInDetailsSidePanel
isLoadingAnomaliesData={isLoadingAnomaliesData}
isDraggable={isDraggable}
type={type}
flowTarget={flowTarget}
startDate={from}
endDate={to}
narrowDateRange={narrowDateRange}
indexPatterns={selectedPatterns}
jobNameById={jobNameById}
/>
) : (
<EmptyPrompt />
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 type { FC } from 'react';
import React, { memo } from 'react';
import { EuiSpacer } from '@elastic/eui';
import { NetworkDetails } from './components/network_details';
import { FlyoutBody } from '../shared/components/flyout_body';
import type { FlowTargetSourceDest } from '../../../common/search_strategy';

export interface PanelContentProps {
/**
* IP value
*/
ip: string;
/**
* Destination or source information
*/
flowTarget: FlowTargetSourceDest;
}

/**
* Network details expandable flyout right section
*/
export const PanelContent: FC<PanelContentProps> = memo(({ ip, flowTarget }: PanelContentProps) => {
return (
<FlyoutBody>
<EuiSpacer size="m" />
<NetworkDetails ip={ip} flowTarget={flowTarget} />
</FlyoutBody>
);
});

PanelContent.displayName = 'PanelContent';
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* 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 type { FC } from 'react';
import React, { memo, useMemo } from 'react';
import type { EuiFlyoutHeader } from '@elastic/eui';
import { SecurityPageName } from '@kbn/deeplinks-security';
import { getNetworkDetailsUrl } from '../../common/components/link_to';
import { SecuritySolutionLinkAnchor } from '../../common/components/links';
import type { FlowTargetSourceDest } from '../../../common/search_strategy';
import { FlyoutHeader } from '../shared/components/flyout_header';
import { FlyoutTitle } from '../shared/components/flyout_title';
import { encodeIpv6 } from '../../common/lib/helpers';

export interface PanelHeaderProps extends React.ComponentProps<typeof EuiFlyoutHeader> {
/**
* IP value
*/
ip: string;
/**
* Destination or source information
*/
flowTarget: FlowTargetSourceDest;
}

/**
*
*/
export const PanelHeader: FC<PanelHeaderProps> = memo(
({ ip, flowTarget, ...flyoutHeaderProps }: PanelHeaderProps) => {
const href = useMemo(
() => getNetworkDetailsUrl(encodeURIComponent(encodeIpv6(ip)), flowTarget),
[flowTarget, ip]
);

return (
<FlyoutHeader {...flyoutHeaderProps}>
<SecuritySolutionLinkAnchor
deepLinkId={SecurityPageName.network}
path={href}
target={'_blank'}
external={false}
>
<FlyoutTitle title={ip} iconType={'globe'} isLink />
</SecuritySolutionLinkAnchor>
</FlyoutHeader>
);
}
);

PanelHeader.displayName = 'PanelHeader';
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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 React, { memo } from 'react';
import type { FlyoutPanelProps } from '@kbn/expandable-flyout';
import type { FlowTargetSourceDest } from '../../../common/search_strategy';
import { PanelHeader } from './header';
import { PanelContent } from './content';

export interface NetworkExpandableFlyoutProps extends FlyoutPanelProps {
key: 'network-details';
params: NetworkPanelProps;
}

export const NetworkPanelKey: NetworkExpandableFlyoutProps['key'] = 'network-details';

export interface NetworkPanelProps extends Record<string, unknown> {
/**
* IP value
*/
ip: string;
/**
* Destination or source information
*/
flowTarget: FlowTargetSourceDest;
}

/**
* Panel to be displayed in the network details expandable flyout right section
*/
export const NetworkPanel = memo(({ ip, flowTarget }: NetworkPanelProps) => {
return (
<>
<PanelHeader ip={ip} flowTarget={flowTarget} />
<PanelContent ip={ip} flowTarget={flowTarget} />
</>
);
});

NetworkPanel.displayName = 'NetworkPanel';
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TestProviders } from '../../../common/mock';
import { TimelineId, TimelineTabs } from '../../../../common/types/timeline';
import { timelineActions } from '../../store';
import { StatefulEventContext } from '../../../common/components/events_viewer/stateful_event_context';
import { NetworkPanelKey } from '../../../flyout/network_details';

jest.mock('react-redux', () => {
const origin = jest.requireActual('react-redux');
Expand Down Expand Up @@ -54,6 +55,13 @@ jest.mock('../../store', () => {
};
});

const mockOpenFlyout = jest.fn();
jest.mock('@kbn/expandable-flyout', () => ({
useExpandableFlyoutApi: () => ({
openFlyout: mockOpenFlyout,
}),
}));

describe('FormattedIp', () => {
const props = {
value: '192.168.1.1',
Expand Down Expand Up @@ -100,7 +108,7 @@ describe('FormattedIp', () => {
expect(timelineActions.toggleDetailPanel).not.toHaveBeenCalled();
});

test('if enableIpDetailsFlyout, should open NetworkDetailsSidePanel', () => {
test('if enableIpDetailsFlyout, should open NetworkDetails expandable flyout', () => {
const context = {
enableHostDetailsFlyout: true,
enableIpDetailsFlyout: true,
Expand All @@ -116,14 +124,14 @@ describe('FormattedIp', () => {
);

userEvent.click(screen.getByTestId('network-details'));
expect(timelineActions.toggleDetailPanel).toHaveBeenCalledWith({
id: context.timelineID,
panelView: 'networkDetail',
params: {
flowTarget: 'source',
ip: props.value,
expect(mockOpenFlyout).toHaveBeenCalledWith({
right: {
id: NetworkPanelKey,
params: {
ip: props.value,
flowTarget: 'source',
},
},
tabType: context.tabType,
});
});
});
Loading

0 comments on commit 1684d37

Please sign in to comment.