diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts index f2840b6d3844b5..dee0e5763dee49 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.test.ts @@ -872,6 +872,59 @@ describe('xy_visualization', () => { }, ]); }); + + it('should return an error if string and date histogram xAccessors (multiple layers) are used together', () => { + // current incompatibility is only for date and numeric histograms as xAccessors + const datasourceLayers = { + first: mockDatasource.publicAPIMock, + second: createMockDatasource('testDatasource').publicAPIMock, + }; + datasourceLayers.first.getOperationForColumnId = jest.fn((id: string) => + id === 'a' + ? (({ + dataType: 'date', + scale: 'interval', + } as unknown) as Operation) + : null + ); + datasourceLayers.second.getOperationForColumnId = jest.fn((id: string) => + id === 'e' + ? (({ + dataType: 'string', + scale: 'ordinal', + } as unknown) as Operation) + : null + ); + expect( + xyVisualization.getErrorMessages( + { + ...exampleState(), + layers: [ + { + layerId: 'first', + seriesType: 'area', + splitAccessor: 'd', + xAccessor: 'a', + accessors: ['b'], + }, + { + layerId: 'second', + seriesType: 'area', + splitAccessor: 'd', + xAccessor: 'e', + accessors: ['b'], + }, + ], + }, + datasourceLayers + ) + ).toEqual([ + { + shortMessage: 'Wrong data type for Horizontal axis.', + longMessage: 'Data type mismatch for the Horizontal axis, use a different function.', + }, + ]); + }); }); describe('#getWarningMessages', () => { diff --git a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx index ad2c9fd7139853..bd20ed300bf618 100644 --- a/x-pack/plugins/lens/public/xy_visualization/visualization.tsx +++ b/x-pack/plugins/lens/public/xy_visualization/visualization.tsx @@ -542,8 +542,15 @@ function checkXAccessorCompatibility( datasourceLayers: Record ) { const errors = []; - const hasDateHistogramSet = state.layers.some(checkIntervalOperation('date', datasourceLayers)); - const hasNumberHistogram = state.layers.some(checkIntervalOperation('number', datasourceLayers)); + const hasDateHistogramSet = state.layers.some( + checkScaleOperation('interval', 'date', datasourceLayers) + ); + const hasNumberHistogram = state.layers.some( + checkScaleOperation('interval', 'number', datasourceLayers) + ); + const hasOrdinalAxis = state.layers.some( + checkScaleOperation('ordinal', undefined, datasourceLayers) + ); if (state.layers.length > 1 && hasDateHistogramSet && hasNumberHistogram) { errors.push({ shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { @@ -560,11 +567,28 @@ function checkXAccessorCompatibility( }), }); } + if (state.layers.length > 1 && (hasDateHistogramSet || hasNumberHistogram) && hasOrdinalAxis) { + errors.push({ + shortMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXShort', { + defaultMessage: `Wrong data type for {axis}.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + longMessage: i18n.translate('xpack.lens.xyVisualization.dataTypeFailureXOrdinalLong', { + defaultMessage: `Data type mismatch for the {axis}, use a different function.`, + values: { + axis: getAxisName('x', { isHorizontal: isHorizontalChart(state.layers) }), + }, + }), + }); + } return errors; } -function checkIntervalOperation( - dataType: 'date' | 'number', +function checkScaleOperation( + scaleType: 'ordinal' | 'interval' | 'ratio', + dataType: 'date' | 'number' | 'string' | undefined, datasourceLayers: Record ) { return (layer: XYLayerConfig) => { @@ -573,6 +597,8 @@ function checkIntervalOperation( return false; } const operation = datasourceAPI?.getOperationForColumnId(layer.xAccessor); - return Boolean(operation?.dataType === dataType && operation.scale === 'interval'); + return Boolean( + operation && (!dataType || operation.dataType === dataType) && operation.scale === scaleType + ); }; }