diff --git a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx index 4784e3dc45d1c9..6f41b1f2c99cdc 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/areachart.tsx @@ -24,6 +24,7 @@ import { getTheme, ChartSeriesConfigs, browserTimezone, + chartDefaultSettings, } from './common'; import { AutoSizer } from '../auto_sizer'; @@ -68,11 +69,14 @@ export const AreaChartBaseComponent = React.memo<{ const yTickFormatter = get('configs.axis.yTickFormatter', chartConfigs); const xAxisId = getAxisId(`group-${data[0].key}-x`); const yAxisId = getAxisId(`group-${data[0].key}-y`); - + const settings = { + ...chartDefaultSettings, + ...get('configs.settings', chartConfigs), + }; return chartConfigs.width && chartConfigs.height ? (
- + {data.map(series => { const seriesKey = series.key; const seriesSpecId = getSpecId(seriesKey); diff --git a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx index f63b1699e2f4d8..4408879ec729cf 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/barchart.tsx @@ -18,6 +18,7 @@ import { getTheme, ChartSeriesConfigs, browserTimezone, + chartDefaultSettings, } from './common'; import { AutoSizer } from '../auto_sizer'; @@ -32,10 +33,13 @@ export const BarChartBaseComponent = React.memo<{ const yTickFormatter = get('configs.axis.yTickFormatter', chartConfigs); const xAxisId = getAxisId(`stat-items-barchart-${data[0].key}-x`); const yAxisId = getAxisId(`stat-items-barchart-${data[0].key}-y`); - + const settings = { + ...chartDefaultSettings, + ...get('configs.settings', chartConfigs), + }; return chartConfigs.width && chartConfigs.height ? ( - + {data.map(series => { const barSeriesKey = series.key; const barSeriesSpecId = getSpecId(barSeriesKey); diff --git a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx index c8646900e52506..05ca3d29dafa68 100644 --- a/x-pack/legacy/plugins/siem/public/components/charts/common.tsx +++ b/x-pack/legacy/plugins/siem/public/components/charts/common.tsx @@ -17,14 +17,18 @@ import { ScaleType, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; -import { TickFormatter } from '@elastic/charts/dist/lib/series/specs'; +import { TickFormatter, Rotation, Rendering } from '@elastic/charts/dist/lib/series/specs'; import chrome from 'ui/chrome'; import moment from 'moment-timezone'; +import { SettingSpecProps } from '@elastic/charts/dist/specs/settings'; const chartHeight = 74; +const chartDefaultRotation: Rotation = 0; +const chartDefaultRendering: Rendering = 'canvas'; const FlexGroup = styled(EuiFlexGroup)` height: 100%; `; +export type UpdateDateRange = (min: number, max: number) => void; export const ChartHolder = () => ( @@ -38,6 +42,15 @@ export const ChartHolder = () => ( ); +export const chartDefaultSettings = { + rotation: chartDefaultRotation, + rendering: chartDefaultRendering, + animatedData: false, + showLegend: false, + showLegendDisplayValue: false, + debug: false, +}; + export interface ChartData { x: number | string | null; y: number | string | null; @@ -54,6 +67,7 @@ export interface ChartSeriesConfigs { xTickFormatter?: TickFormatter | undefined; yTickFormatter?: TickFormatter | undefined; }; + settings?: Partial; } export interface ChartConfigsData { diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.test.tsx index 671514062e394c..f9e23b28109169 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.test.tsx @@ -17,17 +17,32 @@ describe('kpiHostsComponent', () => { const ID = 'kpiHost'; const from = new Date('2019-06-15T06:00:00.000Z').valueOf(); const to = new Date('2019-06-18T06:00:00.000Z').valueOf(); + const narrowDateRange = () => {}; describe('render', () => { test('it should render spinner if it is loading', () => { const wrapper: ShallowWrapper = shallow( - + ); expect(toJson(wrapper)).toMatchSnapshot(); }); test('it should render KpiHostsData', () => { const wrapper: ShallowWrapper = shallow( - + ); expect(toJson(wrapper)).toMatchSnapshot(); }); @@ -40,6 +55,7 @@ describe('kpiHostsComponent', () => { id={ID} loading={false} to={to} + narrowDateRange={narrowDateRange} /> ); expect(toJson(wrapper)).toMatchSnapshot(); @@ -56,7 +72,16 @@ describe('kpiHostsComponent', () => { }); beforeEach(() => { - shallow(); + shallow( + + ); }); afterEach(() => { @@ -68,7 +93,7 @@ describe('kpiHostsComponent', () => { }); test(`it should apply correct mapping by given data type`, () => { - expect(mockUseKpiMatrixStatus).toBeCalledWith(mapping, data, ID, from, to); + expect(mockUseKpiMatrixStatus).toBeCalledWith(mapping, data, ID, from, to, narrowDateRange); }); }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx index b8fa63c8d55e50..c7dafa224142eb 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/hosts/kpi_hosts/index.tsx @@ -13,6 +13,7 @@ import { KpiHostsData, KpiHostDetailsData } from '../../../../graphql/types'; import { StatItemsComponent, StatItemsProps, useKpiMatrixStatus } from '../../../stat_items'; import { kpiHostsMapping } from './kpi_hosts_mapping'; import { kpiHostDetailsMapping } from './kpi_host_details_mapping'; +import { UpdateDateRange } from '../../../charts/common'; const kpiWidgetHeight = 247; @@ -21,6 +22,7 @@ interface GenericKpiHostProps { id: string; loading: boolean; to: number; + narrowDateRange: UpdateDateRange; } interface KpiHostsProps extends GenericKpiHostProps { @@ -43,10 +45,18 @@ export const KpiHostsComponent = ({ loading, id, to, + narrowDateRange, }: KpiHostsProps | KpiHostDetailsProps) => { const mappings = (data as KpiHostsData).hosts !== undefined ? kpiHostsMapping : kpiHostDetailsMapping; - const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(mappings, data, id, from, to); + const statItemsProps: StatItemsProps[] = useKpiMatrixStatus( + mappings, + data, + id, + from, + to, + narrowDateRange + ); return loading ? ( diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/__snapshots__/index.test.tsx.snap index 2895b3b41a3a89..912a383d09e436 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/__snapshots__/index.test.tsx.snap @@ -35,6 +35,7 @@ exports[`KpiNetwork Component rendering it renders loading icons 1`] = ` from={1560578400000} id="kpiNetwork" loading={true} + narrowDateRange={[MockFunction]} to={1560837600000} /> `; @@ -74,6 +75,7 @@ exports[`KpiNetwork Component rendering it renders the default widget 1`] = ` from={1560578400000} id="kpiNetwork" loading={false} + narrowDateRange={[MockFunction]} to={1560837600000} /> `; diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.test.tsx index cfcbbfd6828793..eb6204044bdb77 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.test.tsx @@ -19,6 +19,7 @@ describe('KpiNetwork Component', () => { const state: State = mockGlobalState; const from = new Date('2019-06-15T06:00:00.000Z').valueOf(); const to = new Date('2019-06-18T06:00:00.000Z').valueOf(); + const narrowDateRange = jest.fn(); let store = createStore(state, apolloClientObservable); @@ -36,6 +37,7 @@ describe('KpiNetwork Component', () => { id="kpiNetwork" loading={true} to={to} + narrowDateRange={narrowDateRange} /> ); @@ -52,6 +54,7 @@ describe('KpiNetwork Component', () => { id="kpiNetwork" loading={false} to={to} + narrowDateRange={narrowDateRange} /> ); diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx index 9cf34029f54335..88c895eeb8af4d 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/index.tsx @@ -20,6 +20,7 @@ import { import { KpiNetworkData } from '../../../../graphql/types'; import * as i18n from './translations'; +import { UpdateDateRange } from '../../../charts/common'; const kipsPerRow = 2; const kpiWidgetHeight = 228; @@ -34,6 +35,7 @@ interface KpiNetworkProps { id: string; loading: boolean; to: number; + narrowDateRange: UpdateDateRange; } export const fieldTitleChartMapping: Readonly = [ @@ -124,14 +126,23 @@ export const KpiNetworkBaseComponent = ({ id, from, to, + narrowDateRange, }: { fieldsMapping: Readonly; data: KpiNetworkData; id: string; from: number; to: number; + narrowDateRange: UpdateDateRange; }) => { - const statItemsProps: StatItemsProps[] = useKpiMatrixStatus(fieldsMapping, data, id, from, to); + const statItemsProps: StatItemsProps[] = useKpiMatrixStatus( + fieldsMapping, + data, + id, + from, + to, + narrowDateRange + ); return ( @@ -143,7 +154,7 @@ export const KpiNetworkBaseComponent = ({ }; export const KpiNetworkComponent = React.memo( - ({ data, from, id, loading, to }) => { + ({ data, from, id, loading, to, narrowDateRange }) => { return loading ? ( @@ -162,6 +173,7 @@ export const KpiNetworkComponent = React.memo( fieldsMapping={mappingsPerLine} from={from} to={to} + narrowDateRange={narrowDateRange} /> ))} @@ -173,6 +185,7 @@ export const KpiNetworkComponent = React.memo( fieldsMapping={fieldTitleChartMapping} from={from} to={to} + narrowDateRange={narrowDateRange} /> diff --git a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/mock.ts b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/mock.ts index 69e14b4796fbe9..d7f0686dc5b69d 100644 --- a/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/mock.ts +++ b/x-pack/legacy/plugins/siem/public/components/page/network/kpi_network/mock.ts @@ -7,6 +7,8 @@ import { KpiNetworkData } from '../../../../graphql/types'; import { StatItems } from '../../../stat_items'; +export const mockNarrowDateRange = jest.fn(); + export const mockData: { KpiNetwork: KpiNetworkData } = { KpiNetwork: { networkEvents: 16, @@ -216,4 +218,5 @@ export const mockEnableChartsData = { id: 'statItem', index: 4, to: 1560837600000, + narrowDateRange: mockNarrowDateRange, }; diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap index fb0e584d032bc7..a26a654c809406 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/__snapshots__/index.test.tsx.snap @@ -28,6 +28,7 @@ exports[`Stat Items Component disable charts it renders the default widget 1`] = id="statItems" index={0} key="mock-keys" + narrowDateRange={[MockFunction]} to={1560837600000} > @@ -271,6 +272,7 @@ exports[`Stat Items Component disable charts it renders the default widget 2`] = id="statItems" index={0} key="mock-keys" + narrowDateRange={[MockFunction]} to={1560837600000} > @@ -587,6 +589,7 @@ exports[`Stat Items Component rendering kpis with charts it renders the default id="statItems" index={0} key="mock-keys" + narrowDateRange={[MockFunction]} to={1560837600000} > @@ -973,6 +976,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "ordinal", "yScaleType": "linear", }, + "settings": Object { + "onElementClick": [Function], + "rotation": 90, + }, } } > @@ -996,6 +1003,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "ordinal", "yScaleType": "linear", }, + "settings": Object { + "onElementClick": [Function], + "rotation": 90, + }, } } data={ @@ -1033,6 +1044,10 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "ordinal", "yScaleType": "linear", }, + "settings": Object { + "onElementClick": [Function], + "rotation": 90, + }, } } data={ @@ -1126,6 +1141,9 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "time", "yScaleType": "linear", }, + "settings": Object { + "onBrushEnd": [MockFunction], + }, } } > @@ -1150,6 +1168,9 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "time", "yScaleType": "linear", }, + "settings": Object { + "onBrushEnd": [MockFunction], + }, } } data={ @@ -1204,6 +1225,9 @@ exports[`Stat Items Component rendering kpis with charts it renders the default "xScaleType": "time", "yScaleType": "linear", }, + "settings": Object { + "onBrushEnd": [MockFunction], + }, } } data={ diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/stat_items/index.test.tsx index e171e1d853c001..b6185d7f0d12d3 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/index.test.tsx @@ -25,6 +25,7 @@ import { mockData, mockEnableChartsData, mockNoChartMappings, + mockNarrowDateRange, } from '../page/network/kpi_network/mock'; import { mockGlobalState, apolloClientObservable } from '../../mock'; import { State, createStore } from '../../store'; @@ -50,6 +51,7 @@ describe('Stat Items Component', () => { index={0} key="mock-keys" to={to} + narrowDateRange={mockNarrowDateRange} /> ), @@ -67,6 +69,7 @@ describe('Stat Items Component', () => { index={0} key="mock-keys" to={to} + narrowDateRange={mockNarrowDateRange} /> ), @@ -151,6 +154,7 @@ describe('Stat Items Component', () => { index: 0, key: 'mock-keys', to, + narrowDateRange: mockNarrowDateRange, }; let wrapper: ReactWrapper; beforeAll(() => { @@ -229,7 +233,8 @@ describe('useKpiMatrixStatus', () => { data, 'statItem', from, - to + to, + mockNarrowDateRange ); return ( diff --git a/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx b/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx index 3caee78ce6775e..1bac959c7f6887 100644 --- a/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/stat_items/index.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ScaleType, niceTimeFormatter } from '@elastic/charts'; +import { ScaleType, niceTimeFormatter, Rotation } from '@elastic/charts'; import { EuiFlexGroup, EuiFlexItem, @@ -18,10 +18,11 @@ import { get, getOr } from 'lodash/fp'; import React, { useState, useEffect } from 'react'; import styled from 'styled-components'; +import { BrushEndListener, ElementClickListener } from '@elastic/charts/dist/state/chart_state'; import { KpiHostsData, KpiNetworkData } from '../../graphql/types'; import { AreaChart } from '../charts/areachart'; import { BarChart } from '../charts/barchart'; -import { ChartConfigsData, ChartData, ChartSeriesConfigs } from '../charts/common'; +import { ChartConfigsData, ChartData, ChartSeriesConfigs, UpdateDateRange } from '../charts/common'; import { getEmptyTagValue } from '../empty_value'; import { InspectButton } from '../inspect'; @@ -62,22 +63,31 @@ export interface StatItemsProps extends StatItems { barChart?: ChartConfigsData[]; from: number; id: string; - to: number; + narrowDateRange: UpdateDateRange; } export const numberFormatter = (value: string | number): string => value.toLocaleString(); -export const areachartConfigs = (from: number, to: number) => ({ +const statItemBarchartRotation: Rotation = 90; + +export const areachartConfigs = (config?: { + xTickFormatter: (value: number) => string; + onBrushEnd?: BrushEndListener; +}) => ({ series: { xScaleType: ScaleType.Time, yScaleType: ScaleType.Linear, }, axis: { - xTickFormatter: niceTimeFormatter([from, to]), + xTickFormatter: get('xTickFormatter', config), yTickFormatter: numberFormatter, }, + settings: { + onBrushEnd: getOr(() => {}, 'onBrushEnd', config), + }, }); -export const barchartConfigs = { + +export const barchartConfigs = (config?: { onElementClick?: ElementClickListener }) => ({ series: { xScaleType: ScaleType.Ordinal, yScaleType: ScaleType.Linear, @@ -85,7 +95,11 @@ export const barchartConfigs = { axis: { xTickFormatter: numberFormatter, }, -}; + settings: { + onElementClick: getOr(() => {}, 'onElementClick', config), + rotation: statItemBarchartRotation, + }, +}); export const addValueToFields = ( fields: StatItem[], @@ -137,7 +151,8 @@ export const useKpiMatrixStatus = ( data: KpiHostsData | KpiNetworkData, id: string, from: number, - to: number + to: number, + narrowDateRange: UpdateDateRange ): StatItemsProps[] => { const [statItemsProps, setStatItemsProps] = useState(mappings as StatItemsProps[]); @@ -153,6 +168,7 @@ export const useKpiMatrixStatus = ( key: `kpi-summary-${stat.key}`, from, to, + narrowDateRange, }; }) ); @@ -174,6 +190,7 @@ export const StatItemsComponent = React.memo( id, index, to, + narrowDateRange, }) => { const [isHover, setIsHover] = useState(false); const isBarChartDataAvailable = @@ -235,13 +252,19 @@ export const StatItemsComponent = React.memo( {enableBarChart && ( - + )} {enableAreaChart && from != null && to != null && ( - + )} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx index f6ad586a83b2b7..271d490a003fd3 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/host_details.tsx @@ -151,6 +151,11 @@ const HostDetailsComponent = pure( refetch={refetch} setQuery={setQuery} to={to} + narrowDateRange={(min: number, max: number) => { + setTimeout(() => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, 500); + }} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx index 66352265c00e34..7040fd3dc609da 100644 --- a/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/hosts/hosts.tsx @@ -96,6 +96,11 @@ const HostsComponent = pure(({ filterQuery, setAbsoluteRang refetch={refetch} setQuery={setQuery} to={to} + narrowDateRange={(min: number, max: number) => { + setTimeout(() => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, 500); + }} /> )} diff --git a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx index 3fa8cbe623d038..a0d7f6c1a444e4 100644 --- a/x-pack/legacy/plugins/siem/public/pages/network/network.tsx +++ b/x-pack/legacy/plugins/siem/public/pages/network/network.tsx @@ -85,6 +85,11 @@ const NetworkComponent = pure( loading={loading} from={from} to={to} + narrowDateRange={(min: number, max: number) => { + setTimeout(() => { + setAbsoluteRangeDatePicker({ id: 'global', from: min, to: max }); + }, 500); + }} /> )}