mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* chart styling * rename variable * styling for bar chart * add unit test * clean up * fix for code review
This commit is contained in:
parent
20b15ef565
commit
100865a57e
13 changed files with 553 additions and 441 deletions
|
@ -7,13 +7,135 @@
|
|||
import { ShallowWrapper, shallow } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import { AreaChartBaseComponent, AreaChartWithCustomPrompt, AreaChart } from './areachart';
|
||||
import { ChartHolder, ChartSeriesData } from './common';
|
||||
import { AreaChartBaseComponent, AreaChart } from './areachart';
|
||||
import { ChartSeriesData } from './common';
|
||||
import { ScaleType, AreaSeries, Axis } from '@elastic/charts';
|
||||
|
||||
jest.mock('@elastic/charts');
|
||||
const customHeight = '100px';
|
||||
const customWidth = '120px';
|
||||
const chartDataSets = [
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: null },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1096175 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: {} },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
const chartHolderDataSets = [
|
||||
[null],
|
||||
[[]],
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: null,
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: null,
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf() },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf() },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
];
|
||||
describe('AreaChartBaseComponent', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
const mockAreaChartData: ChartSeriesData[] = [
|
||||
|
@ -186,137 +308,6 @@ describe('AreaChartBaseComponent', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('AreaChartWithCustomPrompt', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
describe.each([
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1096175 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
] as Array<[ChartSeriesData[]]>)('renders areachart', data => {
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(
|
||||
<AreaChartWithCustomPrompt height={customHeight} width={customWidth} data={data} />
|
||||
);
|
||||
});
|
||||
|
||||
it('render AreaChartBaseComponent', () => {
|
||||
expect(shallowWrapper.find(AreaChartBaseComponent)).toHaveLength(1);
|
||||
expect(shallowWrapper.find(ChartHolder)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each([
|
||||
null,
|
||||
[],
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: null,
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: null,
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf() },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf() },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf() },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: null },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{
|
||||
key: 'uniqueSourceIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 580213 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: {} },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12382 },
|
||||
],
|
||||
color: '#DB1374',
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationIpsHistogram',
|
||||
value: [
|
||||
{ x: new Date('2019-05-03T13:00:00.000Z').valueOf(), y: 565975 },
|
||||
{ x: new Date('2019-05-04T01:00:00.000Z').valueOf(), y: 1084366 },
|
||||
{ x: new Date('2019-05-04T13:00:00.000Z').valueOf(), y: 12280 },
|
||||
],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
] as Array<[ChartSeriesData[] | null | undefined]>)('renders prompt', data => {
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(
|
||||
<AreaChartWithCustomPrompt height={customHeight} width={customWidth} data={data} />
|
||||
);
|
||||
});
|
||||
|
||||
it('render Chart Holder', () => {
|
||||
expect(shallowWrapper.find(AreaChartBaseComponent)).toHaveLength(0);
|
||||
expect(shallowWrapper.find(ChartHolder)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('AreaChart', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
const mockConfig = {
|
||||
|
@ -332,20 +323,28 @@ describe('AreaChart', () => {
|
|||
},
|
||||
customHeight: 324,
|
||||
};
|
||||
describe.each(chartDataSets as Array<[ChartSeriesData[]]>)('with valid data [%o]', data => {
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(<AreaChart configs={mockConfig} areaChart={data} />);
|
||||
});
|
||||
|
||||
it('should render if data exist', () => {
|
||||
const mockData = [
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 100, x: 100, g: 'group' }], color: '#DB1374' },
|
||||
];
|
||||
shallowWrapper = shallow(<AreaChart configs={mockConfig} areaChart={mockData} />);
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(1);
|
||||
expect(shallowWrapper.find('ChartHolder')).toHaveLength(0);
|
||||
it(`should render area chart`, () => {
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(1);
|
||||
expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('should render a chartHolder if no data given', () => {
|
||||
const mockData = [{ key: 'uniqueSourceIps', value: [], color: '#DB1374' }];
|
||||
shallowWrapper = shallow(<AreaChart configs={mockConfig} areaChart={mockData} />);
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(0);
|
||||
expect(shallowWrapper.find('ChartHolder')).toHaveLength(1);
|
||||
});
|
||||
describe.each(chartHolderDataSets as Array<[ChartSeriesData[] | null | undefined]>)(
|
||||
'with invalid data [%o]',
|
||||
data => {
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(<AreaChart configs={mockConfig} areaChart={data} />);
|
||||
});
|
||||
|
||||
it(`should render a chart place holder`, () => {
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(0);
|
||||
expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -17,19 +17,19 @@ import {
|
|||
AreaSeriesStyle,
|
||||
RecursivePartial,
|
||||
} from '@elastic/charts';
|
||||
import { getOr, get } from 'lodash/fp';
|
||||
import { getOr, get, isNull, isNumber } from 'lodash/fp';
|
||||
import { AutoSizer } from '../auto_sizer';
|
||||
import { ChartPlaceHolder } from './chart_place_holder';
|
||||
import {
|
||||
ChartSeriesData,
|
||||
ChartHolder,
|
||||
getSeriesStyle,
|
||||
WrappedByAutoSizer,
|
||||
ChartSeriesConfigs,
|
||||
browserTimezone,
|
||||
chartDefaultSettings,
|
||||
ChartSeriesConfigs,
|
||||
ChartSeriesData,
|
||||
getChartHeight,
|
||||
getChartWidth,
|
||||
getSeriesStyle,
|
||||
WrappedByAutoSizer,
|
||||
} from './common';
|
||||
import { AutoSizer } from '../auto_sizer';
|
||||
|
||||
// custom series styles: https://ela.st/areachart-styling
|
||||
const getSeriesLineStyle = (): RecursivePartial<AreaSeriesStyle> => {
|
||||
|
@ -51,6 +51,17 @@ const getSeriesLineStyle = (): RecursivePartial<AreaSeriesStyle> => {
|
|||
};
|
||||
};
|
||||
|
||||
const checkIfAllTheDataInTheSeriesAreValid = (series: unknown): series is ChartSeriesData =>
|
||||
!!get('value.length', series) &&
|
||||
get('value', series).every(
|
||||
({ x, y }: { x: unknown; y: unknown }) => !isNull(x) && isNumber(y) && y > 0
|
||||
);
|
||||
|
||||
const checkIfAnyValidSeriesExist = (
|
||||
data: ChartSeriesData[] | null | undefined
|
||||
): data is ChartSeriesData[] =>
|
||||
Array.isArray(data) && data.some(checkIfAllTheDataInTheSeriesAreValid);
|
||||
|
||||
// https://ela.st/multi-areaseries
|
||||
export const AreaChartBaseComponent = React.memo<{
|
||||
data: ChartSeriesData[];
|
||||
|
@ -73,12 +84,12 @@ export const AreaChartBaseComponent = React.memo<{
|
|||
{data.map(series => {
|
||||
const seriesKey = series.key;
|
||||
const seriesSpecId = getSpecId(seriesKey);
|
||||
return series.value != null ? (
|
||||
return checkIfAllTheDataInTheSeriesAreValid(series) ? (
|
||||
<AreaSeries
|
||||
id={seriesSpecId}
|
||||
key={seriesKey}
|
||||
name={series.key.replace('Histogram', '')}
|
||||
data={series.value}
|
||||
data={series.value || undefined}
|
||||
xScaleType={getOr(ScaleType.Linear, 'configs.series.xScaleType', chartConfigs)}
|
||||
yScaleType={getOr(ScaleType.Linear, 'configs.series.yScaleType', chartConfigs)}
|
||||
timeZone={browserTimezone}
|
||||
|
@ -106,28 +117,6 @@ export const AreaChartBaseComponent = React.memo<{
|
|||
|
||||
AreaChartBaseComponent.displayName = 'AreaChartBaseComponent';
|
||||
|
||||
export const AreaChartWithCustomPrompt = React.memo<{
|
||||
data: ChartSeriesData[] | null | undefined;
|
||||
height: string | null | undefined;
|
||||
width: string | null | undefined;
|
||||
configs?: ChartSeriesConfigs | undefined;
|
||||
}>(({ data, height, width, configs }) => {
|
||||
return data != null &&
|
||||
data.length &&
|
||||
data.every(
|
||||
({ value }) =>
|
||||
value != null &&
|
||||
value.length > 0 &&
|
||||
value.every(chart => chart.x != null && chart.y != null)
|
||||
) ? (
|
||||
<AreaChartBaseComponent height={height} width={width} data={data} configs={configs} />
|
||||
) : (
|
||||
<ChartHolder height={height} width={width} />
|
||||
);
|
||||
});
|
||||
|
||||
AreaChartWithCustomPrompt.displayName = 'AreaChartWithCustomPrompt';
|
||||
|
||||
export const AreaChart = React.memo<{
|
||||
areaChart: ChartSeriesData[] | null | undefined;
|
||||
configs?: ChartSeriesConfigs | undefined;
|
||||
|
@ -135,11 +124,11 @@ export const AreaChart = React.memo<{
|
|||
const customHeight = get('customHeight', configs);
|
||||
const customWidth = get('customWidth', configs);
|
||||
|
||||
return get(`0.value.length`, areaChart) ? (
|
||||
return checkIfAnyValidSeriesExist(areaChart) ? (
|
||||
<AutoSizer detectAnyWindowResize={false} content>
|
||||
{({ measureRef, content: { height, width } }) => (
|
||||
<WrappedByAutoSizer innerRef={measureRef} height={getChartHeight(customHeight, height)}>
|
||||
<AreaChartWithCustomPrompt
|
||||
<AreaChartBaseComponent
|
||||
data={areaChart}
|
||||
height={getChartHeight(customHeight, height)}
|
||||
width={getChartWidth(customWidth, width)}
|
||||
|
@ -149,7 +138,11 @@ export const AreaChart = React.memo<{
|
|||
)}
|
||||
</AutoSizer>
|
||||
) : (
|
||||
<ChartHolder height={getChartHeight(customHeight)} width={getChartWidth(customWidth)} />
|
||||
<ChartPlaceHolder
|
||||
height={getChartHeight(customHeight)}
|
||||
width={getChartWidth(customWidth)}
|
||||
data={areaChart}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,13 +7,113 @@
|
|||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
|
||||
import { BarChartBaseComponent, BarChartWithCustomPrompt, BarChart } from './barchart';
|
||||
import { ChartSeriesData, ChartHolder } from './common';
|
||||
import { BarChartBaseComponent, BarChart } from './barchart';
|
||||
import { ChartSeriesData } from './common';
|
||||
import { BarSeries, ScaleType, Axis } from '@elastic/charts';
|
||||
|
||||
jest.mock('@elastic/charts');
|
||||
const customHeight = '100px';
|
||||
const customWidth = '120px';
|
||||
const chartDataSets = [
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: '' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: '' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 0, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: null, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
const chartHolderDataSets: Array<[ChartSeriesData[] | undefined | null]> = [
|
||||
[[]],
|
||||
[null],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{}], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{}],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 0, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 0, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
] as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const mockConfig = {
|
||||
series: {
|
||||
xScaleType: ScaleType.Time,
|
||||
yScaleType: ScaleType.Linear,
|
||||
stackAccessors: ['g'],
|
||||
},
|
||||
axis: {
|
||||
xTickFormatter: jest.fn(),
|
||||
yTickFormatter: jest.fn(),
|
||||
tickSize: 8,
|
||||
},
|
||||
customHeight: 324,
|
||||
};
|
||||
|
||||
describe('BarChartBaseComponent', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
const mockBarChartData: ChartSeriesData[] = [
|
||||
|
@ -168,164 +268,28 @@ describe('BarChartBaseComponent', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe.each([
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: '' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: '' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 1714, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 0, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
])('BarChartWithCustomPrompt', mockBarChartData => {
|
||||
describe.each(chartDataSets)('BarChart with valid data [%o]', data => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
describe('renders barchart', () => {
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(
|
||||
<BarChartWithCustomPrompt
|
||||
height={customHeight}
|
||||
width={customWidth}
|
||||
data={mockBarChartData}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
it('render BarChartBaseComponent', () => {
|
||||
expect(shallowWrapper.find(BarChartBaseComponent)).toHaveLength(1);
|
||||
expect(shallowWrapper.find(ChartHolder)).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const table: Array<[ChartSeriesData[] | undefined | null]> = [
|
||||
[],
|
||||
null,
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{}], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{}],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 0, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 0, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: null, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: 2354, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
{ key: 'uniqueSourceIps', value: [{ y: null, x: 'uniqueSourceIps' }], color: '#DB1374' },
|
||||
{
|
||||
key: 'uniqueDestinationIps',
|
||||
value: [{ y: null, x: 'uniqueDestinationIps' }],
|
||||
color: '#490092',
|
||||
},
|
||||
],
|
||||
],
|
||||
] as any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
describe.each(table)('renders prompt', data => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(
|
||||
<BarChartWithCustomPrompt height={customHeight} width={customWidth} data={data} />
|
||||
);
|
||||
shallowWrapper = shallow(<BarChart configs={mockConfig} barChart={data} />);
|
||||
});
|
||||
|
||||
it('render Chart Holder', () => {
|
||||
expect(shallowWrapper.find(BarChartBaseComponent)).toHaveLength(0);
|
||||
expect(shallowWrapper.find(ChartHolder)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('BarChart', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
const mockConfig = {
|
||||
series: {
|
||||
xScaleType: ScaleType.Time,
|
||||
yScaleType: ScaleType.Linear,
|
||||
stackAccessors: ['g'],
|
||||
},
|
||||
axis: {
|
||||
xTickFormatter: jest.fn(),
|
||||
yTickFormatter: jest.fn(),
|
||||
tickSize: 8,
|
||||
},
|
||||
customHeight: 324,
|
||||
};
|
||||
|
||||
it('should render if data exist', () => {
|
||||
const mockData = [
|
||||
{ key: 'uniqueSourceIps', value: [{ y: 100, x: 100, g: 'group' }], color: '#DB1374' },
|
||||
];
|
||||
shallowWrapper = shallow(<BarChart configs={mockConfig} barChart={mockData} />);
|
||||
it(`should render chart`, () => {
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(1);
|
||||
expect(shallowWrapper.find('ChartHolder')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should render a chartHolder if no data given', () => {
|
||||
const mockData = [{ key: 'uniqueSourceIps', value: [], color: '#DB1374' }];
|
||||
shallowWrapper = shallow(<BarChart configs={mockConfig} barChart={mockData} />);
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(0);
|
||||
expect(shallowWrapper.find('ChartHolder')).toHaveLength(1);
|
||||
expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe.each(chartHolderDataSets)('BarChart with invalid data [%o]', data => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
|
||||
beforeAll(() => {
|
||||
shallowWrapper = shallow(<BarChart configs={mockConfig} barChart={data} />);
|
||||
});
|
||||
|
||||
it(`should render chart holder`, () => {
|
||||
expect(shallowWrapper.find('AutoSizer')).toHaveLength(0);
|
||||
expect(shallowWrapper.find('ChartPlaceHolder')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,20 +16,33 @@ import {
|
|||
ScaleType,
|
||||
Settings,
|
||||
} from '@elastic/charts';
|
||||
import { getOr, get } from 'lodash/fp';
|
||||
import { getOr, get, isNumber } from 'lodash/fp';
|
||||
import { AutoSizer } from '../auto_sizer';
|
||||
import { ChartPlaceHolder } from './chart_place_holder';
|
||||
import {
|
||||
ChartSeriesData,
|
||||
WrappedByAutoSizer,
|
||||
ChartHolder,
|
||||
SeriesType,
|
||||
getSeriesStyle,
|
||||
ChartSeriesConfigs,
|
||||
browserTimezone,
|
||||
chartDefaultSettings,
|
||||
ChartSeriesConfigs,
|
||||
ChartSeriesData,
|
||||
checkIfAllValuesAreZero,
|
||||
getSeriesStyle,
|
||||
getChartHeight,
|
||||
getChartWidth,
|
||||
SeriesType,
|
||||
WrappedByAutoSizer,
|
||||
} from './common';
|
||||
import { AutoSizer } from '../auto_sizer';
|
||||
|
||||
const checkIfAllTheDataInTheSeriesAreValid = (series: ChartSeriesData): series is ChartSeriesData =>
|
||||
series != null &&
|
||||
!!get('value.length', series) &&
|
||||
(series.value || []).every(({ x, y }) => isNumber(y) && y >= 0);
|
||||
|
||||
const checkIfAnyValidSeriesExist = (
|
||||
data: ChartSeriesData[] | null | undefined
|
||||
): data is ChartSeriesData[] =>
|
||||
Array.isArray(data) &&
|
||||
!checkIfAllValuesAreZero(data) &&
|
||||
data.some(checkIfAllTheDataInTheSeriesAreValid);
|
||||
|
||||
// Bar chart rotation: https://ela.st/chart-rotations
|
||||
export const BarChartBaseComponent = React.memo<{
|
||||
|
@ -54,7 +67,7 @@ export const BarChartBaseComponent = React.memo<{
|
|||
const barSeriesKey = series.key;
|
||||
const barSeriesSpecId = getSpecId(barSeriesKey);
|
||||
const seriesType = SeriesType.BAR;
|
||||
return (
|
||||
return checkIfAllTheDataInTheSeriesAreValid ? (
|
||||
<BarSeries
|
||||
id={barSeriesSpecId}
|
||||
key={barSeriesKey}
|
||||
|
@ -69,7 +82,7 @@ export const BarChartBaseComponent = React.memo<{
|
|||
stackAccessors={get('configs.series.stackAccessors', chartConfigs)}
|
||||
customSeriesColors={getSeriesStyle(barSeriesKey, series.color, seriesType)}
|
||||
/>
|
||||
);
|
||||
) : null;
|
||||
})}
|
||||
|
||||
<Axis
|
||||
|
@ -87,37 +100,17 @@ export const BarChartBaseComponent = React.memo<{
|
|||
|
||||
BarChartBaseComponent.displayName = 'BarChartBaseComponent';
|
||||
|
||||
export const BarChartWithCustomPrompt = React.memo<{
|
||||
data: ChartSeriesData[] | null | undefined;
|
||||
height: string | null | undefined;
|
||||
width: string | null | undefined;
|
||||
configs?: ChartSeriesConfigs | undefined;
|
||||
}>(({ data, height, width, configs }) => {
|
||||
return data &&
|
||||
data.length &&
|
||||
data.some(
|
||||
({ value }) =>
|
||||
value != null && value.length > 0 && value.every(chart => chart.y != null && chart.y >= 0)
|
||||
) ? (
|
||||
<BarChartBaseComponent height={height} width={width} data={data} configs={configs} />
|
||||
) : (
|
||||
<ChartHolder height={height} width={width} />
|
||||
);
|
||||
});
|
||||
|
||||
BarChartWithCustomPrompt.displayName = 'BarChartWithCustomPrompt';
|
||||
|
||||
export const BarChart = React.memo<{
|
||||
barChart: ChartSeriesData[] | null | undefined;
|
||||
configs?: ChartSeriesConfigs | undefined;
|
||||
}>(({ barChart, configs }) => {
|
||||
const customHeight = get('customHeight', configs);
|
||||
const customWidth = get('customWidth', configs);
|
||||
return get(`0.value.length`, barChart) ? (
|
||||
return checkIfAnyValidSeriesExist(barChart) ? (
|
||||
<AutoSizer detectAnyWindowResize={false} content>
|
||||
{({ measureRef, content: { height, width } }) => (
|
||||
<WrappedByAutoSizer innerRef={measureRef} height={getChartHeight(customHeight, height)}>
|
||||
<BarChartWithCustomPrompt
|
||||
<BarChartBaseComponent
|
||||
height={getChartHeight(customHeight, height)}
|
||||
width={getChartWidth(customWidth, width)}
|
||||
data={barChart}
|
||||
|
@ -127,7 +120,11 @@ export const BarChart = React.memo<{
|
|||
)}
|
||||
</AutoSizer>
|
||||
) : (
|
||||
<ChartHolder height={getChartHeight(customHeight)} width={getChartWidth(customWidth)} />
|
||||
<ChartPlaceHolder
|
||||
height={getChartHeight(customHeight)}
|
||||
width={getChartWidth(customWidth)}
|
||||
data={barChart}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* 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, ShallowWrapper } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { ChartPlaceHolder } from './chart_place_holder';
|
||||
import { ChartSeriesData } from './common';
|
||||
|
||||
describe('ChartPlaceHolder', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
const mockDataAllZeros = [
|
||||
{
|
||||
key: 'mockKeyA',
|
||||
color: 'mockColor',
|
||||
value: [{ x: 'a', y: 0 }, { x: 'b', y: 0 }],
|
||||
},
|
||||
{
|
||||
key: 'mockKeyB',
|
||||
color: 'mockColor',
|
||||
value: [{ x: 'a', y: 0 }, { x: 'b', y: 0 }],
|
||||
},
|
||||
];
|
||||
const mockDataUnexpectedValue = [
|
||||
{
|
||||
key: 'mockKeyA',
|
||||
color: 'mockColor',
|
||||
value: [{ x: 'a', y: '' }, { x: 'b', y: 0 }],
|
||||
},
|
||||
{
|
||||
key: 'mockKeyB',
|
||||
color: 'mockColor',
|
||||
value: [{ x: 'a', y: {} }, { x: 'b', y: 0 }],
|
||||
},
|
||||
];
|
||||
|
||||
it('should render with default props', () => {
|
||||
const height = `100%`;
|
||||
const width = `100%`;
|
||||
shallowWrapper = shallow(<ChartPlaceHolder data={mockDataAllZeros} />);
|
||||
expect(shallowWrapper.props()).toMatchObject({
|
||||
height,
|
||||
width,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render with given props', () => {
|
||||
const height = `100px`;
|
||||
const width = `100px`;
|
||||
shallowWrapper = shallow(
|
||||
<ChartPlaceHolder height={height} width={width} data={mockDataAllZeros} />
|
||||
);
|
||||
expect(shallowWrapper.props()).toMatchObject({
|
||||
height,
|
||||
width,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render correct wording when all values returned zero', () => {
|
||||
const height = `100px`;
|
||||
const width = `100px`;
|
||||
shallowWrapper = shallow(
|
||||
<ChartPlaceHolder height={height} width={width} data={mockDataAllZeros} />
|
||||
);
|
||||
expect(
|
||||
shallowWrapper
|
||||
.find(`[data-test-subj="chartHolderText"]`)
|
||||
.childAt(0)
|
||||
.text()
|
||||
).toEqual('All values returned zero');
|
||||
});
|
||||
|
||||
it('should render correct wording when unexpected value exists', () => {
|
||||
const height = `100px`;
|
||||
const width = `100px`;
|
||||
shallowWrapper = shallow(
|
||||
<ChartPlaceHolder
|
||||
height={height}
|
||||
width={width}
|
||||
data={mockDataUnexpectedValue as ChartSeriesData[]}
|
||||
/>
|
||||
);
|
||||
expect(
|
||||
shallowWrapper
|
||||
.find(`[data-test-subj="chartHolderText"]`)
|
||||
.childAt(0)
|
||||
.text()
|
||||
).toEqual('Chart Data Not Available');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 { EuiFlexItem, EuiText, EuiFlexGroup } from '@elastic/eui';
|
||||
import styled from 'styled-components';
|
||||
import { ChartSeriesData, checkIfAllValuesAreZero } from './common';
|
||||
import * as i18n from './translation';
|
||||
|
||||
const FlexGroup = styled(EuiFlexGroup)<{ height?: string | null; width?: string | null }>`
|
||||
height: ${({ height }) => (height ? height : '100%')};
|
||||
width: ${({ width }) => (width ? width : '100%')};
|
||||
position: relative;
|
||||
margin: 0;
|
||||
`;
|
||||
|
||||
FlexGroup.displayName = 'FlexGroup';
|
||||
|
||||
export const ChartPlaceHolder = ({
|
||||
height = '100%',
|
||||
width = '100%',
|
||||
data,
|
||||
}: {
|
||||
height?: string | null;
|
||||
width?: string | null;
|
||||
data: ChartSeriesData[] | null | undefined;
|
||||
}) => (
|
||||
<FlexGroup justifyContent="center" alignItems="center" height={height} width={width}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s" textAlign="center" color="subdued" data-test-subj="chartHolderText">
|
||||
{checkIfAllValuesAreZero(data)
|
||||
? i18n.ALL_VALUES_ZEROS_TITLE
|
||||
: i18n.DATA_NOT_AVAILABLE_TITLE}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</FlexGroup>
|
||||
);
|
|
@ -3,18 +3,18 @@
|
|||
* 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, ShallowWrapper } from 'enzyme';
|
||||
import * as React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import {
|
||||
ChartHolder,
|
||||
checkIfAllValuesAreZero,
|
||||
defaultChartHeight,
|
||||
getChartHeight,
|
||||
getChartWidth,
|
||||
WrappedByAutoSizer,
|
||||
defaultChartHeight,
|
||||
getSeriesStyle,
|
||||
SeriesType,
|
||||
getTheme,
|
||||
SeriesType,
|
||||
WrappedByAutoSizer,
|
||||
ChartSeriesData,
|
||||
} from './common';
|
||||
import 'jest-styled-components';
|
||||
import { mergeWithDefaultTheme, LIGHT_THEME } from '@elastic/charts';
|
||||
|
@ -26,30 +26,6 @@ jest.mock('@elastic/charts', () => {
|
|||
};
|
||||
});
|
||||
|
||||
describe('ChartHolder', () => {
|
||||
let shallowWrapper: ShallowWrapper;
|
||||
|
||||
it('should render with default props', () => {
|
||||
const height = `100%`;
|
||||
const width = `100%`;
|
||||
shallowWrapper = shallow(<ChartHolder />);
|
||||
expect(shallowWrapper.props()).toMatchObject({
|
||||
height,
|
||||
width,
|
||||
});
|
||||
});
|
||||
|
||||
it('should render with given props', () => {
|
||||
const height = `100px`;
|
||||
const width = `100px`;
|
||||
shallowWrapper = shallow(<ChartHolder height={height} width={width} />);
|
||||
expect(shallowWrapper.props()).toMatchObject({
|
||||
height,
|
||||
width,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('WrappedByAutoSizer', () => {
|
||||
it('should render correct default height', () => {
|
||||
const wrapper = shallow(<WrappedByAutoSizer />);
|
||||
|
@ -88,7 +64,7 @@ describe('getTheme', () => {
|
|||
chartMargins: { bottom: 0, left: 0, right: 0, top: 4 },
|
||||
chartPaddings: { bottom: 0, left: 0, right: 0, top: 0 },
|
||||
scales: {
|
||||
barsPadding: 0.5,
|
||||
barsPadding: 0.05,
|
||||
},
|
||||
};
|
||||
getTheme();
|
||||
|
@ -130,3 +106,46 @@ describe('getChartWidth', () => {
|
|||
expect(height).toEqual(defaultChartHeight);
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkIfAllValuesAreZero', () => {
|
||||
const mockInvalidDataSets: Array<[ChartSeriesData[]]> = [
|
||||
[[{ key: 'mockKey', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 1 }] }]],
|
||||
[
|
||||
[
|
||||
{ key: 'mockKeyA', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 1 }] },
|
||||
{ key: 'mockKeyB', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 1, y: 0 }] },
|
||||
],
|
||||
],
|
||||
];
|
||||
const mockValidDataSets: Array<[ChartSeriesData[]]> = [
|
||||
[[{ key: 'mockKey', color: 'mockColor', value: [{ x: 0, y: 0 }, { x: 1, y: 0 }] }]],
|
||||
[
|
||||
[
|
||||
{ key: 'mockKeyA', color: 'mockColor', value: [{ x: 1, y: 0 }, { x: 3, y: 0 }] },
|
||||
{ key: 'mockKeyB', color: 'mockColor', value: [{ x: 2, y: 0 }, { x: 4, y: 0 }] },
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
describe.each(mockInvalidDataSets)('with data [%o]', data => {
|
||||
let result: boolean;
|
||||
beforeAll(() => {
|
||||
result = checkIfAllValuesAreZero(data);
|
||||
});
|
||||
|
||||
it(`should return false`, () => {
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe.each(mockValidDataSets)('with data [%o]', data => {
|
||||
let result: boolean;
|
||||
beforeAll(() => {
|
||||
result = checkIfAllValuesAreZero(data);
|
||||
});
|
||||
|
||||
it(`should return true`, () => {
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,58 +3,33 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { EuiFlexGroup, EuiText, EuiFlexItem } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import {
|
||||
CustomSeriesColorsMap,
|
||||
DARK_THEME,
|
||||
DataSeriesColorsValues,
|
||||
getSpecId,
|
||||
LIGHT_THEME,
|
||||
mergeWithDefaultTheme,
|
||||
PartialTheme,
|
||||
LIGHT_THEME,
|
||||
DARK_THEME,
|
||||
ScaleType,
|
||||
TickFormatter,
|
||||
SettingSpecProps,
|
||||
Rotation,
|
||||
Rendering,
|
||||
Rotation,
|
||||
ScaleType,
|
||||
SettingSpecProps,
|
||||
TickFormatter,
|
||||
} from '@elastic/charts';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
import moment from 'moment-timezone';
|
||||
import styled from 'styled-components';
|
||||
import { DEFAULT_DATE_FORMAT_TZ, DEFAULT_DARK_MODE } from '../../../common/constants';
|
||||
|
||||
export const defaultChartHeight = '100%';
|
||||
export const defaultChartWidth = '100%';
|
||||
const chartDefaultRotation: Rotation = 0;
|
||||
const chartDefaultRendering: Rendering = 'canvas';
|
||||
const FlexGroup = styled(EuiFlexGroup)<{ height?: string | null; width?: string | null }>`
|
||||
height: ${({ height }) => (height ? height : '100%')};
|
||||
width: ${({ width }) => (width ? width : '100%')};
|
||||
`;
|
||||
|
||||
FlexGroup.displayName = 'FlexGroup';
|
||||
|
||||
export type UpdateDateRange = (min: number, max: number) => void;
|
||||
|
||||
export const ChartHolder = ({
|
||||
height = '100%',
|
||||
width = '100%',
|
||||
}: {
|
||||
height?: string | null;
|
||||
width?: string | null;
|
||||
}) => (
|
||||
<FlexGroup justifyContent="center" alignItems="center" height={height} width={width}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiText size="s" textAlign="center" color="subdued">
|
||||
{i18n.translate('xpack.siem.chart.dataNotAvailableTitle', {
|
||||
defaultMessage: 'Chart Data Not Available',
|
||||
})}
|
||||
</EuiText>
|
||||
</EuiFlexItem>
|
||||
</FlexGroup>
|
||||
);
|
||||
|
||||
export interface ChartData {
|
||||
x: number | string | null;
|
||||
y: number | string | null;
|
||||
|
@ -136,7 +111,7 @@ export const getTheme = () => {
|
|||
bottom: 0,
|
||||
},
|
||||
scales: {
|
||||
barsPadding: 0.5,
|
||||
barsPadding: 0.05,
|
||||
},
|
||||
};
|
||||
const isDarkMode: boolean = chrome.getUiSettingsClient().get(DEFAULT_DARK_MODE);
|
||||
|
@ -166,3 +141,9 @@ export const getChartWidth = (customWidth?: number, autoSizerWidth?: number): st
|
|||
const height = customWidth || autoSizerWidth;
|
||||
return height ? `${height}px` : defaultChartWidth;
|
||||
};
|
||||
|
||||
export const checkIfAllValuesAreZero = (data: ChartSeriesData[] | null | undefined): boolean =>
|
||||
Array.isArray(data) &&
|
||||
data.every(series => {
|
||||
return Array.isArray(series.value) && (series.value as ChartData[]).every(({ y }) => y === 0);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* 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 ALL_VALUES_ZEROS_TITLE = i18n.translate('xpack.siem.chart.dataAllValuesZerosTitle', {
|
||||
defaultMessage: 'All values returned zero',
|
||||
});
|
||||
|
||||
export const DATA_NOT_AVAILABLE_TITLE = i18n.translate('xpack.siem.chart.dataNotAvailableTitle', {
|
||||
defaultMessage: 'Chart Data Not Available',
|
||||
});
|
|
@ -53,7 +53,7 @@ const getBarchartConfigs = (from: number, to: number, onBrushEnd: UpdateDateRang
|
|||
showLegend: true,
|
||||
theme: {
|
||||
scales: {
|
||||
barsPadding: 0.05,
|
||||
barsPadding: 0.08,
|
||||
},
|
||||
chartMargins: {
|
||||
left: 0,
|
||||
|
|
|
@ -184,12 +184,19 @@ export const mockEnableChartsData = {
|
|||
{
|
||||
key: 'uniqueSourcePrivateIps',
|
||||
color: '#DB1374',
|
||||
value: [{ x: 'Src.', y: 383, g: 'uniqueSourcePrivateIps' }],
|
||||
value: [
|
||||
{
|
||||
x: 'Src.',
|
||||
y: 383,
|
||||
g: 'uniqueSourcePrivateIps',
|
||||
y0: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'uniqueDestinationPrivateIps',
|
||||
color: '#490092',
|
||||
value: [{ x: 'Dest.', y: 18, g: 'uniqueDestinationPrivateIps' }],
|
||||
value: [{ x: 'Dest.', y: 18, g: 'uniqueDestinationPrivateIps', y0: 0 }],
|
||||
},
|
||||
],
|
||||
description: 'Unique private IPs',
|
||||
|
|
|
@ -994,6 +994,9 @@ exports[`Stat Items Component rendering kpis with charts it renders the default
|
|||
},
|
||||
"customHeight": 74,
|
||||
"series": Object {
|
||||
"stackAccessors": Array [
|
||||
"y0",
|
||||
],
|
||||
"xScaleType": "ordinal",
|
||||
"yScaleType": "linear",
|
||||
},
|
||||
|
|
|
@ -103,6 +103,7 @@ export const barchartConfigs = (config?: { onElementClick?: ElementClickListener
|
|||
series: {
|
||||
xScaleType: ScaleType.Ordinal,
|
||||
yScaleType: ScaleType.Linear,
|
||||
stackAccessors: ['y0'],
|
||||
},
|
||||
axis: {
|
||||
xTickFormatter: numberFormatter,
|
||||
|
@ -145,6 +146,7 @@ export const addValueToBarChart = (
|
|||
x,
|
||||
y,
|
||||
g: key,
|
||||
y0: 0,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue