mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[TSVB][Lens]Fix conversion from static value in timeseries to reference line in lens (#142453) (#142596)
* Fix conversion static value in timeseries to reference line in lens
* Doesn't allow convert static value with split
* Fix condition
* Ignore axis position from model for top n
* Added tests
Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
(cherry picked from commit 8e770bb608
)
# Conflicts:
# src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.test.ts
# src/plugins/vis_types/timeseries/public/convert_to_lens/lib/configurations/xy/layers.ts
# src/plugins/vis_types/timeseries/public/convert_to_lens/top_n/index.ts
This commit is contained in:
parent
e55eebd128
commit
99d6218b88
5 changed files with 122 additions and 46 deletions
|
@ -24,6 +24,33 @@ jest.mock('uuid', () => ({
|
|||
v4: () => 'test-id',
|
||||
}));
|
||||
|
||||
const mockedIndices = [
|
||||
{
|
||||
id: 'test',
|
||||
title: 'test',
|
||||
timeFieldName: 'test_field',
|
||||
getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }),
|
||||
},
|
||||
] as unknown as DataView[];
|
||||
|
||||
const indexPatternsService = {
|
||||
getDefault: jest.fn(() =>
|
||||
Promise.resolve({
|
||||
id: 'default',
|
||||
title: 'index',
|
||||
getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }),
|
||||
})
|
||||
),
|
||||
get: jest.fn((id) => Promise.resolve({ ...mockedIndices[0], id })),
|
||||
find: jest.fn((search: string, size: number) => {
|
||||
if (size !== 1) {
|
||||
// shouldn't request more than one data view since there is a significant performance penalty
|
||||
throw new Error('trying to fetch too many data views');
|
||||
}
|
||||
return Promise.resolve(mockedIndices || []);
|
||||
}),
|
||||
} as unknown as DataViewsPublicPluginStart;
|
||||
|
||||
describe('getLayers', () => {
|
||||
const dataSourceLayers: Record<number, Layer> = [
|
||||
{
|
||||
|
@ -285,10 +312,16 @@ describe('getLayers', () => {
|
|||
series: [createSeries({ metrics: staticValueMetric })],
|
||||
});
|
||||
|
||||
test.each<[string, [Record<number, Layer>, Panel], Array<Partial<XYLayerConfig>>]>([
|
||||
test.each<
|
||||
[
|
||||
string,
|
||||
[Record<number, Layer>, Panel, DataViewsPublicPluginStart, boolean],
|
||||
Array<Partial<XYLayerConfig>>
|
||||
]
|
||||
>([
|
||||
[
|
||||
'data layer if columns do not include static column',
|
||||
[dataSourceLayers, panel],
|
||||
[dataSourceLayers, panel, indexPatternsService, false],
|
||||
[
|
||||
{
|
||||
layerType: 'data',
|
||||
|
@ -307,9 +340,30 @@ describe('getLayers', () => {
|
|||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'data layer with "left" axisMode if isSingleAxis is provided',
|
||||
[dataSourceLayers, panel, indexPatternsService, true],
|
||||
[
|
||||
{
|
||||
layerType: 'data',
|
||||
accessors: ['column-id-1'],
|
||||
xAccessor: 'column-id-2',
|
||||
splitAccessor: 'column-id-3',
|
||||
seriesType: 'area',
|
||||
layerId: 'test-layer-1',
|
||||
yConfig: [
|
||||
{
|
||||
forAccessor: 'column-id-1',
|
||||
axisMode: 'left',
|
||||
color: '#68BC00',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
[
|
||||
'reference line layer if columns include static column',
|
||||
[dataSourceLayersWithStatic, panelWithStaticValue],
|
||||
[dataSourceLayersWithStatic, panelWithStaticValue, indexPatternsService, false],
|
||||
[
|
||||
{
|
||||
layerType: 'referenceLine',
|
||||
|
@ -318,9 +372,10 @@ describe('getLayers', () => {
|
|||
yConfig: [
|
||||
{
|
||||
forAccessor: 'column-id-1',
|
||||
axisMode: 'right',
|
||||
axisMode: 'left',
|
||||
color: '#68BC00',
|
||||
fill: 'below',
|
||||
lineWidth: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -328,7 +383,7 @@ describe('getLayers', () => {
|
|||
],
|
||||
[
|
||||
'correct colors if columns include percentile columns',
|
||||
[dataSourceLayersWithPercentile, panelWithPercentileMetric],
|
||||
[dataSourceLayersWithPercentile, panelWithPercentileMetric, indexPatternsService, false],
|
||||
[
|
||||
{
|
||||
yConfig: [
|
||||
|
@ -348,7 +403,12 @@ describe('getLayers', () => {
|
|||
],
|
||||
[
|
||||
'correct colors if columns include percentile rank columns',
|
||||
[dataSourceLayersWithPercentileRank, panelWithPercentileRankMetric],
|
||||
[
|
||||
dataSourceLayersWithPercentileRank,
|
||||
panelWithPercentileRankMetric,
|
||||
indexPatternsService,
|
||||
false,
|
||||
],
|
||||
[
|
||||
{
|
||||
yConfig: [
|
||||
|
@ -368,7 +428,7 @@ describe('getLayers', () => {
|
|||
],
|
||||
[
|
||||
'annotation layer gets correct params and converts color, extraFields and icons',
|
||||
[dataSourceLayersWithStatic, panelWithSingleAnnotation],
|
||||
[dataSourceLayersWithStatic, panelWithSingleAnnotation, indexPatternsService, false],
|
||||
[
|
||||
{
|
||||
layerType: 'referenceLine',
|
||||
|
@ -377,9 +437,10 @@ describe('getLayers', () => {
|
|||
yConfig: [
|
||||
{
|
||||
forAccessor: 'column-id-1',
|
||||
axisMode: 'right',
|
||||
axisMode: 'left',
|
||||
color: '#68BC00',
|
||||
fill: 'below',
|
||||
lineWidth: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -413,7 +474,7 @@ describe('getLayers', () => {
|
|||
],
|
||||
[
|
||||
'multiple annotations with different data views create separate layers',
|
||||
[dataSourceLayersWithStatic, panelWithMultiAnnotations],
|
||||
[dataSourceLayersWithStatic, panelWithMultiAnnotations, indexPatternsService, false],
|
||||
[
|
||||
{
|
||||
layerType: 'referenceLine',
|
||||
|
@ -422,9 +483,10 @@ describe('getLayers', () => {
|
|||
yConfig: [
|
||||
{
|
||||
forAccessor: 'column-id-1',
|
||||
axisMode: 'right',
|
||||
axisMode: 'left',
|
||||
color: '#68BC00',
|
||||
fill: 'below',
|
||||
lineWidth: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -498,27 +560,7 @@ describe('getLayers', () => {
|
|||
],
|
||||
],
|
||||
])('should return %s', async (_, input, expected) => {
|
||||
const layers = await getLayers(...input, indexPatternsService as DataViewsPublicPluginStart);
|
||||
const layers = await getLayers(...input);
|
||||
expect(layers).toEqual(expected.map(expect.objectContaining));
|
||||
});
|
||||
});
|
||||
|
||||
const mockedIndices = [
|
||||
{
|
||||
id: 'test',
|
||||
title: 'test',
|
||||
getFieldByName: (name: string) => ({ aggregatable: name !== 'host' }),
|
||||
},
|
||||
] as unknown as DataView[];
|
||||
|
||||
const indexPatternsService = {
|
||||
getDefault: jest.fn(() => Promise.resolve({ id: 'default', title: 'index' })),
|
||||
get: jest.fn(() => Promise.resolve(mockedIndices[0])),
|
||||
find: jest.fn((search: string, size: number) => {
|
||||
if (size !== 1) {
|
||||
// shouldn't request more than one data view since there is a significant performance penalty
|
||||
throw new Error('trying to fetch too many data views');
|
||||
}
|
||||
return Promise.resolve(mockedIndices || []);
|
||||
}),
|
||||
} as unknown as DataViewsPublicPluginStart;
|
||||
|
|
|
@ -23,7 +23,7 @@ import { DataViewsPublicPluginStart, DataView } from '@kbn/data-plugin/public/da
|
|||
import { fetchIndexPattern } from '../../../../../common/index_patterns_utils';
|
||||
import { ICON_TYPES_MAP } from '../../../../application/visualizations/constants';
|
||||
import { SUPPORTED_METRICS } from '../../metrics';
|
||||
import type { Annotation, Metric, Panel } from '../../../../../common/types';
|
||||
import type { Annotation, Metric, Panel, Series } from '../../../../../common/types';
|
||||
import { getSeriesAgg } from '../../series';
|
||||
import {
|
||||
isPercentileRanksColumnWithMeta,
|
||||
|
@ -43,6 +43,10 @@ function getPalette(palette: PaletteOutput): PaletteOutput {
|
|||
: palette;
|
||||
}
|
||||
|
||||
function getAxisMode(series: Series, model: Panel): YAxisMode {
|
||||
return (series.separate_axis ? series.axis_position : model.axis_position) as YAxisMode;
|
||||
}
|
||||
|
||||
function getColor(
|
||||
metricColumn: Column,
|
||||
metric: Metric,
|
||||
|
@ -68,7 +72,8 @@ function nonNullable<T>(value: T): value is NonNullable<T> {
|
|||
export const getLayers = async (
|
||||
dataSourceLayers: Record<number, Layer>,
|
||||
model: Panel,
|
||||
dataViews: DataViewsPublicPluginStart
|
||||
dataViews: DataViewsPublicPluginStart,
|
||||
isSingleAxis: boolean = false
|
||||
): Promise<XYLayerConfig[]> => {
|
||||
const nonAnnotationsLayers: XYLayerConfig[] = Object.keys(dataSourceLayers).map((key) => {
|
||||
const series = model.series[parseInt(key, 10)];
|
||||
|
@ -83,13 +88,13 @@ export const getLayers = async (
|
|||
const metricColumns = dataSourceLayer.columns.filter(
|
||||
(l) => !l.isBucketed && l.columnId !== referenceColumnId
|
||||
);
|
||||
const isReferenceLine = metrics.length === 1 && metrics[0].type === 'static';
|
||||
const isReferenceLine =
|
||||
metricColumns.length === 1 && metricColumns[0].operationType === 'static_value';
|
||||
const splitAccessor = dataSourceLayer.columns.find(
|
||||
(column) => column.isBucketed && column.isSplit
|
||||
)?.columnId;
|
||||
const chartType = getChartType(series, model.type);
|
||||
const commonProps = {
|
||||
seriesType: chartType,
|
||||
layerId: dataSourceLayer.layerId,
|
||||
accessors: metricColumns.map((metricColumn) => {
|
||||
return metricColumn.columnId;
|
||||
|
@ -101,19 +106,19 @@ export const getLayers = async (
|
|||
return {
|
||||
forAccessor: metricColumn.columnId,
|
||||
color: getColor(metricColumn, metric!, series.color, splitAccessor),
|
||||
axisMode: (series.separate_axis
|
||||
? series.axis_position
|
||||
: model.axis_position) as YAxisMode,
|
||||
axisMode: isReferenceLine // reference line should be assigned to axis with real data
|
||||
? model.series.some((s) => s.id !== series.id && getAxisMode(s, model) === 'right')
|
||||
? 'right'
|
||||
: 'left'
|
||||
: isSingleAxis
|
||||
? 'left'
|
||||
: getAxisMode(series, model),
|
||||
...(isReferenceLine && {
|
||||
fill: chartType === 'area' ? FillTypes.BELOW : FillTypes.NONE,
|
||||
fill: chartType.includes('area') ? FillTypes.BELOW : FillTypes.NONE,
|
||||
lineWidth: series.line_width,
|
||||
}),
|
||||
};
|
||||
}),
|
||||
xAccessor: dataSourceLayer.columns.find((column) => column.isBucketed && !column.isSplit)
|
||||
?.columnId,
|
||||
splitAccessor,
|
||||
collapseFn: seriesAgg,
|
||||
palette: getPalette(series.palette as PaletteOutput),
|
||||
};
|
||||
if (isReferenceLine) {
|
||||
return {
|
||||
|
@ -122,8 +127,14 @@ export const getLayers = async (
|
|||
};
|
||||
} else {
|
||||
return {
|
||||
seriesType: chartType,
|
||||
layerType: 'data',
|
||||
...commonProps,
|
||||
xAccessor: dataSourceLayer.columns.find((column) => column.isBucketed && !column.isSplit)
|
||||
?.columnId,
|
||||
splitAccessor,
|
||||
collapseFn: seriesAgg,
|
||||
palette: getPalette(series.palette as PaletteOutput),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
|
@ -112,6 +112,19 @@ describe('convertToLens', () => {
|
|||
expect(mockGetBucketsColumns).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should return null for static value with buckets', async () => {
|
||||
mockGetBucketsColumns.mockReturnValue([{}]);
|
||||
mockGetMetricsColumns.mockReturnValue([
|
||||
{
|
||||
operationType: 'static_value',
|
||||
},
|
||||
]);
|
||||
const result = await convertToLens(model);
|
||||
expect(result).toBeNull();
|
||||
expect(mockGetMetricsColumns).toBeCalledTimes(1);
|
||||
expect(mockGetBucketsColumns).toBeCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should return state for valid model', async () => {
|
||||
const result = await convertToLens(model);
|
||||
expect(result).toBeDefined();
|
||||
|
|
|
@ -88,11 +88,21 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model: Panel
|
|||
return null;
|
||||
}
|
||||
|
||||
const isReferenceLine =
|
||||
metricsColumns.length === 1 && metricsColumns[0].operationType === 'static_value';
|
||||
|
||||
// only static value without split is supported
|
||||
if (isReferenceLine && bucketsColumns.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const layerId = uuid();
|
||||
extendedLayers[layerIdx] = {
|
||||
indexPatternId,
|
||||
layerId,
|
||||
columns: [...metricsColumns, dateHistogramColumn, ...bucketsColumns],
|
||||
columns: isReferenceLine
|
||||
? [...metricsColumns]
|
||||
: [...metricsColumns, dateHistogramColumn, ...bucketsColumns],
|
||||
columnOrder: [],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ export const convertToLens: ConvertTsvbToLensVisualization = async (model, timeR
|
|||
};
|
||||
}
|
||||
|
||||
const configLayers = await getLayers(extendedLayers, model, dataViews);
|
||||
const configLayers = await getLayers(extendedLayers, model, dataViews, true);
|
||||
|
||||
return {
|
||||
type: 'lnsXY',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue