mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Security Solution] - remove old host details flyout and panel (#187831)
This commit is contained in:
parent
a400595281
commit
62144fbbe1
13 changed files with 3 additions and 803 deletions
|
@ -23,15 +23,6 @@ export type ExpandedEventType =
|
|||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedHostType =
|
||||
| {
|
||||
panelView?: 'hostDetail';
|
||||
params?: {
|
||||
hostName: string;
|
||||
};
|
||||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedNetworkType =
|
||||
| {
|
||||
panelView?: 'networkDetail';
|
||||
|
@ -42,7 +33,7 @@ export type ExpandedNetworkType =
|
|||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedDetailType = ExpandedEventType | ExpandedHostType | ExpandedNetworkType;
|
||||
export type ExpandedDetailType = ExpandedEventType | ExpandedNetworkType;
|
||||
|
||||
export enum TimelineTabs {
|
||||
query = 'query',
|
||||
|
|
|
@ -21,15 +21,6 @@ export type ExpandedEventType =
|
|||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedHostType =
|
||||
| {
|
||||
panelView?: 'hostDetail';
|
||||
params?: {
|
||||
hostName: string;
|
||||
};
|
||||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedNetworkType =
|
||||
| {
|
||||
panelView?: 'networkDetail';
|
||||
|
@ -40,7 +31,7 @@ export type ExpandedNetworkType =
|
|||
}
|
||||
| EmptyObject;
|
||||
|
||||
export type ExpandedDetailType = ExpandedEventType | ExpandedHostType | ExpandedNetworkType;
|
||||
export type ExpandedDetailType = ExpandedEventType | ExpandedNetworkType;
|
||||
|
||||
export type ExpandedDetailTimeline = {
|
||||
[tab in TimelineTabs]?: ExpandedDetailType;
|
||||
|
|
|
@ -285,355 +285,6 @@ exports[`Details Panel Component DetailsPanel:EventDetails: rendering it should
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`Details Panel Component DetailsPanel:HostDetails: rendering it should render the Host Details view in the Details Panel when the panelView is hostDetail and the hostName is set 1`] = `
|
||||
.c3 {
|
||||
color: #98a2b3;
|
||||
}
|
||||
|
||||
.c2 {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.c2 dt {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.c2 dd {
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.c2 dd > div {
|
||||
width: -webkit-fit-content;
|
||||
width: -moz-fit-content;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.c1 {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.c1 .euiButtonIcon {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 6px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.c0 {
|
||||
width: 100%;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex-grow: 1;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.c0 > * {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.c0 .inspectButtonComponent {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 250ms ease;
|
||||
transition: opacity 250ms ease;
|
||||
}
|
||||
|
||||
.c0 .inspectButtonComponent:focus-visible {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.c0:hover .inspectButtonComponent {
|
||||
pointer-events: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.c4 {
|
||||
padding: 12px;
|
||||
background: rgba(250,251,253,0.9);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.c5 {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
<div
|
||||
class="c0"
|
||||
data-test-subj="hoverVisibilityContainer"
|
||||
>
|
||||
<div
|
||||
class="euiFlexGroup c1 emotion-euiFlexGroup-l-flexStart-stretch-column"
|
||||
data-test-subj="host-overview"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<dl
|
||||
class="euiDescriptionList c2 emotion-euiDescriptionList-row-left"
|
||||
data-type="row"
|
||||
>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Host ID
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
First seen
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
aria-label="Loading"
|
||||
class="euiLoadingSpinner emotion-euiLoadingSpinner-m"
|
||||
data-test-subj="loading-spinner"
|
||||
role="progressbar"
|
||||
/>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Last seen
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
aria-label="Loading"
|
||||
class="euiLoadingSpinner emotion-euiLoadingSpinner-m"
|
||||
data-test-subj="loading-spinner"
|
||||
role="progressbar"
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<dl
|
||||
class="euiDescriptionList c2 emotion-euiDescriptionList-row-left"
|
||||
data-type="row"
|
||||
>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
IP addresses
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
MAC addresses
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Platform
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<dl
|
||||
class="euiDescriptionList c2 emotion-euiDescriptionList-row-left"
|
||||
data-type="row"
|
||||
>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Operating system
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Family
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Version
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Architecture
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-grow-1"
|
||||
>
|
||||
<dl
|
||||
class="euiDescriptionList c2 emotion-euiDescriptionList-row-left"
|
||||
data-type="row"
|
||||
>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Cloud provider
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Region
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Instance ID
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
<dt
|
||||
class="euiDescriptionList__title emotion-euiDescriptionList__title-row-normal-s"
|
||||
>
|
||||
Machine type
|
||||
</dt>
|
||||
<dd
|
||||
class="euiDescriptionList__description emotion-euiDescriptionList__description-row-normal"
|
||||
>
|
||||
<span
|
||||
class="c3"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<aside
|
||||
class="c4"
|
||||
>
|
||||
<div
|
||||
class="euiFlexGroup c5 emotion-euiFlexGroup-s-center-center-column"
|
||||
overlay="[object Object]"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem emotion-euiFlexItem-growZero"
|
||||
>
|
||||
<span
|
||||
aria-label="Loading"
|
||||
class="euiLoadingSpinner emotion-euiLoadingSpinner-xl"
|
||||
data-test-subj="loading-spinner"
|
||||
role="progressbar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Details Panel Component DetailsPanel:NetworkDetails: rendering it should render the Network Details view in the Details Panel when the panelView is networkDetail and the ip is set 1`] = `
|
||||
.c3 {
|
||||
color: #98a2b3;
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* 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 { mount } from 'enzyme';
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { mockGlobalState, TestProviders } from '../../../../common/mock';
|
||||
import { ExpandableHostDetails } from './expandable_host';
|
||||
import { mockAnomalies } from '../../../../common/components/ml/mock';
|
||||
import type { Anomalies } from '../../../../common/components/ml/types';
|
||||
import { hasMlUserPermissions } from '../../../../../common/machine_learning/has_ml_user_permissions';
|
||||
import { InputsModelId } from '../../../../common/store/inputs/constants';
|
||||
const mockDispatch = jest.fn();
|
||||
jest.mock('../../../../../common/machine_learning/has_ml_user_permissions');
|
||||
jest.mock('react-redux', () => {
|
||||
const original = jest.requireActual('react-redux');
|
||||
|
||||
return {
|
||||
...original,
|
||||
useDispatch: () => mockDispatch,
|
||||
};
|
||||
});
|
||||
jest.mock('../../../../common/components/ml/anomaly/anomaly_table_provider', () => ({
|
||||
AnomalyTableProvider: ({
|
||||
children,
|
||||
}: {
|
||||
children: (args: {
|
||||
anomaliesData: Anomalies;
|
||||
isLoadingAnomaliesData: boolean;
|
||||
jobNameById: Record<string, string | undefined>;
|
||||
}) => React.ReactNode;
|
||||
}) => children({ anomaliesData: mockAnomalies, isLoadingAnomaliesData: false, jobNameById: {} }),
|
||||
}));
|
||||
|
||||
describe('Expandable Host Component', () => {
|
||||
beforeAll(() => {
|
||||
(hasMlUserPermissions as jest.Mock).mockReturnValue(true);
|
||||
});
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
const mockProps = {
|
||||
contextID: 'text-context',
|
||||
hostName: 'testHostName',
|
||||
scopeId: 'testScopeId',
|
||||
};
|
||||
|
||||
describe('ExpandableHostDetails: rendering', () => {
|
||||
test('it should render the HostOverview of the ExpandableHostDetails', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ExpandableHostDetails {...mockProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('[data-test-subj="host-overview"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
test('it should render the HostOverview of the ExpandableHostDetails with the correct indices', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ExpandableHostDetails {...mockProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('HostOverview').prop('indexNames')).toStrictEqual(
|
||||
mockGlobalState.sourcerer.sourcererScopes.default.selectedPatterns
|
||||
);
|
||||
});
|
||||
|
||||
test('it should set date range to anomaly date range', async () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<ExpandableHostDetails {...mockProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
wrapper.find('[data-test-subj="anomaly-score-popover"]').first().simulate('click');
|
||||
await waitFor(() => {
|
||||
wrapper
|
||||
.find('button[data-test-subj="anomaly-description-narrow-range-link"]')
|
||||
.first()
|
||||
.simulate('click');
|
||||
});
|
||||
expect(mockDispatch).toHaveBeenCalledWith({
|
||||
type: 'x-pack/security_solution/local/inputs/SET_ABSOLUTE_RANGE_DATE_PICKER',
|
||||
payload: {
|
||||
id: InputsModelId.global,
|
||||
from: '2019-06-15T06:00:00.000Z',
|
||||
to: '2019-06-17T06:00:00.000Z',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* 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 } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiTitle } from '@elastic/eui';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { InputsModelId } from '../../../../common/store/inputs/constants';
|
||||
import { HostDetailsLink } from '../../../../common/components/links';
|
||||
import { useGlobalTime } from '../../../../common/containers/use_global_time';
|
||||
import { useSourcererDataView } from '../../../../sourcerer/containers';
|
||||
import { HostOverview } from '../../../../overview/components/host_overview';
|
||||
import { setAbsoluteRangeDatePicker } from '../../../../common/store/inputs/actions';
|
||||
import type { HostItem } from '../../../../../common/search_strategy';
|
||||
import { AnomalyTableProvider } from '../../../../common/components/ml/anomaly/anomaly_table_provider';
|
||||
import { hostToCriteria } from '../../../../common/components/ml/criteria/host_to_criteria';
|
||||
import { scoreIntervalToDateTime } from '../../../../common/components/ml/score/score_interval_to_datetime';
|
||||
import { useHostDetails, ID } from '../../../../explore/hosts/containers/hosts/details';
|
||||
|
||||
interface ExpandableHostProps {
|
||||
hostName: string;
|
||||
}
|
||||
|
||||
const StyledTitle = styled.h4`
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
`;
|
||||
|
||||
export const ExpandableHostDetailsTitle = ({ hostName }: ExpandableHostProps) => (
|
||||
<EuiTitle size="s">
|
||||
<StyledTitle data-test-subj="host-details-header">
|
||||
{i18n.translate('xpack.securitySolution.timeline.sidePanel.hostDetails.title', {
|
||||
defaultMessage: 'Host details',
|
||||
})}
|
||||
{`: ${hostName}`}
|
||||
</StyledTitle>
|
||||
</EuiTitle>
|
||||
);
|
||||
|
||||
export const ExpandableHostDetailsPageLink = ({ hostName }: ExpandableHostProps) => (
|
||||
<HostDetailsLink hostName={hostName} isButton>
|
||||
{i18n.translate('xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink', {
|
||||
defaultMessage: 'View details page',
|
||||
})}
|
||||
</HostDetailsLink>
|
||||
);
|
||||
|
||||
export const ExpandableHostDetails = ({
|
||||
contextID,
|
||||
scopeId,
|
||||
hostName,
|
||||
isDraggable = false,
|
||||
}: ExpandableHostProps & { contextID: string; scopeId: string; isDraggable?: boolean }) => {
|
||||
const { to, from, isInitializing } = useGlobalTime();
|
||||
/*
|
||||
Normally `selectedPatterns` from useSourcererDataView would be where we obtain the indices,
|
||||
but those indices are only loaded when viewing the pages where the sourcerer is initialized (i.e. Hosts and Overview)
|
||||
When a user goes directly to the detections page, the patterns have not been loaded yet
|
||||
as that information isn't used for the detections page. With this details component being accessible
|
||||
from the detections page, the decision was made to get all existing index names to account for this.
|
||||
Otherwise, an empty array is defaulted for the `indexNames` in the query which leads to inconsistencies in the data returned
|
||||
(i.e. extraneous endpoint data is retrieved from the backend leading to endpoint data not being returned)
|
||||
*/
|
||||
const { selectedPatterns } = useSourcererDataView();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [loading, { hostDetails: hostOverview }] = useHostDetails({
|
||||
endDate: to,
|
||||
hostName,
|
||||
indexNames: selectedPatterns,
|
||||
startDate: from,
|
||||
});
|
||||
const narrowDateRange = useCallback(
|
||||
(score, interval) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
dispatch(
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: InputsModelId.global,
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
})
|
||||
);
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
return (
|
||||
<AnomalyTableProvider
|
||||
criteriaFields={hostToCriteria(hostOverview)}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
skip={isInitializing}
|
||||
>
|
||||
{({ isLoadingAnomaliesData, anomaliesData, jobNameById }) => (
|
||||
<HostOverview
|
||||
contextID={contextID}
|
||||
scopeId={scopeId}
|
||||
id={ID}
|
||||
isInDetailsSidePanel
|
||||
data={hostOverview as HostItem}
|
||||
anomaliesData={anomaliesData}
|
||||
isDraggable={isDraggable}
|
||||
isLoadingAnomaliesData={isLoadingAnomaliesData}
|
||||
indexNames={selectedPatterns}
|
||||
loading={loading}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
narrowDateRange={narrowDateRange}
|
||||
hostName={hostName}
|
||||
jobNameById={jobNameById}
|
||||
/>
|
||||
)}
|
||||
</AnomalyTableProvider>
|
||||
);
|
||||
};
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
* 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,
|
||||
EuiFlyoutHeader,
|
||||
EuiFlyoutBody,
|
||||
EuiFlexItem,
|
||||
EuiButtonIcon,
|
||||
EuiSpacer,
|
||||
EuiHorizontalRule,
|
||||
} from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React, { useMemo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { AssetCriticalityAccordion } from '../../../../entity_analytics/components/asset_criticality/asset_criticality_selector';
|
||||
import {
|
||||
ExpandableHostDetails,
|
||||
ExpandableHostDetailsPageLink,
|
||||
ExpandableHostDetailsTitle,
|
||||
} from './expandable_host';
|
||||
|
||||
const StyledEuiFlyoutBody = styled(EuiFlyoutBody)`
|
||||
.euiFlyoutBody__overflow {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.euiFlyoutBody__overflowContent {
|
||||
flex: 1;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
margin-bottom: 64px; // account for firefox, which doesn't seem to respect the bottom padding
|
||||
padding: ${({ theme }) => `${theme.eui.euiSizeXS} ${theme.eui.euiSizeM} 0px`};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledEuiFlexGroup = styled(EuiFlexGroup)`
|
||||
flex: 1 0 auto;
|
||||
`;
|
||||
|
||||
const StyledEuiFlexButtonWrapper = styled(EuiFlexItem)`
|
||||
align-self: flex-start;
|
||||
flex: 1 0 auto;
|
||||
`;
|
||||
|
||||
const StyledPanelContent = styled.div`
|
||||
display: block;
|
||||
height: 100%;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
`;
|
||||
|
||||
interface HostDetailsProps {
|
||||
contextID: string;
|
||||
scopeId: string;
|
||||
expandedHost: { hostName: string };
|
||||
handleOnHostClosed: () => void;
|
||||
isFlyoutView?: boolean;
|
||||
isDraggable?: boolean;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react/display-name
|
||||
export const HostDetailsPanel: React.FC<HostDetailsProps> = React.memo(
|
||||
({ contextID, scopeId, expandedHost, handleOnHostClosed, isDraggable, isFlyoutView }) => {
|
||||
const { hostName } = expandedHost;
|
||||
const entity = useMemo(() => ({ name: hostName, type: 'host' as const }), [hostName]);
|
||||
if (!hostName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return isFlyoutView ? (
|
||||
<>
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<ExpandableHostDetailsTitle hostName={hostName} />
|
||||
</EuiFlyoutHeader>
|
||||
<StyledEuiFlyoutBody>
|
||||
<EuiSpacer size="m" />
|
||||
<ExpandableHostDetailsPageLink hostName={hostName} />
|
||||
<EuiHorizontalRule />
|
||||
<AssetCriticalityAccordion entity={entity} />
|
||||
<ExpandableHostDetails contextID={contextID} scopeId={scopeId} hostName={hostName} />
|
||||
</StyledEuiFlyoutBody>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<StyledEuiFlexGroup justifyContent="spaceBetween" wrap={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<ExpandableHostDetailsTitle hostName={hostName} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
iconType="cross"
|
||||
aria-label={i18n.translate(
|
||||
'xpack.securitySolution.timeline.sidePanel.hostDetails.close',
|
||||
{
|
||||
defaultMessage: 'close',
|
||||
}
|
||||
)}
|
||||
onClick={handleOnHostClosed}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</StyledEuiFlexGroup>
|
||||
<EuiSpacer size="m" />
|
||||
<StyledEuiFlexButtonWrapper grow={false}>
|
||||
<ExpandableHostDetailsPageLink hostName={hostName} />
|
||||
</StyledEuiFlexButtonWrapper>
|
||||
<EuiSpacer size="m" />
|
||||
<AssetCriticalityAccordion entity={entity} />
|
||||
<StyledPanelContent>
|
||||
<ExpandableHostDetails
|
||||
contextID={contextID}
|
||||
scopeId={scopeId}
|
||||
hostName={hostName}
|
||||
isDraggable={isDraggable}
|
||||
/>
|
||||
</StyledPanelContent>
|
||||
</>
|
||||
);
|
||||
}
|
||||
);
|
|
@ -64,15 +64,6 @@ describe('Details Panel Component', () => {
|
|||
},
|
||||
};
|
||||
|
||||
const hostExpandedDetail: ExpandedDetailTimeline = {
|
||||
[TimelineTabs.query]: {
|
||||
panelView: 'hostDetail',
|
||||
params: {
|
||||
hostName: 'woohoo!',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const networkExpandedDetail: ExpandedDetailTimeline = {
|
||||
[TimelineTabs.query]: {
|
||||
panelView: 'networkDetail',
|
||||
|
@ -289,50 +280,6 @@ describe('Details Panel Component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('DetailsPanel:HostDetails: rendering', () => {
|
||||
beforeEach(() => {
|
||||
mockUseSearchStrategy.mockReturnValue({
|
||||
loading: true,
|
||||
result: {
|
||||
hostDetails: {
|
||||
host: {},
|
||||
},
|
||||
},
|
||||
error: undefined,
|
||||
search: jest.fn(),
|
||||
refetch: jest.fn(),
|
||||
inspect: {},
|
||||
});
|
||||
const mockState = {
|
||||
...state,
|
||||
timeline: {
|
||||
...state.timeline,
|
||||
timelineById: {
|
||||
[TimelineId.test]: state.timeline.timelineById[TimelineId.test],
|
||||
[TimelineId.active]: state.timeline.timelineById[TimelineId.test],
|
||||
},
|
||||
},
|
||||
};
|
||||
mockState.timeline.timelineById[TimelineId.test].expandedDetail = hostExpandedDetail;
|
||||
mockState.timeline.timelineById[TimelineId.active].expandedDetail = hostExpandedDetail;
|
||||
store = createMockStore(mockState);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockUseSearchStrategy.mockReset();
|
||||
});
|
||||
|
||||
test('it should render the Host Details view in the Details Panel when the panelView is hostDetail and the hostName is set', () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders store={store}>
|
||||
<DetailsPanel {...mockProps} />
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
expect(wrapper.find('ExpandableHostDetails').first().render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('DetailsPanel:NetworkDetails: rendering', () => {
|
||||
beforeEach(() => {
|
||||
mockUseSearchStrategy.mockReturnValue({
|
||||
|
|
|
@ -20,7 +20,6 @@ import type { RunTimeMappings } from '../../../sourcerer/store/model';
|
|||
import { TimelineId, TimelineTabs } from '../../../../common/types/timeline';
|
||||
import { useDeepEqualSelector } from '../../../common/hooks/use_selector';
|
||||
import { EventDetailsPanel } from './event_details';
|
||||
import { HostDetailsPanel } from './host_details';
|
||||
import { NetworkDetailsPanel } from './network_details';
|
||||
|
||||
interface DetailsPanelProps {
|
||||
|
@ -125,20 +124,6 @@ export const DetailsPanel = React.memo(
|
|||
);
|
||||
}
|
||||
|
||||
if (currentTabDetail?.panelView === 'hostDetail' && currentTabDetail?.params?.hostName) {
|
||||
flyoutUniqueKey = currentTabDetail.params.hostName;
|
||||
visiblePanel = (
|
||||
<HostDetailsPanel
|
||||
contextID={contextID}
|
||||
expandedHost={currentTabDetail?.params}
|
||||
handleOnHostClosed={closePanel}
|
||||
isDraggable={isDraggable}
|
||||
isFlyoutView={isFlyoutView}
|
||||
scopeId={scopeId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (currentTabDetail?.panelView === 'networkDetail' && currentTabDetail?.params?.ip) {
|
||||
flyoutUniqueKey = currentTabDetail.params.ip;
|
||||
visiblePanel = (
|
||||
|
|
|
@ -126,11 +126,7 @@ const StatefulEventComponent: React.FC<Props> = ({
|
|||
const expandedDetail = useDeepEqualSelector(
|
||||
(state) => (getTimeline(state, timelineId) ?? timelineDefaults).expandedDetail ?? {}
|
||||
);
|
||||
const hostNameArr = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'host.name' });
|
||||
|
||||
const hostName = useMemo(() => {
|
||||
return hostNameArr && hostNameArr.length > 0 ? hostNameArr[0] : null;
|
||||
}, [hostNameArr]);
|
||||
const hostIpList = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'host.ip' });
|
||||
const sourceIpList = useGetMappedNonEcsValue({ data: event?.data, fieldName: 'source.ip' });
|
||||
const destinationIpList = useGetMappedNonEcsValue({
|
||||
|
@ -151,8 +147,6 @@ const StatefulEventComponent: React.FC<Props> = ({
|
|||
const isDetailPanelExpanded: boolean =
|
||||
(activeExpandedDetail?.panelView === 'eventDetail' &&
|
||||
activeExpandedDetail?.params?.eventId === eventId) ||
|
||||
(activeExpandedDetail?.panelView === 'hostDetail' &&
|
||||
activeExpandedDetail?.params?.hostName === hostName) ||
|
||||
(activeExpandedDetail?.panelView === 'networkDetail' &&
|
||||
activeExpandedDetail?.params?.ip &&
|
||||
hostIPAddresses?.has(activeExpandedDetail?.params?.ip)) ||
|
||||
|
|
|
@ -872,12 +872,7 @@ describe('SiemLocalStorage', () => {
|
|||
],
|
||||
dataViewId: null,
|
||||
deletedEventIds: [],
|
||||
expandedDetail: {
|
||||
query: {
|
||||
params: { hostName: 'Host-riizqhdnoy' },
|
||||
panelView: 'hostDetail',
|
||||
},
|
||||
},
|
||||
expandedDetail: {},
|
||||
filters: [],
|
||||
indexNames: [],
|
||||
isSelectAllChecked: false,
|
||||
|
|
|
@ -37905,9 +37905,6 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "Rechercher des événements",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "Rechercher",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "Les événements des fournisseurs de données ci-dessus sont combinés avec les résultats de ce KQL",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.close": "fermer",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "Afficher la page de détails",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.title": "Détails de l'hôte",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "Score maximal d'anomalie par tâche",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.close": "fermer",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "Afficher la page de détails",
|
||||
|
|
|
@ -37775,9 +37775,6 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "イベントを検索",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "検索",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "上のデータプロバイダーからのイベントは、この KQL からの結果と組み合わされます。",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.close": "閉じる",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "詳細ページを表示",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.title": "ホストの詳細",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "ジョブ別の最高異常スコア",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.close": "閉じる",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "詳細ページを表示",
|
||||
|
|
|
@ -37944,9 +37944,6 @@
|
|||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlPlaceholder": "搜索事件",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlSelectedText": "搜索",
|
||||
"xpack.securitySolution.timeline.searchOrFilter.searchKqlTooltip": "来自上述数据提供程序的事件与此 KQL 的结果进行组合",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.close": "关闭",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.hostDetailsPageLink": "查看详情页面",
|
||||
"xpack.securitySolution.timeline.sidePanel.hostDetails.title": "主机详情",
|
||||
"xpack.securitySolution.timeline.sidePanel.maxAnomalyScoreByJobTitle": "最大异常分数(按作业)",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.close": "关闭",
|
||||
"xpack.securitySolution.timeline.sidePanel.networkDetails.networkDetailsPageLink": "查看详情页面",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue