[Lens] Use new charts APIs to simplify series naming (#60708)

* build: update @elastic/charts to v18.1.0

* tests: fix breaking-change on legendItem className

* fix: type changes and ml custom tooltip data

* tests: fix snapshot test

* [Lens] Use new charts APIs to simplify series naming

* Fix types

* Fix naming

* Remove accidental file

* Update snapshots

Co-authored-by: Marco Vettorello <vettorello.marco@gmail.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Wylie Conlon 2020-03-23 16:44:57 -04:00 committed by GitHub
parent 3eeb8df172
commit 3c924d9f87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 121 additions and 129 deletions

View file

@ -29,24 +29,23 @@ exports[`xy_expression XYChart component it renders area 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -58,8 +57,8 @@ exports[`xy_expression XYChart component it renders area 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -96,24 +95,23 @@ exports[`xy_expression XYChart component it renders bar 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -125,8 +123,8 @@ exports[`xy_expression XYChart component it renders bar 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -163,24 +161,23 @@ exports[`xy_expression XYChart component it renders horizontal bar 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -192,8 +189,8 @@ exports[`xy_expression XYChart component it renders horizontal bar 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -230,24 +227,23 @@ exports[`xy_expression XYChart component it renders line 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -259,8 +255,8 @@ exports[`xy_expression XYChart component it renders line 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -297,24 +293,23 @@ exports[`xy_expression XYChart component it renders stacked area 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -330,8 +325,8 @@ exports[`xy_expression XYChart component it renders stacked area 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -368,24 +363,23 @@ exports[`xy_expression XYChart component it renders stacked bar 1`] = `
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -401,8 +395,8 @@ exports[`xy_expression XYChart component it renders stacked bar 1`] = `
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"
@ -439,24 +433,23 @@ exports[`xy_expression XYChart component it renders stacked horizontal bar 1`] =
data={
Array [
Object {
"Label A": 1,
"Label B": 2,
"Label D": "Foo",
"a": 1,
"b": 2,
"c": "I",
"d": "Foo",
},
Object {
"Label A": 1,
"Label B": 5,
"Label D": "Bar",
"a": 1,
"b": 5,
"c": "J",
"d": "Bar",
},
]
}
enableHistogramMode={false}
id="Label D"
id="d"
key="0"
name={[Function]}
splitSeriesAccessors={
Array [
"d",
@ -472,8 +465,8 @@ exports[`xy_expression XYChart component it renders stacked horizontal bar 1`] =
xScaleType="ordinal"
yAccessors={
Array [
"Label A",
"Label B",
"a",
"b",
]
}
yScaleType="linear"

View file

@ -12,6 +12,7 @@ import {
LineSeries,
Settings,
ScaleType,
SeriesNameFn,
} from '@elastic/charts';
import { xyChart, XYChart } from './xy_expression';
import { LensMultiTable } from '../types';
@ -367,7 +368,7 @@ describe('xy_expression', () => {
expect(component.find(BarSeries).prop('enableHistogramMode')).toEqual(false);
});
test('it rewrites the rows based on provided labels', () => {
test('it names the series for multiple accessors', () => {
const { data, args } = sampleArgs();
const component = shallow(
@ -379,25 +380,56 @@ describe('xy_expression', () => {
chartTheme={{}}
/>
);
expect(component.find(LineSeries).prop('data')).toEqual([
{ 'Label A': 1, 'Label B': 2, c: 'I', 'Label D': 'Foo', d: 'Foo' },
{ 'Label A': 1, 'Label B': 5, c: 'J', 'Label D': 'Bar', d: 'Bar' },
]);
const nameFn = component.find(LineSeries).prop('name') as SeriesNameFn;
expect(
nameFn(
{
seriesKeys: ['a', 'b', 'c', 'd'],
key: '',
specId: 'a',
yAccessor: '',
splitAccessors: new Map(),
},
false
)
).toEqual('Label A - Label B - c - Label D');
});
test('it uses labels as Y accessors', () => {
test('it names the series for a single accessor', () => {
const { data, args } = sampleArgs();
const component = shallow(
<XYChart
data={data}
args={args}
args={{
...args,
layers: [
{
...args.layers[0],
accessors: ['a'],
},
],
}}
formatFactory={getFormatSpy}
timeZone="UTC"
chartTheme={{}}
/>
);
expect(component.find(LineSeries).prop('yAccessors')).toEqual(['Label A', 'Label B']);
const nameFn = component.find(LineSeries).prop('name') as SeriesNameFn;
expect(
nameFn(
{
seriesKeys: ['a', 'b', 'c', 'd'],
key: '',
specId: 'a',
yAccessor: '',
splitAccessors: new Map(),
},
false
)
).toEqual('Label A');
});
test('it set the scale of the x axis according to the args prop', () => {

View file

@ -18,7 +18,6 @@ import {
} from '@elastic/charts';
import { I18nProvider } from '@kbn/i18n/react';
import {
KibanaDatatable,
IInterpreterRenderHandlers,
ExpressionRenderDefinition,
ExpressionFunctionDefinition,
@ -33,6 +32,11 @@ import { XYArgs, SeriesType, visualizationTypes } from './types';
import { VisualizationContainer } from '../visualization_container';
import { isHorizontalChart } from './state_helpers';
type InferPropType<T> = T extends React.FunctionComponent<infer P> ? P : T;
type SeriesSpec = InferPropType<typeof LineSeries> &
InferPropType<typeof BarSeries> &
InferPropType<typeof AreaSeries>;
export interface XYChartProps {
data: LensMultiTable;
args: XYArgs;
@ -247,80 +251,43 @@ export function XYChart({ data, args, formatFactory, timeZone, chartTheme }: XYC
return;
}
const columnToLabelMap = columnToLabel ? JSON.parse(columnToLabel) : {};
const splitAccessorLabel = splitAccessor ? columnToLabelMap[splitAccessor] : '';
const yAccessors = accessors.map(accessor => columnToLabelMap[accessor] || accessor);
const idForLegend = splitAccessorLabel || yAccessors;
const sanitized = sanitizeRows({
splitAccessor,
formatFactory,
columnToLabelMap,
table: data.tables[layerId],
});
const seriesProps = {
key: index,
splitSeriesAccessors: sanitized.splitAccessor ? [sanitized.splitAccessor] : [],
const columnToLabelMap: Record<string, string> = columnToLabel
? JSON.parse(columnToLabel)
: {};
const table = data.tables[layerId];
const seriesProps: SeriesSpec = {
splitSeriesAccessors: splitAccessor ? [splitAccessor] : [],
stackAccessors: seriesType.includes('stacked') ? [xAccessor] : [],
id: idForLegend,
id: splitAccessor || accessors.join(','),
xAccessor,
yAccessors,
data: sanitized.rows,
yAccessors: accessors,
data: table.rows,
xScaleType,
yScaleType,
enableHistogramMode: isHistogram && (seriesType.includes('stacked') || !splitAccessor),
timeZone,
name(d) {
if (accessors.length > 1) {
return d.seriesKeys
.map((key: string | number) => columnToLabelMap[key] || key)
.join(' - ');
}
return columnToLabelMap[d.seriesKeys[0]] ?? d.seriesKeys[0];
},
};
return seriesType === 'line' ? (
<LineSeries {...seriesProps} />
<LineSeries key={index} {...seriesProps} />
) : seriesType === 'bar' ||
seriesType === 'bar_stacked' ||
seriesType === 'bar_horizontal' ||
seriesType === 'bar_horizontal_stacked' ? (
<BarSeries {...seriesProps} />
<BarSeries key={index} {...seriesProps} />
) : (
<AreaSeries {...seriesProps} />
<AreaSeries key={index} {...seriesProps} />
);
}
)}
</Chart>
);
}
/**
* Renames the columns to match the user-configured accessors in
* columnToLabelMap. If a splitAccessor is provided, formats the
* values in that column.
*/
function sanitizeRows({
splitAccessor,
table,
formatFactory,
columnToLabelMap,
}: {
splitAccessor?: string;
table: KibanaDatatable;
formatFactory: FormatFactory;
columnToLabelMap: Record<string, string | undefined>;
}) {
const column = table.columns.find(c => c.id === splitAccessor);
const formatter = formatFactory(column && column.formatHint);
return {
splitAccessor: column && column.id,
rows: table.rows.map(r => {
const newRow: typeof r = {};
if (column) {
newRow[column.id] = formatter.convert(r[column.id]);
}
Object.keys(r).forEach(key => {
const newKey = columnToLabelMap[key] || key;
newRow[newKey] = r[key];
});
return newRow;
}),
};
}