mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* add histogram * fix types error * rename matrix histogram component * clean up * add dns histogram container * wrap passed in function with useCallback * isolate utils functions * extract types * disable chart legend for dns histogram * add dns bytes in
This commit is contained in:
parent
3c1695a200
commit
bb79547905
21 changed files with 564 additions and 155 deletions
|
@ -7,7 +7,7 @@
|
|||
import { shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import { MatrixOverTimeHistogram } from '.';
|
||||
import { MatrixHistogram } from '.';
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
return {
|
||||
|
@ -53,7 +53,7 @@ describe('Load More Events Table Component', () => {
|
|||
};
|
||||
describe('rendering', () => {
|
||||
test('it renders EuiLoadingContent on initialLoad', () => {
|
||||
const wrapper = shallow(<MatrixOverTimeHistogram {...mockMatrixOverTimeHistogramProps} />);
|
||||
const wrapper = shallow(<MatrixHistogram {...mockMatrixOverTimeHistogramProps} />);
|
||||
|
||||
expect(wrapper.find(`[data-test-subj="initialLoadingPanelMatrixOverTime"]`)).toBeTruthy();
|
||||
});
|
||||
|
@ -65,7 +65,7 @@ describe('Load More Events Table Component', () => {
|
|||
totalCount: 10,
|
||||
loading: true,
|
||||
};
|
||||
const wrapper = shallow(<MatrixOverTimeHistogram {...mockProps} />);
|
||||
const wrapper = shallow(<MatrixHistogram {...mockProps} />);
|
||||
expect(wrapper.find('.loader')).toBeTruthy();
|
||||
});
|
||||
|
||||
|
@ -76,7 +76,7 @@ describe('Load More Events Table Component', () => {
|
|||
totalCount: 10,
|
||||
loading: false,
|
||||
};
|
||||
const wrapper = shallow(<MatrixOverTimeHistogram {...mockProps} />);
|
||||
const wrapper = shallow(<MatrixHistogram {...mockProps} />);
|
||||
|
||||
expect(wrapper.find(`.barchart`)).toBeTruthy();
|
||||
});
|
|
@ -5,100 +5,50 @@
|
|||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { ScaleType, niceTimeFormatter, Position } from '@elastic/charts';
|
||||
import { ScaleType } from '@elastic/charts';
|
||||
|
||||
import { getOr, head, last } from 'lodash/fp';
|
||||
import darkTheme from '@elastic/eui/dist/eui_theme_dark.json';
|
||||
import lightTheme from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { EuiLoadingContent } from '@elastic/eui';
|
||||
import { BarChart } from '../charts/barchart';
|
||||
import { HeaderSection } from '../header_section';
|
||||
import { ChartSeriesData, UpdateDateRange } from '../charts/common';
|
||||
import { MatrixOverTimeHistogramData } from '../../graphql/types';
|
||||
import { ChartSeriesData } from '../charts/common';
|
||||
import { DEFAULT_DARK_MODE } from '../../../common/constants';
|
||||
import { useKibanaUiSetting } from '../../lib/settings/use_kibana_ui_setting';
|
||||
import { Loader } from '../loader';
|
||||
import { Panel } from '../panel';
|
||||
import { getBarchartConfigs, getCustomChartData } from './utils';
|
||||
import { MatrixHistogramProps, MatrixHistogramDataTypes } from './types';
|
||||
|
||||
export interface MatrixOverTimeBasicProps {
|
||||
id: string;
|
||||
data: MatrixOverTimeHistogramData[];
|
||||
loading: boolean;
|
||||
startDate: number;
|
||||
endDate: number;
|
||||
updateDateRange: UpdateDateRange;
|
||||
totalCount: number;
|
||||
}
|
||||
|
||||
export interface MatrixOverTimeProps extends MatrixOverTimeBasicProps {
|
||||
customChartData?: ChartSeriesData[];
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
dataKey: string;
|
||||
}
|
||||
|
||||
const getBarchartConfigs = (from: number, to: number, onBrushEnd: UpdateDateRange) => ({
|
||||
series: {
|
||||
xScaleType: ScaleType.Time,
|
||||
yScaleType: ScaleType.Linear,
|
||||
stackAccessors: ['g'],
|
||||
},
|
||||
axis: {
|
||||
xTickFormatter: niceTimeFormatter([from, to]),
|
||||
yTickFormatter: (value: string | number): string => value.toLocaleString(),
|
||||
tickSize: 8,
|
||||
},
|
||||
settings: {
|
||||
legendPosition: Position.Bottom,
|
||||
onBrushEnd,
|
||||
showLegend: true,
|
||||
theme: {
|
||||
scales: {
|
||||
barsPadding: 0.08,
|
||||
},
|
||||
chartMargins: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
chartPaddings: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
customHeight: 324,
|
||||
});
|
||||
|
||||
export const MatrixOverTimeHistogram = ({
|
||||
customChartData,
|
||||
id,
|
||||
loading,
|
||||
export const MatrixHistogram = ({
|
||||
data,
|
||||
dataKey,
|
||||
endDate,
|
||||
updateDateRange,
|
||||
id,
|
||||
loading,
|
||||
mapping,
|
||||
scaleType = ScaleType.Time,
|
||||
startDate,
|
||||
title,
|
||||
subtitle,
|
||||
title,
|
||||
totalCount,
|
||||
}: MatrixOverTimeProps) => {
|
||||
const bucketStartDate = getOr(startDate, 'x', head(data));
|
||||
const bucketEndDate = getOr(endDate, 'x', last(data));
|
||||
const barchartConfigs = getBarchartConfigs(bucketStartDate!, bucketEndDate!, updateDateRange);
|
||||
updateDateRange,
|
||||
yTickFormatter,
|
||||
showLegend,
|
||||
}: MatrixHistogramProps<MatrixHistogramDataTypes>) => {
|
||||
const barchartConfigs = getBarchartConfigs({
|
||||
from: startDate,
|
||||
to: endDate,
|
||||
onBrushEnd: updateDateRange,
|
||||
scaleType,
|
||||
yTickFormatter,
|
||||
showLegend,
|
||||
});
|
||||
const [showInspect, setShowInspect] = useState(false);
|
||||
const [darkMode] = useKibanaUiSetting(DEFAULT_DARK_MODE);
|
||||
const [loadingInitial, setLoadingInitial] = useState(false);
|
||||
|
||||
const barChartData: ChartSeriesData[] = customChartData || [
|
||||
{
|
||||
key: dataKey,
|
||||
value: data,
|
||||
},
|
||||
];
|
||||
const barChartData: ChartSeriesData[] = getCustomChartData(data, mapping);
|
||||
|
||||
useEffect(() => {
|
||||
if (totalCount >= 0 && loadingInitial) {
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { ScaleType } from '@elastic/charts';
|
||||
import { MatrixOverTimeHistogramData, MatrixOverOrdinalHistogramData } from '../../graphql/types';
|
||||
import { AuthMatrixDataFields } from '../page/hosts/authentications_over_time/utils';
|
||||
import { UpdateDateRange } from '../charts/common';
|
||||
|
||||
export type MatrixHistogramDataTypes = MatrixOverTimeHistogramData | MatrixOverOrdinalHistogramData;
|
||||
export type MatrixHistogramMappingTypes = AuthMatrixDataFields;
|
||||
export interface MatrixHistogramBasicProps<T> {
|
||||
data: T[];
|
||||
endDate: number;
|
||||
id: string;
|
||||
loading: boolean;
|
||||
mapping?: MatrixHistogramMappingTypes;
|
||||
startDate: number;
|
||||
totalCount: number;
|
||||
updateDateRange: UpdateDateRange;
|
||||
}
|
||||
|
||||
export interface MatrixHistogramProps<T> extends MatrixHistogramBasicProps<T> {
|
||||
dataKey?: string;
|
||||
scaleType?: ScaleType;
|
||||
subtitle?: string;
|
||||
title?: string;
|
||||
yTickFormatter?: (value: number) => string;
|
||||
showLegend?: boolean;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 { ScaleType, niceTimeFormatter, Position } from '@elastic/charts';
|
||||
import { get, groupBy, map, toPairs } from 'lodash/fp';
|
||||
import numeral from '@elastic/numeral';
|
||||
import { UpdateDateRange, ChartSeriesData } from '../charts/common';
|
||||
import { MatrixHistogramDataTypes, MatrixHistogramMappingTypes } from './types';
|
||||
|
||||
export const getBarchartConfigs = ({
|
||||
from,
|
||||
to,
|
||||
scaleType,
|
||||
onBrushEnd,
|
||||
yTickFormatter,
|
||||
showLegend,
|
||||
}: {
|
||||
from: number;
|
||||
to: number;
|
||||
scaleType: ScaleType;
|
||||
onBrushEnd: UpdateDateRange;
|
||||
yTickFormatter?: (value: number) => string;
|
||||
showLegend?: boolean;
|
||||
}) => ({
|
||||
series: {
|
||||
xScaleType: scaleType || ScaleType.Time,
|
||||
yScaleType: ScaleType.Linear,
|
||||
stackAccessors: ['g'],
|
||||
},
|
||||
axis: {
|
||||
xTickFormatter: scaleType === ScaleType.Time ? niceTimeFormatter([from, to]) : undefined,
|
||||
yTickFormatter:
|
||||
yTickFormatter != null
|
||||
? yTickFormatter
|
||||
: (value: string | number): string => value.toLocaleString(),
|
||||
tickSize: 8,
|
||||
},
|
||||
settings: {
|
||||
legendPosition: Position.Bottom,
|
||||
onBrushEnd,
|
||||
showLegend: showLegend || true,
|
||||
theme: {
|
||||
scales: {
|
||||
barsPadding: 0.08,
|
||||
},
|
||||
chartMargins: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
chartPaddings: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
customHeight: 324,
|
||||
});
|
||||
|
||||
export const formatToChartDataItem = ([key, value]: [
|
||||
string,
|
||||
MatrixHistogramDataTypes[]
|
||||
]): ChartSeriesData => ({
|
||||
key,
|
||||
value,
|
||||
});
|
||||
|
||||
export const getCustomChartData = (
|
||||
data: MatrixHistogramDataTypes[],
|
||||
mapping?: MatrixHistogramMappingTypes
|
||||
): ChartSeriesData[] => {
|
||||
const dataGroupedByEvent = groupBy('g', data);
|
||||
const dataGroupedEntries = toPairs(dataGroupedByEvent);
|
||||
const formattedChartData = map(formatToChartDataItem, dataGroupedEntries);
|
||||
|
||||
if (mapping)
|
||||
return map((item: ChartSeriesData) => {
|
||||
const customColor = get(`${item.key}.color`, mapping);
|
||||
item.color = customColor;
|
||||
return item;
|
||||
}, formattedChartData);
|
||||
else return formattedChartData;
|
||||
};
|
||||
|
||||
export const bytesFormatter = (value: number) => {
|
||||
return numeral(value).format('0,0.[0]b');
|
||||
};
|
|
@ -7,21 +7,23 @@
|
|||
import React from 'react';
|
||||
|
||||
import * as i18n from './translation';
|
||||
import { getCustomChartData } from './utils';
|
||||
import { MatrixOverTimeHistogram, MatrixOverTimeBasicProps } from '../../../matrix_over_time';
|
||||
import { MatrixHistogram } from '../../../matrix_histogram';
|
||||
import { MatrixHistogramBasicProps } from '../../../matrix_histogram/types';
|
||||
import { MatrixOverTimeHistogramData } from '../../../../graphql/types';
|
||||
import { authMatrixDataMappingFields } from './utils';
|
||||
|
||||
export const AuthenticationsOverTimeHistogram = (props: MatrixOverTimeBasicProps) => {
|
||||
export const AuthenticationsOverTimeHistogram = (
|
||||
props: MatrixHistogramBasicProps<MatrixOverTimeHistogramData>
|
||||
) => {
|
||||
const dataKey = 'authenticationsOverTime';
|
||||
const { data, ...matrixOverTimeProps } = props;
|
||||
|
||||
const customChartData = getCustomChartData(data);
|
||||
|
||||
return (
|
||||
<MatrixOverTimeHistogram
|
||||
title={i18n.AUTHENTICATIONS_COUNT}
|
||||
<MatrixHistogram
|
||||
mapping={authMatrixDataMappingFields}
|
||||
dataKey={dataKey}
|
||||
data={data}
|
||||
customChartData={customChartData}
|
||||
title={i18n.AUTHENTICATIONS_COUNT}
|
||||
{...matrixOverTimeProps}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -4,36 +4,28 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { groupBy, map, toPairs } from 'lodash/fp';
|
||||
|
||||
import { ChartSeriesData } from '../../../charts/common';
|
||||
import { MatrixOverTimeHistogramData } from '../../../../graphql/types';
|
||||
import { KpiHostsChartColors } from '../kpi_hosts/types';
|
||||
|
||||
const formatToChartDataItem = ([key, value]: [
|
||||
string,
|
||||
MatrixOverTimeHistogramData[]
|
||||
]): ChartSeriesData => ({
|
||||
key,
|
||||
value,
|
||||
});
|
||||
enum AuthMatrixDataGroup {
|
||||
authSuccess = 'authentication_success',
|
||||
authFailure = 'authentication_failure',
|
||||
}
|
||||
|
||||
const addCustomColors = (item: ChartSeriesData) => {
|
||||
if (item.key === 'authentication_success') {
|
||||
item.color = KpiHostsChartColors.authSuccess;
|
||||
}
|
||||
export interface AuthMatrixDataFields {
|
||||
[AuthMatrixDataGroup.authSuccess]: ChartSeriesData;
|
||||
[AuthMatrixDataGroup.authFailure]: ChartSeriesData;
|
||||
}
|
||||
|
||||
if (item.key === 'authentication_failure') {
|
||||
item.color = KpiHostsChartColors.authFailure;
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
export const getCustomChartData = (data: MatrixOverTimeHistogramData[]): ChartSeriesData[] => {
|
||||
const dataGroupedByEvent = groupBy('g', data);
|
||||
const dataGroupedEntries = toPairs(dataGroupedByEvent);
|
||||
const formattedChartData = map(formatToChartDataItem, dataGroupedEntries);
|
||||
|
||||
return map(addCustomColors, formattedChartData);
|
||||
export const authMatrixDataMappingFields: AuthMatrixDataFields = {
|
||||
[AuthMatrixDataGroup.authSuccess]: {
|
||||
key: AuthMatrixDataGroup.authSuccess,
|
||||
value: null,
|
||||
color: KpiHostsChartColors.authSuccess,
|
||||
},
|
||||
[AuthMatrixDataGroup.authFailure]: {
|
||||
key: AuthMatrixDataGroup.authFailure,
|
||||
value: null,
|
||||
color: KpiHostsChartColors.authFailure,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,16 +7,20 @@
|
|||
import React from 'react';
|
||||
|
||||
import * as i18n from './translation';
|
||||
import { MatrixOverTimeHistogram, MatrixOverTimeBasicProps } from '../../../matrix_over_time';
|
||||
import { MatrixHistogram } from '../../../matrix_histogram';
|
||||
import { MatrixHistogramBasicProps } from '../../../matrix_histogram/types';
|
||||
import { MatrixOverTimeHistogramData } from '../../../../graphql/types';
|
||||
|
||||
export const EventsOverTimeHistogram = (props: MatrixOverTimeBasicProps) => {
|
||||
export const EventsOverTimeHistogram = (
|
||||
props: MatrixHistogramBasicProps<MatrixOverTimeHistogramData>
|
||||
) => {
|
||||
const dataKey = 'eventsOverTime';
|
||||
const { totalCount } = props;
|
||||
const subtitle = `${i18n.SHOWING}: ${totalCount.toLocaleString()} ${i18n.UNIT(totalCount)}`;
|
||||
const { ...matrixOverTimeProps } = props;
|
||||
|
||||
return (
|
||||
<MatrixOverTimeHistogram
|
||||
<MatrixHistogram
|
||||
title={i18n.EVENT_COUNT_FREQUENCY_BY_ACTION}
|
||||
subtitle={subtitle}
|
||||
dataKey={dataKey}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import { ScaleType } from '@elastic/charts';
|
||||
import * as i18n from './translation';
|
||||
import { MatrixHistogram } from '../../../matrix_histogram';
|
||||
import { bytesFormatter } from '../../../matrix_histogram/utils';
|
||||
import { MatrixOverOrdinalHistogramData } from '../../../../graphql/types';
|
||||
import { MatrixHistogramBasicProps } from '../../../matrix_histogram/types';
|
||||
|
||||
export const NetworkDnsHistogram = (
|
||||
props: MatrixHistogramBasicProps<MatrixOverOrdinalHistogramData>
|
||||
) => {
|
||||
const dataKey = 'histogram';
|
||||
const { ...matrixOverTimeProps } = props;
|
||||
|
||||
return (
|
||||
<MatrixHistogram
|
||||
title={i18n.NETWORK_DNS_HISTOGRAM}
|
||||
dataKey={dataKey}
|
||||
scaleType={ScaleType.Ordinal}
|
||||
yTickFormatter={bytesFormatter}
|
||||
showLegend={false}
|
||||
{...matrixOverTimeProps}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export const NETWORK_DNS_HISTOGRAM = i18n.translate('xpack.siem.DNS.histogramTitle', {
|
||||
defaultMessage: 'Top DNS domains bytes count',
|
||||
});
|
|
@ -126,5 +126,57 @@ export const mockData: { NetworkDns: NetworkDnsData } = {
|
|||
fakeTotalCount: 50,
|
||||
showMorePagesIndicator: true,
|
||||
},
|
||||
histogram: [
|
||||
{
|
||||
x: 'nflxvideo.net',
|
||||
g: 'nflxvideo.net',
|
||||
y: 12546,
|
||||
},
|
||||
{
|
||||
x: 'apple.com',
|
||||
g: 'apple.com',
|
||||
y: 31687,
|
||||
},
|
||||
{
|
||||
x: 'googlevideo.com',
|
||||
g: 'googlevideo.com',
|
||||
y: 16292,
|
||||
},
|
||||
{
|
||||
x: 'netflix.com',
|
||||
g: 'netflix.com',
|
||||
y: 218193,
|
||||
},
|
||||
{
|
||||
x: 'samsungcloudsolution.com',
|
||||
g: 'samsungcloudsolution.com',
|
||||
y: 11702,
|
||||
},
|
||||
{
|
||||
x: 'doubleclick.net',
|
||||
g: 'doubleclick.net',
|
||||
y: 14372,
|
||||
},
|
||||
{
|
||||
x: 'digitalocean.com',
|
||||
g: 'digitalocean.com',
|
||||
y: 4111,
|
||||
},
|
||||
{
|
||||
x: 'samsungelectronics.com',
|
||||
g: 'samsungelectronics.com',
|
||||
y: 36592,
|
||||
},
|
||||
{
|
||||
x: 'google.com',
|
||||
g: 'google.com',
|
||||
y: 8072,
|
||||
},
|
||||
{
|
||||
x: 'samsungcloudsolution.net',
|
||||
g: 'samsungcloudsolution.net',
|
||||
y: 11518,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
@ -50,6 +50,11 @@ export const networkDnsQuery = gql`
|
|||
dsl
|
||||
response
|
||||
}
|
||||
histogram {
|
||||
x
|
||||
y
|
||||
g
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,15 +16,17 @@ import {
|
|||
NetworkDnsEdges,
|
||||
NetworkDnsSortField,
|
||||
PageInfoPaginated,
|
||||
MatrixOverOrdinalHistogramData,
|
||||
} from '../../graphql/types';
|
||||
import { inputsModel, networkModel, networkSelectors, State, inputsSelectors } from '../../store';
|
||||
import { generateTablePaginationOptions } from '../../components/paginated_table/helpers';
|
||||
import { createFilter, getDefaultFetchPolicy } from '../helpers';
|
||||
import { QueryTemplatePaginated, QueryTemplatePaginatedProps } from '../query_template_paginated';
|
||||
import { networkDnsQuery } from './index.gql_query';
|
||||
import { DEFAULT_TABLE_ACTIVE_PAGE, DEFAULT_TABLE_LIMIT } from '../../store/constants';
|
||||
|
||||
const ID = 'networkDnsQuery';
|
||||
|
||||
const HISTOGRAM_ID = 'networkDnsHistogramQuery';
|
||||
export interface NetworkDnsArgs {
|
||||
id: string;
|
||||
inspect: inputsModel.InspectQuery;
|
||||
|
@ -35,6 +37,7 @@ export interface NetworkDnsArgs {
|
|||
pageInfo: PageInfoPaginated;
|
||||
refetch: inputsModel.Refetch;
|
||||
totalCount: number;
|
||||
histogram: MatrixOverOrdinalHistogramData[];
|
||||
}
|
||||
|
||||
export interface OwnProps extends QueryTemplatePaginatedProps {
|
||||
|
@ -52,7 +55,7 @@ export interface NetworkDnsComponentReduxProps {
|
|||
|
||||
type NetworkDnsProps = OwnProps & NetworkDnsComponentReduxProps;
|
||||
|
||||
class NetworkDnsComponentQuery extends QueryTemplatePaginated<
|
||||
export class NetworkDnsComponentQuery extends QueryTemplatePaginated<
|
||||
NetworkDnsProps,
|
||||
GetNetworkDnsQuery.Query,
|
||||
GetNetworkDnsQuery.Variables
|
||||
|
@ -129,6 +132,7 @@ class NetworkDnsComponentQuery extends QueryTemplatePaginated<
|
|||
pageInfo: getOr({}, 'source.NetworkDns.pageInfo', data),
|
||||
refetch: this.memoizedRefetchQuery(variables, limit, refetch),
|
||||
totalCount: getOr(-1, 'source.NetworkDns.totalCount', data),
|
||||
histogram: getOr(null, 'source.NetworkDns.histogram', data),
|
||||
});
|
||||
}}
|
||||
</Query>
|
||||
|
@ -144,6 +148,24 @@ const makeMapStateToProps = () => {
|
|||
return {
|
||||
...getNetworkDnsSelector(state),
|
||||
isInspected,
|
||||
id,
|
||||
};
|
||||
};
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const makeMapHistogramStateToProps = () => {
|
||||
const getNetworkDnsSelector = networkSelectors.dnsSelector();
|
||||
const getQuery = inputsSelectors.globalQueryByIdSelector();
|
||||
const mapStateToProps = (state: State, { id = HISTOGRAM_ID }: OwnProps) => {
|
||||
const { isInspected } = getQuery(state, id);
|
||||
return {
|
||||
...getNetworkDnsSelector(state),
|
||||
activePage: DEFAULT_TABLE_ACTIVE_PAGE,
|
||||
limit: DEFAULT_TABLE_LIMIT,
|
||||
isInspected,
|
||||
id,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -151,3 +173,6 @@ const makeMapStateToProps = () => {
|
|||
};
|
||||
|
||||
export const NetworkDnsQuery = connect(makeMapStateToProps)(NetworkDnsComponentQuery);
|
||||
export const NetworkDnsHistogramQuery = connect(makeMapHistogramStateToProps)(
|
||||
NetworkDnsComponentQuery
|
||||
);
|
||||
|
|
|
@ -8034,6 +8034,26 @@
|
|||
"type": { "kind": "OBJECT", "name": "Inspect", "ofType": null },
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "histogram",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "MatrixOverOrdinalHistogramData",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
|
@ -8135,6 +8155,53 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "MatrixOverOrdinalHistogramData",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "Float", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "g",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": { "kind": "SCALAR", "name": "String", "ofType": null }
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "NetworkHttpSortField",
|
||||
|
|
|
@ -1626,6 +1626,8 @@ export interface NetworkDnsData {
|
|||
pageInfo: PageInfoPaginated;
|
||||
|
||||
inspect?: Maybe<Inspect>;
|
||||
|
||||
histogram?: Maybe<MatrixOverOrdinalHistogramData[]>;
|
||||
}
|
||||
|
||||
export interface NetworkDnsEdges {
|
||||
|
@ -1648,6 +1650,14 @@ export interface NetworkDnsItem {
|
|||
uniqueDomains?: Maybe<number>;
|
||||
}
|
||||
|
||||
export interface MatrixOverOrdinalHistogramData {
|
||||
x: string;
|
||||
|
||||
y: number;
|
||||
|
||||
g: string;
|
||||
}
|
||||
|
||||
export interface NetworkHttpData {
|
||||
edges: NetworkHttpEdges[];
|
||||
|
||||
|
@ -3311,6 +3321,8 @@ export namespace GetNetworkDnsQuery {
|
|||
pageInfo: PageInfo;
|
||||
|
||||
inspect: Maybe<Inspect>;
|
||||
|
||||
histogram: Maybe<Histogram[]>;
|
||||
};
|
||||
|
||||
export type Edges = {
|
||||
|
@ -3360,6 +3372,16 @@ export namespace GetNetworkDnsQuery {
|
|||
|
||||
response: string[];
|
||||
};
|
||||
|
||||
export type Histogram = {
|
||||
__typename?: 'MatrixOverOrdinalHistogramData';
|
||||
|
||||
x: string;
|
||||
|
||||
y: number;
|
||||
|
||||
g: string;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace GetNetworkHttpQuery {
|
||||
|
|
|
@ -7,13 +7,16 @@
|
|||
import React from 'react';
|
||||
import { getOr } from 'lodash/fp';
|
||||
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { NetworkDnsTable } from '../../../components/page/network/network_dns_table';
|
||||
import { NetworkDnsQuery } from '../../../containers/network_dns';
|
||||
import { NetworkDnsQuery, NetworkDnsHistogramQuery } from '../../../containers/network_dns';
|
||||
import { manageQuery } from '../../../components/page/manage_query';
|
||||
|
||||
import { DnsQueryTabBodyProps } from './types';
|
||||
import { NetworkDnsHistogram } from '../../../components/page/network/dns_histogram';
|
||||
|
||||
const NetworkDnsTableManage = manageQuery(NetworkDnsTable);
|
||||
const NetworkDnsHistogramManage = manageQuery(NetworkDnsHistogram);
|
||||
|
||||
export const DnsQueryTabBody = ({
|
||||
to,
|
||||
|
@ -22,42 +25,70 @@ export const DnsQueryTabBody = ({
|
|||
from,
|
||||
setQuery,
|
||||
type,
|
||||
updateDateRange = () => {},
|
||||
}: DnsQueryTabBodyProps) => (
|
||||
<NetworkDnsQuery
|
||||
endDate={to}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
sourceId="default"
|
||||
startDate={from}
|
||||
type={type}
|
||||
>
|
||||
{({
|
||||
totalCount,
|
||||
loading,
|
||||
networkDns,
|
||||
pageInfo,
|
||||
loadPage,
|
||||
id,
|
||||
inspect,
|
||||
isInspected,
|
||||
refetch,
|
||||
}) => (
|
||||
<NetworkDnsTableManage
|
||||
data={networkDns}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', pageInfo)}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
isInspect={isInspected}
|
||||
loading={loading}
|
||||
loadPage={loadPage}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
|
||||
totalCount={totalCount}
|
||||
type={type}
|
||||
/>
|
||||
)}
|
||||
</NetworkDnsQuery>
|
||||
<>
|
||||
<NetworkDnsHistogramQuery
|
||||
endDate={to}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
sourceId="default"
|
||||
startDate={from}
|
||||
type={type}
|
||||
>
|
||||
{({ totalCount, loading, id, inspect, refetch, histogram }) => (
|
||||
<NetworkDnsHistogramManage
|
||||
id={id}
|
||||
loading={loading}
|
||||
data={histogram}
|
||||
endDate={to}
|
||||
startDate={from}
|
||||
inspect={inspect}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
totalCount={totalCount}
|
||||
updateDateRange={updateDateRange}
|
||||
/>
|
||||
)}
|
||||
</NetworkDnsHistogramQuery>
|
||||
<EuiSpacer />
|
||||
<NetworkDnsQuery
|
||||
endDate={to}
|
||||
filterQuery={filterQuery}
|
||||
skip={isInitializing}
|
||||
sourceId="default"
|
||||
startDate={from}
|
||||
type={type}
|
||||
>
|
||||
{({
|
||||
totalCount,
|
||||
loading,
|
||||
networkDns,
|
||||
pageInfo,
|
||||
loadPage,
|
||||
id,
|
||||
inspect,
|
||||
isInspected,
|
||||
refetch,
|
||||
histogram,
|
||||
}) => (
|
||||
<NetworkDnsTableManage
|
||||
data={networkDns}
|
||||
fakeTotalCount={getOr(50, 'fakeTotalCount', pageInfo)}
|
||||
id={id}
|
||||
inspect={inspect}
|
||||
isInspect={isInspected}
|
||||
loading={loading}
|
||||
loadPage={loadPage}
|
||||
refetch={refetch}
|
||||
setQuery={setQuery}
|
||||
showMorePagesIndicator={getOr(false, 'showMorePagesIndicator', pageInfo)}
|
||||
totalCount={totalCount}
|
||||
type={type}
|
||||
/>
|
||||
)}
|
||||
</NetworkDnsQuery>
|
||||
</>
|
||||
);
|
||||
|
||||
DnsQueryTabBody.displayName = 'DNSQueryTabBody';
|
||||
|
|
|
@ -19,6 +19,7 @@ import { DnsQueryTabBody } from './dns_query_tab_body';
|
|||
import { ConditionalFlexGroup } from './conditional_flex_group';
|
||||
import { NetworkRoutesProps, NetworkRouteType } from './types';
|
||||
import { TlsQueryTabBody } from './tls_query_tab_body';
|
||||
import { Anomaly } from '../../../components/ml/types';
|
||||
|
||||
export const NetworkRoutes = ({
|
||||
networkPagePath,
|
||||
|
@ -32,7 +33,7 @@ export const NetworkRoutes = ({
|
|||
setAbsoluteRangeDatePicker,
|
||||
}: NetworkRoutesProps) => {
|
||||
const narrowDateRange = useCallback(
|
||||
(score, interval) => {
|
||||
(score: Anomaly, interval: string) => {
|
||||
const fromTo = scoreIntervalToDateTime(score, interval);
|
||||
setAbsoluteRangeDatePicker({
|
||||
id: 'global',
|
||||
|
@ -42,6 +43,12 @@ export const NetworkRoutes = ({
|
|||
},
|
||||
[scoreIntervalToDateTime, setAbsoluteRangeDatePicker]
|
||||
);
|
||||
const updateDateRange = useCallback(
|
||||
(min: number, max: number) => {
|
||||
setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max });
|
||||
},
|
||||
[from, to]
|
||||
);
|
||||
|
||||
const tabProps = {
|
||||
networkPagePath,
|
||||
|
@ -52,6 +59,7 @@ export const NetworkRoutes = ({
|
|||
from,
|
||||
indexPattern,
|
||||
setQuery,
|
||||
updateDateRange,
|
||||
};
|
||||
|
||||
const anomaliesProps = {
|
||||
|
|
|
@ -14,10 +14,13 @@ import { NarrowDateRange } from '../../../components/ml/types';
|
|||
import { GlobalTimeArgs } from '../../../containers/global_time';
|
||||
|
||||
import { SetAbsoluteRangeDatePicker } from '../types';
|
||||
import { UpdateDateRange } from '../../../components/charts/common';
|
||||
|
||||
interface QueryTabBodyProps {
|
||||
type: networkModel.NetworkType;
|
||||
filterQuery?: string | ESTermQuery;
|
||||
updateDateRange?: UpdateDateRange;
|
||||
narrowDateRange?: NarrowDateRange;
|
||||
}
|
||||
|
||||
export type DnsQueryTabBodyProps = QueryTabBodyProps & GlobalTimeArgs;
|
||||
|
|
|
@ -145,11 +145,18 @@ export const networkSchema = gql`
|
|||
cursor: CursorType!
|
||||
}
|
||||
|
||||
type MatrixOverOrdinalHistogramData {
|
||||
x: String!
|
||||
y: Float!
|
||||
g: String!
|
||||
}
|
||||
|
||||
type NetworkDnsData {
|
||||
edges: [NetworkDnsEdges!]!
|
||||
totalCount: Float!
|
||||
pageInfo: PageInfoPaginated!
|
||||
inspect: Inspect
|
||||
histogram: [MatrixOverOrdinalHistogramData!]
|
||||
}
|
||||
|
||||
enum NetworkHttpFields {
|
||||
|
|
|
@ -1628,6 +1628,8 @@ export interface NetworkDnsData {
|
|||
pageInfo: PageInfoPaginated;
|
||||
|
||||
inspect?: Maybe<Inspect>;
|
||||
|
||||
histogram?: Maybe<MatrixOverOrdinalHistogramData[]>;
|
||||
}
|
||||
|
||||
export interface NetworkDnsEdges {
|
||||
|
@ -1650,6 +1652,14 @@ export interface NetworkDnsItem {
|
|||
uniqueDomains?: Maybe<number>;
|
||||
}
|
||||
|
||||
export interface MatrixOverOrdinalHistogramData {
|
||||
x: string;
|
||||
|
||||
y: number;
|
||||
|
||||
g: string;
|
||||
}
|
||||
|
||||
export interface NetworkHttpData {
|
||||
edges: NetworkHttpEdges[];
|
||||
|
||||
|
@ -6949,6 +6959,8 @@ export namespace NetworkDnsDataResolvers {
|
|||
pageInfo?: PageInfoResolver<PageInfoPaginated, TypeParent, TContext>;
|
||||
|
||||
inspect?: InspectResolver<Maybe<Inspect>, TypeParent, TContext>;
|
||||
|
||||
histogram?: HistogramResolver<Maybe<MatrixOverOrdinalHistogramData[]>, TypeParent, TContext>;
|
||||
}
|
||||
|
||||
export type EdgesResolver<
|
||||
|
@ -6971,6 +6983,11 @@ export namespace NetworkDnsDataResolvers {
|
|||
Parent = NetworkDnsData,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
export type HistogramResolver<
|
||||
R = Maybe<MatrixOverOrdinalHistogramData[]>,
|
||||
Parent = NetworkDnsData,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
}
|
||||
|
||||
export namespace NetworkDnsEdgesResolvers {
|
||||
|
@ -7039,6 +7056,32 @@ export namespace NetworkDnsItemResolvers {
|
|||
> = Resolver<R, Parent, TContext>;
|
||||
}
|
||||
|
||||
export namespace MatrixOverOrdinalHistogramDataResolvers {
|
||||
export interface Resolvers<TContext = SiemContext, TypeParent = MatrixOverOrdinalHistogramData> {
|
||||
x?: XResolver<string, TypeParent, TContext>;
|
||||
|
||||
y?: YResolver<number, TypeParent, TContext>;
|
||||
|
||||
g?: GResolver<string, TypeParent, TContext>;
|
||||
}
|
||||
|
||||
export type XResolver<
|
||||
R = string,
|
||||
Parent = MatrixOverOrdinalHistogramData,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
export type YResolver<
|
||||
R = number,
|
||||
Parent = MatrixOverOrdinalHistogramData,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
export type GResolver<
|
||||
R = string,
|
||||
Parent = MatrixOverOrdinalHistogramData,
|
||||
TContext = SiemContext
|
||||
> = Resolver<R, Parent, TContext>;
|
||||
}
|
||||
|
||||
export namespace NetworkHttpDataResolvers {
|
||||
export interface Resolvers<TContext = SiemContext, TypeParent = NetworkHttpData> {
|
||||
edges?: EdgesResolver<NetworkHttpEdges[], TypeParent, TContext>;
|
||||
|
@ -8704,6 +8747,7 @@ export type IResolvers<TContext = SiemContext> = {
|
|||
NetworkDnsData?: NetworkDnsDataResolvers.Resolvers<TContext>;
|
||||
NetworkDnsEdges?: NetworkDnsEdgesResolvers.Resolvers<TContext>;
|
||||
NetworkDnsItem?: NetworkDnsItemResolvers.Resolvers<TContext>;
|
||||
MatrixOverOrdinalHistogramData?: MatrixOverOrdinalHistogramDataResolvers.Resolvers<TContext>;
|
||||
NetworkHttpData?: NetworkHttpDataResolvers.Resolvers<TContext>;
|
||||
NetworkHttpEdges?: NetworkHttpEdgesResolvers.Resolvers<TContext>;
|
||||
NetworkHttpItem?: NetworkHttpItemResolvers.Resolvers<TContext>;
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
NetworkHttpData,
|
||||
NetworkHttpEdges,
|
||||
NetworkTopNFlowEdges,
|
||||
MatrixOverOrdinalHistogramData,
|
||||
} from '../../graphql/types';
|
||||
import { inspectStringifyObject } from '../../utils/build_query';
|
||||
import { DatabaseSearchResponse, FrameworkAdapter, FrameworkRequest } from '../framework';
|
||||
|
@ -140,6 +141,7 @@ export class ElasticsearchNetworkAdapter implements NetworkAdapter {
|
|||
);
|
||||
const fakeTotalCount = fakePossibleCount <= totalCount ? fakePossibleCount : totalCount;
|
||||
const edges = networkDnsEdges.splice(cursorStart, querySize - cursorStart);
|
||||
const histogram = getHistogramData(edges);
|
||||
const inspect = {
|
||||
dsl: [inspectStringifyObject(dsl)],
|
||||
response: [inspectStringifyObject(response)],
|
||||
|
@ -154,6 +156,7 @@ export class ElasticsearchNetworkAdapter implements NetworkAdapter {
|
|||
showMorePagesIndicator,
|
||||
},
|
||||
totalCount,
|
||||
histogram,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -194,6 +197,32 @@ export class ElasticsearchNetworkAdapter implements NetworkAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
const getHistogramData = (
|
||||
data: NetworkDnsEdges[]
|
||||
): MatrixOverOrdinalHistogramData[] | undefined => {
|
||||
if (!Array.isArray(data)) return undefined;
|
||||
return data.reduce(
|
||||
(acc: MatrixOverOrdinalHistogramData[], { node: { dnsBytesOut, dnsBytesIn, _id } }) => {
|
||||
if (_id != null && dnsBytesOut != null && dnsBytesIn != null)
|
||||
return [
|
||||
...acc,
|
||||
{
|
||||
x: _id,
|
||||
y: dnsBytesOut,
|
||||
g: 'DNS Bytes Out',
|
||||
},
|
||||
{
|
||||
x: _id,
|
||||
y: dnsBytesIn,
|
||||
g: 'DNS Bytes In',
|
||||
},
|
||||
];
|
||||
return acc;
|
||||
},
|
||||
[]
|
||||
);
|
||||
};
|
||||
|
||||
const getTopNFlowEdges = (
|
||||
response: DatabaseSearchResponse<NetworkTopNFlowData, TermAggregation>,
|
||||
options: NetworkTopNFlowRequestOptions
|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
"include": [
|
||||
"**/*"
|
||||
],
|
||||
"exclude": [],
|
||||
"exclude": []
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue