[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:
parent
3eeb8df172
commit
3c924d9f87
|
@ -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"
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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;
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue