[SIEM] Refactor hosts routing (#47459)
This commit is contained in:
parent
49804a2645
commit
d01099778b
|
@ -1,15 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`body render snapshot 1`] = `
|
||||
<Component>
|
||||
<Connect(HostDetailsBodyComponent)
|
||||
detailName="host-1"
|
||||
from={0}
|
||||
isInitializing={false}
|
||||
setQuery={[Function]}
|
||||
to={0}
|
||||
>
|
||||
<Component />
|
||||
</Connect(HostDetailsBodyComponent)>
|
||||
</Component>
|
||||
`;
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { shallow, mount } from 'enzyme';
|
||||
import toJson from 'enzyme-to-json';
|
||||
import React from 'react';
|
||||
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||
|
||||
import { mockIndexPattern } from '../../../mock/index_pattern';
|
||||
import { TestProviders } from '../../../mock/test_providers';
|
||||
import { mockUiSettings } from '../../../mock/ui_settings';
|
||||
import { CommonChildren } from '../navigation/types';
|
||||
import { HostDetailsBody } from './body';
|
||||
import { useKibanaCore } from '../../../lib/compose/kibana_core';
|
||||
|
||||
const mockUseKibanaCore = useKibanaCore as jest.Mock;
|
||||
jest.mock('../../../lib/compose/kibana_core');
|
||||
mockUseKibanaCore.mockImplementation(() => ({
|
||||
uiSettings: mockUiSettings,
|
||||
}));
|
||||
|
||||
jest.mock('../../../containers/source', () => ({
|
||||
indicesExistOrDataTemporarilyUnavailable: () => true,
|
||||
WithSource: ({
|
||||
children,
|
||||
}: {
|
||||
children: (args: {
|
||||
indicesExist: boolean;
|
||||
indexPattern: StaticIndexPattern;
|
||||
}) => React.ReactNode;
|
||||
}) => children({ indicesExist: true, indexPattern: mockIndexPattern }),
|
||||
}));
|
||||
|
||||
describe('body', () => {
|
||||
test('render snapshot', () => {
|
||||
const child: CommonChildren = () => <span>{'I am a child'}</span>;
|
||||
const wrapper = shallow(
|
||||
<TestProviders>
|
||||
<HostDetailsBody
|
||||
children={child}
|
||||
from={0}
|
||||
isInitializing={false}
|
||||
detailName={'host-1'}
|
||||
setQuery={() => {}}
|
||||
to={0}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
expect(toJson(wrapper)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('it should pass expected object properties to children', () => {
|
||||
const child = jest.fn();
|
||||
mount(
|
||||
<TestProviders>
|
||||
<HostDetailsBody
|
||||
children={child}
|
||||
from={0}
|
||||
isInitializing={false}
|
||||
detailName={'host-1'}
|
||||
setQuery={() => {}}
|
||||
to={0}
|
||||
/>
|
||||
</TestProviders>
|
||||
);
|
||||
// match against everything but the functions to ensure they are there as expected
|
||||
expect(child.mock.calls[0][0]).toMatchObject({
|
||||
endDate: 0,
|
||||
filterQuery:
|
||||
'{"bool":{"must":[],"filter":[{"match_all":{}},{"match_phrase":{"host.name":{"query":"host-1"}}}],"should":[],"must_not":[]}}',
|
||||
skip: false,
|
||||
startDate: 0,
|
||||
type: 'details',
|
||||
indexPattern: {
|
||||
fields: [
|
||||
{ name: '@timestamp', searchable: true, type: 'date', aggregatable: true },
|
||||
{ name: '@version', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.ephemeral_id', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.hostname', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.id', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test1', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test2', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test3', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test4', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test5', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test6', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test7', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test8', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'host.name', searchable: true, type: 'string', aggregatable: true },
|
||||
],
|
||||
title: 'filebeat-*,auditbeat-*,packetbeat-*',
|
||||
},
|
||||
hostName: 'host-1',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,106 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { getEsQueryConfig } from '@kbn/es-query';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../../containers/source';
|
||||
import { setAbsoluteRangeDatePicker as dispatchAbsoluteRangeDatePicker } from '../../../store/inputs/actions';
|
||||
import { scoreIntervalToDateTime } from '../../../components/ml/score/score_interval_to_datetime';
|
||||
import { Anomaly } from '../../../components/ml/types';
|
||||
import { convertToBuildEsQuery } from '../../../lib/keury';
|
||||
import { useKibanaCore } from '../../../lib/compose/kibana_core';
|
||||
|
||||
import { HostDetailsBodyComponentProps } from './types';
|
||||
import { type, makeMapStateToProps } from './utils';
|
||||
|
||||
const HostDetailsBodyComponent = React.memo<HostDetailsBodyComponentProps>(
|
||||
({
|
||||
children,
|
||||
deleteQuery,
|
||||
detailName,
|
||||
filters,
|
||||
from,
|
||||
isInitializing,
|
||||
query,
|
||||
setAbsoluteRangeDatePicker,
|
||||
setQuery,
|
||||
to,
|
||||
}) => {
|
||||
const core = useKibanaCore();
|
||||
return (
|
||||
<WithSource sourceId="default">
|
||||
{({ indicesExist, indexPattern }) => {
|
||||
const filterQuery = convertToBuildEsQuery({
|
||||
config: getEsQueryConfig(core.uiSettings),
|
||||
indexPattern,
|
||||
queries: [query],
|
||||
filters: [
|
||||
{
|
||||
meta: {
|
||||
alias: null,
|
||||
negate: false,
|
||||
disabled: false,
|
||||
type: 'phrase',
|
||||
key: 'host.name',
|
||||
value: detailName,
|
||||
params: {
|
||||
query: detailName,
|
||||
},
|
||||
},
|
||||
query: {
|
||||
match: {
|
||||
'host.name': {
|
||||
query: detailName,
|
||||
type: 'phrase',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
...filters,
|
||||
],
|
||||
});
|
||||
return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
|
||||
<>
|
||||
{children({
|
||||
deleteQuery,
|
||||
endDate: to,
|
||||
filterQuery,
|
||||
skip: isInitializing,
|
||||
setQuery,
|
||||
startDate: from,
|
||||
type,
|
||||
indexPattern,
|
||||
hostName: detailName,
|
||||
narrowDateRange: (score: Anomaly, interval: string) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
},
|
||||
updateDateRange: (min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
},
|
||||
})}
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
</WithSource>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HostDetailsBodyComponent.displayName = 'HostDetailsBodyComponent';
|
||||
|
||||
export const HostDetailsBody = connect(
|
||||
makeMapStateToProps,
|
||||
{
|
||||
setAbsoluteRangeDatePicker: dispatchAbsoluteRangeDatePicker,
|
||||
}
|
||||
)(HostDetailsBodyComponent);
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { mount } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { mockIndexPattern } from '../../../mock/index_pattern';
|
||||
import { TestProviders } from '../../../mock/test_providers';
|
||||
import { mockUiSettings } from '../../../mock/ui_settings';
|
||||
import { HostDetailsTabs } from './details_tabs';
|
||||
import { SetAbsoluteRangeDatePicker } from './types';
|
||||
import { hostDetailsPagePath } from '../types';
|
||||
import { type } from './utils';
|
||||
import { useKibanaCore } from '../../../lib/compose/kibana_core';
|
||||
|
||||
jest.mock('../../../lib/settings/use_kibana_ui_setting');
|
||||
|
||||
const mockUseKibanaCore = useKibanaCore as jest.Mock;
|
||||
jest.mock('../../../lib/compose/kibana_core');
|
||||
mockUseKibanaCore.mockImplementation(() => ({
|
||||
uiSettings: mockUiSettings,
|
||||
}));
|
||||
|
||||
jest.mock('../../../containers/source', () => ({
|
||||
indicesExistOrDataTemporarilyUnavailable: () => true,
|
||||
WithSource: ({
|
||||
children,
|
||||
}: {
|
||||
children: (args: {
|
||||
indicesExist: boolean;
|
||||
indexPattern: StaticIndexPattern;
|
||||
}) => React.ReactNode;
|
||||
}) => children({ indicesExist: true, indexPattern: mockIndexPattern }),
|
||||
}));
|
||||
|
||||
// Test will fail because we will to need to mock some core services to make the test work
|
||||
// For now let's forget about SiemSearchBar
|
||||
jest.mock('../../../components/search_bar', () => ({
|
||||
SiemSearchBar: () => null,
|
||||
}));
|
||||
|
||||
describe('body', () => {
|
||||
const scenariosMap = {
|
||||
authentications: 'AuthenticationsQueryTabBody',
|
||||
allHosts: 'HostsQueryTabBody',
|
||||
uncommonProcesses: 'UncommonProcessQueryTabBody',
|
||||
anomalies: 'AnomaliesQueryTabBody',
|
||||
events: 'EventsQueryTabBody',
|
||||
};
|
||||
|
||||
Object.entries(scenariosMap).forEach(([path, componentName]) =>
|
||||
test(`it should pass expected object properties to ${componentName}`, () => {
|
||||
const wrapper = mount(
|
||||
<TestProviders>
|
||||
<MemoryRouter initialEntries={[`/hosts/host-1/${path}`]}>
|
||||
<HostDetailsTabs
|
||||
from={0}
|
||||
isInitializing={false}
|
||||
detailName={'host-1'}
|
||||
setQuery={() => {}}
|
||||
to={0}
|
||||
setAbsoluteRangeDatePicker={(jest.fn() as unknown) as SetAbsoluteRangeDatePicker}
|
||||
hostDetailsPagePath={hostDetailsPagePath}
|
||||
indexPattern={mockIndexPattern}
|
||||
type={type}
|
||||
filterQuery='{"bool":{"must":[],"filter":[{"match_all":{}},{"match_phrase":{"host.name":{"query":"host-1"}}}],"should":[],"must_not":[]}}'
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</TestProviders>
|
||||
);
|
||||
|
||||
// match against everything but the functions to ensure they are there as expected
|
||||
expect(wrapper.find(componentName).props()).toMatchObject({
|
||||
endDate: 0,
|
||||
filterQuery:
|
||||
'{"bool":{"must":[],"filter":[{"match_all":{}},{"match_phrase":{"host.name":{"query":"host-1"}}}],"should":[],"must_not":[]}}',
|
||||
skip: false,
|
||||
startDate: 0,
|
||||
type: 'details',
|
||||
indexPattern: {
|
||||
fields: [
|
||||
{ name: '@timestamp', searchable: true, type: 'date', aggregatable: true },
|
||||
{ name: '@version', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.ephemeral_id', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.hostname', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.id', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test1', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test2', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test3', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test4', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test5', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test6', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test7', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'agent.test8', searchable: true, type: 'string', aggregatable: true },
|
||||
{ name: 'host.name', searchable: true, type: 'string', aggregatable: true },
|
||||
],
|
||||
title: 'filebeat-*,auditbeat-*,packetbeat-*',
|
||||
},
|
||||
hostName: 'host-1',
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { scoreIntervalToDateTime } from '../../../components/ml/score/score_interval_to_datetime';
|
||||
import { Anomaly } from '../../../components/ml/types';
|
||||
import { HostsTableType } from '../../../store/hosts/model';
|
||||
|
||||
import { HostDetailsTabsProps } from './types';
|
||||
import { type } from './utils';
|
||||
|
||||
import {
|
||||
HostsQueryTabBody,
|
||||
AuthenticationsQueryTabBody,
|
||||
UncommonProcessQueryTabBody,
|
||||
AnomaliesQueryTabBody,
|
||||
EventsQueryTabBody,
|
||||
} from '../navigation';
|
||||
|
||||
const HostDetailsTabs = React.memo<HostDetailsTabsProps>(
|
||||
({
|
||||
deleteQuery,
|
||||
filterQuery,
|
||||
from,
|
||||
isInitializing,
|
||||
detailName,
|
||||
setAbsoluteRangeDatePicker,
|
||||
setQuery,
|
||||
to,
|
||||
indexPattern,
|
||||
hostDetailsPagePath,
|
||||
}) => {
|
||||
const narrowDateRange = useCallback(
|
||||
(score: Anomaly, interval: string) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
},
|
||||
[setAbsoluteRangeDatePicker, scoreIntervalToDateTime]
|
||||
);
|
||||
|
||||
const updateDateRange = useCallback(
|
||||
(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
},
|
||||
[setAbsoluteRangeDatePicker, scoreIntervalToDateTime]
|
||||
);
|
||||
|
||||
const tabProps = {
|
||||
deleteQuery,
|
||||
endDate: to,
|
||||
filterQuery,
|
||||
skip: isInitializing,
|
||||
setQuery,
|
||||
startDate: from,
|
||||
type,
|
||||
indexPattern,
|
||||
hostName: detailName,
|
||||
narrowDateRange,
|
||||
updateDateRange,
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.authentications})`}
|
||||
render={() => <AuthenticationsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.hosts})`}
|
||||
render={() => <HostsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}
|
||||
render={() => <UncommonProcessQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.anomalies})`}
|
||||
render={() => <AnomaliesQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostDetailsPagePath}/:tabName(${HostsTableType.events})`}
|
||||
render={() => <EventsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HostDetailsTabs.displayName = 'HostDetailsTabs';
|
||||
|
||||
export { HostDetailsTabs };
|
|
@ -11,6 +11,8 @@ import { compose } from 'redux';
|
|||
import { connect } from 'react-redux';
|
||||
import { StickyContainer } from 'react-sticky';
|
||||
|
||||
import { inputsSelectors, State } from '../../../store';
|
||||
|
||||
import { FiltersGlobal } from '../../../components/filters_global';
|
||||
import { HeaderPage } from '../../../components/header_page';
|
||||
import { KpiHostDetailsQuery } from '../../../containers/kpi_host_details';
|
||||
|
@ -32,22 +34,19 @@ import { LastEventIndexKey } from '../../../graphql/types';
|
|||
import { convertToBuildEsQuery } from '../../../lib/keury';
|
||||
import { setAbsoluteRangeDatePicker as dispatchAbsoluteRangeDatePicker } from '../../../store/inputs/actions';
|
||||
import { SpyRoute } from '../../../utils/route/spy_routes';
|
||||
|
||||
import { HostsQueryProps } from '../hosts';
|
||||
import { HostsEmptyPage } from '../hosts_empty_page';
|
||||
|
||||
export { HostDetailsBody } from './body';
|
||||
import { navTabsHostDetails } from './nav_tabs';
|
||||
import { HostDetailsComponentProps } from './types';
|
||||
import { makeMapStateToProps } from './utils';
|
||||
import { useKibanaCore } from '../../../lib/compose/kibana_core';
|
||||
|
||||
import { HostsEmptyPage } from '../hosts_empty_page';
|
||||
import { navTabsHostDetails } from './nav_tabs';
|
||||
import { HostDetailsComponentProps, HostDetailsProps } from './types';
|
||||
import { HostDetailsTabs } from './details_tabs';
|
||||
import { type } from './utils';
|
||||
|
||||
const HostOverviewManage = manageQuery(HostOverview);
|
||||
const KpiHostDetailsManage = manageQuery(KpiHostsComponent);
|
||||
|
||||
const HostDetailsComponent = React.memo<HostDetailsComponentProps>(
|
||||
({
|
||||
detailName,
|
||||
filters,
|
||||
from,
|
||||
isInitializing,
|
||||
|
@ -56,6 +55,9 @@ const HostDetailsComponent = React.memo<HostDetailsComponentProps>(
|
|||
setHostDetailsTablesActivePageToZero,
|
||||
setQuery,
|
||||
to,
|
||||
detailName,
|
||||
deleteQuery,
|
||||
hostDetailsPagePath,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
setHostDetailsTablesActivePageToZero(null);
|
||||
|
@ -96,94 +98,111 @@ const HostDetailsComponent = React.memo<HostDetailsComponentProps>(
|
|||
],
|
||||
});
|
||||
return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
|
||||
<StickyContainer>
|
||||
<FiltersGlobal>
|
||||
<SiemSearchBar indexPattern={indexPattern} id="global" />
|
||||
</FiltersGlobal>
|
||||
<>
|
||||
<StickyContainer>
|
||||
<FiltersGlobal>
|
||||
<SiemSearchBar indexPattern={indexPattern} id="global" />
|
||||
</FiltersGlobal>
|
||||
|
||||
<HeaderPage
|
||||
subtitle={
|
||||
<LastEventTime indexKey={LastEventIndexKey.hostDetails} hostName={detailName} />
|
||||
}
|
||||
title={detailName}
|
||||
/>
|
||||
<HostOverviewByNameQuery
|
||||
sourceId="default"
|
||||
hostName={detailName}
|
||||
skip={isInitializing}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
>
|
||||
{({ hostOverview, loading, id, inspect, refetch }) => (
|
||||
<AnomalyTableProvider
|
||||
criteriaFields={hostToCriteria(hostOverview)}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
skip={isInitializing}
|
||||
>
|
||||
{({ isLoadingAnomaliesData, anomaliesData }) => (
|
||||
<HostOverviewManage
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
data={hostOverview}
|
||||
anomaliesData={anomaliesData}
|
||||
isLoadingAnomaliesData={isLoadingAnomaliesData}
|
||||
loading={loading}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
narrowDateRange={(score, interval) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AnomalyTableProvider>
|
||||
)}
|
||||
</HostOverviewByNameQuery>
|
||||
<HeaderPage
|
||||
subtitle={
|
||||
<LastEventTime
|
||||
indexKey={LastEventIndexKey.hostDetails}
|
||||
hostName={detailName}
|
||||
/>
|
||||
}
|
||||
title={detailName}
|
||||
/>
|
||||
<HostOverviewByNameQuery
|
||||
sourceId="default"
|
||||
hostName={detailName}
|
||||
skip={isInitializing}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
>
|
||||
{({ hostOverview, loading, id, inspect, refetch }) => (
|
||||
<AnomalyTableProvider
|
||||
criteriaFields={hostToCriteria(hostOverview)}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
skip={isInitializing}
|
||||
>
|
||||
{({ isLoadingAnomaliesData, anomaliesData }) => (
|
||||
<HostOverviewManage
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
data={hostOverview}
|
||||
anomaliesData={anomaliesData}
|
||||
isLoadingAnomaliesData={isLoadingAnomaliesData}
|
||||
loading={loading}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
narrowDateRange={(score, interval) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AnomalyTableProvider>
|
||||
)}
|
||||
</HostOverviewByNameQuery>
|
||||
|
||||
<EuiHorizontalRule />
|
||||
<EuiHorizontalRule />
|
||||
|
||||
<KpiHostDetailsQuery
|
||||
sourceId="default"
|
||||
<KpiHostDetailsQuery
|
||||
sourceId="default"
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
>
|
||||
{({ kpiHostDetails, id, inspect, loading, refetch }) => (
|
||||
<KpiHostDetailsManage
|
||||
data={kpiHostDetails}
|
||||
from={from}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
to={to}
|
||||
narrowDateRange={(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</KpiHostDetailsQuery>
|
||||
|
||||
<SiemNavigation
|
||||
navTabs={navTabsHostDetails(detailName, hasMlUserPermissions(capabilities))}
|
||||
display="default"
|
||||
showBorder={true}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</StickyContainer>
|
||||
<HostDetailsTabs
|
||||
isInitializing={isInitializing}
|
||||
deleteQuery={deleteQuery}
|
||||
to={to}
|
||||
from={from}
|
||||
detailName={detailName}
|
||||
type={type}
|
||||
setQuery={setQuery}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
startDate={from}
|
||||
endDate={to}
|
||||
>
|
||||
{({ kpiHostDetails, id, inspect, loading, refetch }) => (
|
||||
<KpiHostDetailsManage
|
||||
data={kpiHostDetails}
|
||||
from={from}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
to={to}
|
||||
narrowDateRange={(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</KpiHostDetailsQuery>
|
||||
|
||||
<SiemNavigation
|
||||
navTabs={navTabsHostDetails(detailName, hasMlUserPermissions(capabilities))}
|
||||
display="default"
|
||||
showBorder={true}
|
||||
hostDetailsPagePath={hostDetailsPagePath}
|
||||
indexPattern={indexPattern}
|
||||
setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</StickyContainer>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<HeaderPage title={detailName} />
|
||||
|
||||
<HostsEmptyPage />
|
||||
</>
|
||||
);
|
||||
|
@ -197,7 +216,16 @@ const HostDetailsComponent = React.memo<HostDetailsComponentProps>(
|
|||
|
||||
HostDetailsComponent.displayName = 'HostDetailsComponent';
|
||||
|
||||
export const HostDetails = compose<React.ComponentClass<HostsQueryProps & { detailName: string }>>(
|
||||
export const makeMapStateToProps = () => {
|
||||
const getGlobalQuerySelector = inputsSelectors.globalQuerySelector();
|
||||
const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector();
|
||||
return (state: State) => ({
|
||||
query: getGlobalQuerySelector(state),
|
||||
filters: getGlobalFiltersQuerySelector(state),
|
||||
});
|
||||
};
|
||||
|
||||
export const HostDetails = compose<React.ComponentClass<HostDetailsProps>>(
|
||||
connect(
|
||||
makeMapStateToProps,
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
import { Query } from 'src/plugins/data/common';
|
||||
|
@ -11,13 +12,10 @@ import { Query } from 'src/plugins/data/common';
|
|||
import { InputsModelId } from '../../../store/inputs/constants';
|
||||
import { HostComponentProps } from '../../../components/link_to/redirect_to_hosts';
|
||||
import { HostsTableType } from '../../../store/hosts/model';
|
||||
import { HostsQueryProps } from '../hosts';
|
||||
import { HostsQueryProps } from '../types';
|
||||
import { NavTab } from '../../../components/navigation/types';
|
||||
import {
|
||||
AnomaliesChildren,
|
||||
CommonChildren,
|
||||
KeyHostsNavTabWithoutMlPermission,
|
||||
} from '../navigation/types';
|
||||
import { KeyHostsNavTabWithoutMlPermission } from '../navigation/types';
|
||||
import { hostsModel } from '../../../store';
|
||||
|
||||
interface HostDetailsComponentReduxProps {
|
||||
query: Query;
|
||||
|
@ -31,14 +29,16 @@ interface HostBodyComponentDispatchProps {
|
|||
to: number;
|
||||
}>;
|
||||
detailName: string;
|
||||
hostDetailsPagePath: string;
|
||||
}
|
||||
|
||||
interface HostDetailsComponentDispatchProps extends HostBodyComponentDispatchProps {
|
||||
setHostDetailsTablesActivePageToZero: ActionCreator<null>;
|
||||
}
|
||||
|
||||
export interface HostDetailsBodyProps extends HostsQueryProps {
|
||||
children: CommonChildren | AnomaliesChildren;
|
||||
export interface HostDetailsProps extends HostsQueryProps {
|
||||
detailName: string;
|
||||
hostDetailsPagePath: string;
|
||||
}
|
||||
|
||||
export type HostDetailsComponentProps = HostDetailsComponentReduxProps &
|
||||
|
@ -46,10 +46,6 @@ export type HostDetailsComponentProps = HostDetailsComponentReduxProps &
|
|||
HostComponentProps &
|
||||
HostsQueryProps;
|
||||
|
||||
export type HostDetailsBodyComponentProps = HostDetailsComponentReduxProps &
|
||||
HostBodyComponentDispatchProps &
|
||||
HostDetailsBodyProps;
|
||||
|
||||
type KeyHostDetailsNavTabWithoutMlPermission = HostsTableType.authentications &
|
||||
HostsTableType.uncommonProcesses &
|
||||
HostsTableType.events;
|
||||
|
@ -62,3 +58,16 @@ type KeyHostDetailsNavTab =
|
|||
| KeyHostDetailsNavTabWithMlPermission;
|
||||
|
||||
export type HostDetailsNavTab = Record<KeyHostDetailsNavTab, NavTab>;
|
||||
|
||||
export type HostDetailsTabsProps = HostBodyComponentDispatchProps &
|
||||
HostsQueryProps & {
|
||||
indexPattern: StaticIndexPattern;
|
||||
type: hostsModel.HostsType;
|
||||
filterQuery: string;
|
||||
};
|
||||
|
||||
export type SetAbsoluteRangeDatePicker = ActionCreator<{
|
||||
id: InputsModelId;
|
||||
from: number;
|
||||
to: number;
|
||||
}>;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { Breadcrumb } from 'ui/chrome';
|
||||
|
||||
import { hostsModel, inputsSelectors, State } from '../../../store';
|
||||
import { hostsModel } from '../../../store';
|
||||
import { HostsTableType } from '../../../store/hosts/model';
|
||||
import { getHostsUrl, getHostDetailsUrl } from '../../../components/link_to/redirect_to_hosts';
|
||||
|
||||
|
@ -15,15 +15,6 @@ import { RouteSpyState } from '../../../utils/route/types';
|
|||
|
||||
export const type = hostsModel.HostsType.details;
|
||||
|
||||
export const makeMapStateToProps = () => {
|
||||
const getGlobalQuerySelector = inputsSelectors.globalQuerySelector();
|
||||
const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector();
|
||||
return (state: State) => ({
|
||||
query: getGlobalQuerySelector(state),
|
||||
filters: getGlobalFiltersQuerySelector(state),
|
||||
});
|
||||
};
|
||||
|
||||
const TabNameMappedToI18nKey = {
|
||||
[HostsTableType.hosts]: i18n.NAVIGATION_ALL_HOSTS_TITLE,
|
||||
[HostsTableType.authentications]: i18n.NAVIGATION_AUTHENTICATIONS_TITLE,
|
||||
|
|
|
@ -19,7 +19,8 @@ import { wait } from '../../lib/helpers';
|
|||
import { TestProviders } from '../../mock';
|
||||
import { mockUiSettings } from '../../mock/ui_settings';
|
||||
import { InputsModelId } from '../../store/inputs/constants';
|
||||
import { Hosts, HostsComponentProps } from './hosts';
|
||||
import { HostsComponentProps } from './types';
|
||||
import { Hosts } from './hosts';
|
||||
import { useKibanaCore } from '../../lib/compose/kibana_core';
|
||||
|
||||
jest.mock('../../lib/settings/use_kibana_ui_setting');
|
||||
|
@ -97,6 +98,7 @@ describe('Hosts - rendering', () => {
|
|||
}>,
|
||||
query: { query: '', language: 'kuery' },
|
||||
filters: [],
|
||||
hostsPagePath: '',
|
||||
};
|
||||
|
||||
beforeAll(() => {
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
*/
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { Filter, getEsQueryConfig } from '@kbn/es-query';
|
||||
import { getEsQueryConfig } from '@kbn/es-query';
|
||||
import * as React from 'react';
|
||||
import { compose } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { StickyContainer } from 'react-sticky';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
import { Query } from 'src/plugins/data/common';
|
||||
|
||||
import { FiltersGlobal } from '../../components/filters_global';
|
||||
import { GlobalTimeArgs } from '../../containers/global_time';
|
||||
|
@ -27,41 +25,34 @@ import { SiemSearchBar } from '../../components/search_bar';
|
|||
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
|
||||
import { LastEventIndexKey } from '../../graphql/types';
|
||||
import { convertToBuildEsQuery } from '../../lib/keury';
|
||||
import { inputsSelectors, State } from '../../store';
|
||||
import { inputsSelectors, State, hostsModel } from '../../store';
|
||||
import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../store/inputs/actions';
|
||||
import { InputsModelId } from '../../store/inputs/constants';
|
||||
import { SpyRoute } from '../../utils/route/spy_routes';
|
||||
import { useKibanaCore } from '../../lib/compose/kibana_core';
|
||||
|
||||
import { HostsEmptyPage } from './hosts_empty_page';
|
||||
import { navTabsHosts } from './nav_tabs';
|
||||
import * as i18n from './translations';
|
||||
import { useKibanaCore } from '../../lib/compose/kibana_core';
|
||||
import { HostsComponentProps, HostsComponentReduxProps } from './types';
|
||||
import { HostsTabs } from './hosts_tabs';
|
||||
|
||||
const KpiHostsComponentManage = manageQuery(KpiHostsComponent);
|
||||
|
||||
interface HostsComponentReduxProps {
|
||||
query: Query;
|
||||
filters: Filter[];
|
||||
}
|
||||
|
||||
interface HostsComponentDispatchProps {
|
||||
setAbsoluteRangeDatePicker: ActionCreator<{
|
||||
id: InputsModelId;
|
||||
from: number;
|
||||
to: number;
|
||||
}>;
|
||||
}
|
||||
|
||||
export type HostsQueryProps = GlobalTimeArgs;
|
||||
|
||||
export type HostsComponentProps = HostsComponentReduxProps &
|
||||
HostsComponentDispatchProps &
|
||||
HostsQueryProps;
|
||||
|
||||
const HostsComponent = React.memo<HostsComponentProps>(
|
||||
({ isInitializing, filters, from, query, setAbsoluteRangeDatePicker, setQuery, to }) => {
|
||||
({
|
||||
deleteQuery,
|
||||
isInitializing,
|
||||
filters,
|
||||
from,
|
||||
query,
|
||||
setAbsoluteRangeDatePicker,
|
||||
setQuery,
|
||||
to,
|
||||
hostsPagePath,
|
||||
}) => {
|
||||
const capabilities = React.useContext(MlCapabilitiesContext);
|
||||
const core = useKibanaCore();
|
||||
|
||||
return (
|
||||
<>
|
||||
<WithSource sourceId="default">
|
||||
|
@ -73,48 +64,62 @@ const HostsComponent = React.memo<HostsComponentProps>(
|
|||
filters,
|
||||
});
|
||||
return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
|
||||
<StickyContainer>
|
||||
<FiltersGlobal>
|
||||
<SiemSearchBar indexPattern={indexPattern} id="global" />
|
||||
</FiltersGlobal>
|
||||
<>
|
||||
<StickyContainer>
|
||||
<FiltersGlobal>
|
||||
<SiemSearchBar indexPattern={indexPattern} id="global" />
|
||||
</FiltersGlobal>
|
||||
|
||||
<HeaderPage
|
||||
subtitle={<LastEventTime indexKey={LastEventIndexKey.hosts} />}
|
||||
title={i18n.PAGE_TITLE}
|
||||
/>
|
||||
<>
|
||||
<KpiHostsQuery
|
||||
endDate={to}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
sourceId="default"
|
||||
startDate={from}
|
||||
>
|
||||
{({ kpiHosts, loading, id, inspect, refetch }) => (
|
||||
<KpiHostsComponentManage
|
||||
data={kpiHosts}
|
||||
from={from}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
to={to}
|
||||
narrowDateRange={(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</KpiHostsQuery>
|
||||
<EuiSpacer />
|
||||
<SiemNavigation
|
||||
navTabs={navTabsHosts(hasMlUserPermissions(capabilities))}
|
||||
display="default"
|
||||
showBorder={true}
|
||||
<HeaderPage
|
||||
subtitle={<LastEventTime indexKey={LastEventIndexKey.hosts} />}
|
||||
title={i18n.PAGE_TITLE}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</>
|
||||
</StickyContainer>
|
||||
<>
|
||||
<KpiHostsQuery
|
||||
endDate={to}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
sourceId="default"
|
||||
startDate={from}
|
||||
>
|
||||
{({ kpiHosts, loading, id, inspect, refetch }) => (
|
||||
<KpiHostsComponentManage
|
||||
data={kpiHosts}
|
||||
from={from}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
to={to}
|
||||
narrowDateRange={(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</KpiHostsQuery>
|
||||
<EuiSpacer />
|
||||
<SiemNavigation
|
||||
navTabs={navTabsHosts(hasMlUserPermissions(capabilities))}
|
||||
display="default"
|
||||
showBorder={true}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
</>
|
||||
</StickyContainer>
|
||||
<HostsTabs
|
||||
deleteQuery={deleteQuery}
|
||||
to={to}
|
||||
filterQuery={filterQuery}
|
||||
isInitializing={isInitializing}
|
||||
setQuery={setQuery}
|
||||
from={from}
|
||||
type={hostsModel.HostsType.page}
|
||||
indexPattern={indexPattern}
|
||||
setAbsoluteRangeDatePicker={setAbsoluteRangeDatePicker}
|
||||
hostsPagePath={hostsPagePath}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<HeaderPage title={i18n.PAGE_TITLE} />
|
||||
|
@ -142,8 +147,12 @@ const makeMapStateToProps = () => {
|
|||
return mapStateToProps;
|
||||
};
|
||||
|
||||
interface HostsProps extends GlobalTimeArgs {
|
||||
hostsPagePath: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const Hosts = compose<React.ComponentClass<GlobalTimeArgs>>(
|
||||
export const Hosts = compose<React.ComponentClass<HostsProps>>(
|
||||
connect(
|
||||
makeMapStateToProps,
|
||||
{
|
||||
|
|
|
@ -1,96 +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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { getEsQueryConfig } from '@kbn/es-query';
|
||||
import React, { memo } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { scoreIntervalToDateTime } from '../../components/ml/score/score_interval_to_datetime';
|
||||
import { Anomaly } from '../../components/ml/types';
|
||||
import { indicesExistOrDataTemporarilyUnavailable, WithSource } from '../../containers/source';
|
||||
import { convertToBuildEsQuery } from '../../lib/keury';
|
||||
import { useKibanaCore } from '../../lib/compose/kibana_core';
|
||||
import { hostsModel, inputsSelectors, State } from '../../store';
|
||||
import { setAbsoluteRangeDatePicker as dispatchSetAbsoluteRangeDatePicker } from '../../store/inputs/actions';
|
||||
|
||||
import { HostsComponentProps } from './hosts';
|
||||
import { CommonChildren, AnomaliesChildren } from './navigation/types';
|
||||
|
||||
interface HostsBodyComponentProps extends HostsComponentProps {
|
||||
children: CommonChildren | AnomaliesChildren;
|
||||
}
|
||||
|
||||
const HostsBodyComponent = memo<HostsBodyComponentProps>(
|
||||
({
|
||||
children,
|
||||
deleteQuery,
|
||||
filters,
|
||||
from,
|
||||
isInitializing,
|
||||
query,
|
||||
setAbsoluteRangeDatePicker,
|
||||
setQuery,
|
||||
to,
|
||||
}) => {
|
||||
const core = useKibanaCore();
|
||||
return (
|
||||
<WithSource sourceId="default">
|
||||
{({ indicesExist, indexPattern }) => {
|
||||
const filterQuery = convertToBuildEsQuery({
|
||||
config: getEsQueryConfig(core.uiSettings),
|
||||
indexPattern,
|
||||
queries: [query],
|
||||
filters,
|
||||
});
|
||||
return indicesExistOrDataTemporarilyUnavailable(indicesExist) ? (
|
||||
<>
|
||||
{children({
|
||||
deleteQuery,
|
||||
endDate: to,
|
||||
filterQuery,
|
||||
skip: isInitializing,
|
||||
setQuery,
|
||||
startDate: from,
|
||||
type: hostsModel.HostsType.page,
|
||||
indexPattern,
|
||||
narrowDateRange: (score: Anomaly, interval: string) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
},
|
||||
updateDateRange: (min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
},
|
||||
})}
|
||||
</>
|
||||
) : null;
|
||||
}}
|
||||
</WithSource>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HostsBodyComponent.displayName = 'HostsBodyComponent';
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const getGlobalQuerySelector = inputsSelectors.globalQuerySelector();
|
||||
const getGlobalFiltersQuerySelector = inputsSelectors.globalFiltersQuerySelector();
|
||||
const mapStateToProps = (state: State) => ({
|
||||
query: getGlobalQuerySelector(state),
|
||||
filters: getGlobalFiltersQuerySelector(state),
|
||||
});
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
export const HostsBody = connect(
|
||||
makeMapStateToProps,
|
||||
{
|
||||
setAbsoluteRangeDatePicker: dispatchSetAbsoluteRangeDatePicker,
|
||||
}
|
||||
)(HostsBodyComponent);
|
87
x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx
Normal file
87
x-pack/legacy/plugins/siem/public/pages/hosts/hosts_tabs.tsx
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { HostsTabsProps } from './types';
|
||||
import { scoreIntervalToDateTime } from '../../components/ml/score/score_interval_to_datetime';
|
||||
import { Anomaly } from '../../components/ml/types';
|
||||
import { HostsTableType } from '../../store/hosts/model';
|
||||
|
||||
import {
|
||||
HostsQueryTabBody,
|
||||
AuthenticationsQueryTabBody,
|
||||
UncommonProcessQueryTabBody,
|
||||
AnomaliesQueryTabBody,
|
||||
EventsQueryTabBody,
|
||||
} from './navigation';
|
||||
|
||||
const HostsTabs = memo<HostsTabsProps>(
|
||||
({
|
||||
deleteQuery,
|
||||
filterQuery,
|
||||
setAbsoluteRangeDatePicker,
|
||||
to,
|
||||
from,
|
||||
setQuery,
|
||||
isInitializing,
|
||||
type,
|
||||
indexPattern,
|
||||
hostsPagePath,
|
||||
}) => {
|
||||
const tabProps = {
|
||||
deleteQuery,
|
||||
endDate: to,
|
||||
filterQuery,
|
||||
skip: isInitializing,
|
||||
setQuery,
|
||||
startDate: from,
|
||||
type,
|
||||
indexPattern,
|
||||
narrowDateRange: (score: Anomaly, interval: string) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
from: fromTo.from,
|
||||
to: fromTo.to,
|
||||
});
|
||||
},
|
||||
updateDateRange: (min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.hosts})`}
|
||||
render={() => <HostsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.authentications})`}
|
||||
render={() => <AuthenticationsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}
|
||||
render={() => <UncommonProcessQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.anomalies})`}
|
||||
render={() => <AnomaliesQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.events})`}
|
||||
render={() => <EventsQueryTabBody {...tabProps} />}
|
||||
/>
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
HostsTabs.displayName = 'HostsTabs';
|
||||
|
||||
export { HostsTabs };
|
|
@ -7,21 +7,13 @@
|
|||
import React from 'react';
|
||||
import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { HostDetailsBody, HostDetails } from './details';
|
||||
import {
|
||||
HostsQueryTabBody,
|
||||
AuthenticationsQueryTabBody,
|
||||
UncommonProcessQueryTabBody,
|
||||
AnomaliesQueryTabBody,
|
||||
EventsQueryTabBody,
|
||||
} from './navigation';
|
||||
import { HostsBody } from './hosts_body';
|
||||
import { HostDetails } from './details';
|
||||
import { HostsTableType } from '../../store/hosts/model';
|
||||
|
||||
import { GlobalTime } from '../../containers/global_time';
|
||||
import { SiemPageName } from '../home/types';
|
||||
import { Hosts } from './hosts';
|
||||
|
||||
const hostsPagePath = `/:pageName(${SiemPageName.hosts})`;
|
||||
import { hostsPagePath, hostDetailsPagePath } from './types';
|
||||
|
||||
const getHostsTabPath = (pagePath: string) =>
|
||||
`${pagePath}/:tabName(` +
|
||||
|
@ -32,7 +24,7 @@ const getHostsTabPath = (pagePath: string) =>
|
|||
`${HostsTableType.events})`;
|
||||
|
||||
const getHostDetailsTabPath = (pagePath: string) =>
|
||||
`${pagePath}/:detailName/:tabName(` +
|
||||
`${hostDetailsPagePath}/:tabName(` +
|
||||
`${HostsTableType.authentications}|` +
|
||||
`${HostsTableType.uncommonProcesses}|` +
|
||||
`${HostsTableType.anomalies}|` +
|
||||
|
@ -47,188 +39,35 @@ export const HostsContainer = React.memo<Props>(({ url }) => (
|
|||
<Route
|
||||
strict
|
||||
exact
|
||||
path={hostsPagePath}
|
||||
path={getHostsTabPath(hostsPagePath)}
|
||||
render={() => (
|
||||
<Route
|
||||
path={hostsPagePath}
|
||||
render={() => (
|
||||
<>
|
||||
<Hosts from={from} to={to} setQuery={setQuery} isInitializing={isInitializing} />
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={HostsQueryTabBody}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Hosts
|
||||
hostsPagePath={hostsPagePath}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
deleteQuery={deleteQuery}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
strict
|
||||
exact
|
||||
path={getHostsTabPath(hostsPagePath)}
|
||||
render={() => (
|
||||
<>
|
||||
<Hosts from={from} to={to} setQuery={setQuery} isInitializing={isInitializing} />
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.hosts})`}
|
||||
render={() => (
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={HostsQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.authentications})`}
|
||||
render={() => (
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={AuthenticationsQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.uncommonProcesses})`}
|
||||
render={() => (
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={UncommonProcessQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.anomalies})`}
|
||||
render={() => (
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={AnomaliesQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:tabName(${HostsTableType.events})`}
|
||||
render={() => (
|
||||
<HostsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={EventsQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
strict
|
||||
exact
|
||||
path={getHostDetailsTabPath(hostsPagePath)}
|
||||
render={props => (
|
||||
<>
|
||||
<HostDetails
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
detailName={props.match.params.detailName}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:detailName/:tabName(${HostsTableType.hosts})`}
|
||||
render={() => (
|
||||
<HostDetailsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
children={HostsQueryTabBody}
|
||||
detailName={props.match.params.detailName}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:detailName/:tabName(${HostsTableType.authentications})`}
|
||||
render={() => (
|
||||
<HostDetailsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
detailName={props.match.params.detailName}
|
||||
children={AuthenticationsQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:detailName/:tabName(${HostsTableType.uncommonProcesses})`}
|
||||
render={() => (
|
||||
<HostDetailsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
detailName={props.match.params.detailName}
|
||||
children={UncommonProcessQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:detailName/:tabName(${HostsTableType.anomalies})`}
|
||||
render={() => (
|
||||
<HostDetailsBody
|
||||
deleteQuery={deleteQuery}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
detailName={props.match.params.detailName}
|
||||
children={AnomaliesQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${hostsPagePath}/:detailName/:tabName(${HostsTableType.events})`}
|
||||
render={() => (
|
||||
<HostDetailsBody
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
detailName={props.match.params.detailName}
|
||||
children={EventsQueryTabBody}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
<HostDetails
|
||||
hostDetailsPagePath={hostDetailsPagePath}
|
||||
detailName={props.match.params.detailName}
|
||||
from={from}
|
||||
to={to}
|
||||
setQuery={setQuery}
|
||||
isInitializing={isInitializing}
|
||||
deleteQuery={deleteQuery}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={`${url}/:detailName`}
|
||||
path={hostDetailsPagePath}
|
||||
render={({
|
||||
match: {
|
||||
params: { detailName },
|
||||
|
@ -237,12 +76,9 @@ export const HostsContainer = React.memo<Props>(({ url }) => (
|
|||
}) => <Redirect to={`${url}/${detailName}/${HostsTableType.authentications}${search}`} />}
|
||||
/>
|
||||
<Route
|
||||
path={`/${SiemPageName.hosts}/`}
|
||||
path={`${hostsPagePath}/`}
|
||||
render={({ location: { search = '' } }) => (
|
||||
<Redirect
|
||||
from={`/${SiemPageName.hosts}/"`}
|
||||
to={`/${SiemPageName.hosts}/${HostsTableType.hosts}${search}`}
|
||||
/>
|
||||
<Redirect to={`/${SiemPageName.hosts}/${HostsTableType.hosts}${search}`} />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
|
|
45
x-pack/legacy/plugins/siem/public/pages/hosts/types.ts
Normal file
45
x-pack/legacy/plugins/siem/public/pages/hosts/types.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { StaticIndexPattern } from 'ui/index_patterns';
|
||||
import { ActionCreator } from 'typescript-fsa';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { Query } from 'src/plugins/data/common';
|
||||
|
||||
import { SiemPageName } from '../home/types';
|
||||
import { hostsModel } from '../../store';
|
||||
import { InputsModelId } from '../../store/inputs/constants';
|
||||
import { GlobalTimeArgs } from '../../containers/global_time';
|
||||
|
||||
export const hostsPagePath = `/:pageName(${SiemPageName.hosts})`;
|
||||
export const hostDetailsPagePath = `${hostsPagePath}/:detailName`;
|
||||
|
||||
export interface HostsComponentReduxProps {
|
||||
query: Query;
|
||||
filters: Filter[];
|
||||
}
|
||||
|
||||
export interface HostsComponentDispatchProps {
|
||||
setAbsoluteRangeDatePicker: ActionCreator<{
|
||||
id: InputsModelId;
|
||||
from: number;
|
||||
to: number;
|
||||
}>;
|
||||
hostsPagePath: string;
|
||||
}
|
||||
|
||||
export type HostsTabsProps = HostsComponentDispatchProps &
|
||||
HostsQueryProps & {
|
||||
filterQuery: string;
|
||||
type: hostsModel.HostsType;
|
||||
indexPattern: StaticIndexPattern;
|
||||
};
|
||||
|
||||
export type HostsQueryProps = GlobalTimeArgs;
|
||||
|
||||
export type HostsComponentProps = HostsComponentReduxProps &
|
||||
HostsComponentDispatchProps &
|
||||
HostsQueryProps;
|
Loading…
Reference in a new issue