Skip to content

Commit

Permalink
[Lens][Agg based XY] Convert to Lens Agg based XY. (#142936)
Browse files Browse the repository at this point in the history
* Add conversion config for agg based XY

* Fixed line stacked charts and buckets for layers

* fixed bundle size

* Fixed tests

* Fixed tests, decreased bundle size

* Add possibility to return several layers from getColumnsFromVis

* Some refactoring

* updated limits

* Updated limits

* Added tests for configuration

* updated bundle size limit

* Added tests for getCustomBucketColumns

* Added some functional tests

* Fix gauge/goal configurations

* Fixed nits

* Fixed parent pipeline aggregation, multi split series and respect Show values option

* Added support of current time marker, use one layer for metrics with the same chart type and mode

* Added support of assign color

* Fix terms with order by column

* Fixed sibling pipeline aggs

* Fixed test

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Stratoula Kalafateli <efstratia.kalafateli@elastic.co>
  • Loading branch information
3 people authored Oct 14, 2022
1 parent 7ba6093 commit 3cb5fed
Show file tree
Hide file tree
Showing 51 changed files with 1,736 additions and 325 deletions.
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,6 @@ pageLoadAssetSize:
visTypeTimeseries: 55203
visTypeVega: 153573
visTypeVislib: 242838
visTypeXy: 30000
visTypeXy: 31800
visualizations: 90000
watcher: 43598
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe('layeredXyVis', () => {
args: { ...rest, layers: [sampleExtendedLayer] },
syncColors: false,
syncTooltips: false,
canNavigateToLens: false,
},
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export const layeredXyVisFn: LayeredXyVisFn['fn'] = async (data, args, handlers)
(handlers.variables?.embeddableTitle as string) ??
handlers.getExecutionContext?.()?.description,
},
canNavigateToLens: Boolean(handlers.variables.canNavigateToLens),
syncColors: handlers?.isSyncColorsEnabled?.() ?? false,
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ describe('xyVis', () => {
},
],
},
canNavigateToLens: false,
syncColors: false,
syncTooltips: false,
},
Expand Down Expand Up @@ -346,6 +347,7 @@ describe('xyVis', () => {
},
],
},
canNavigateToLens: false,
syncColors: false,
syncTooltips: false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const xyVisFn: XyVisFn['fn'] = async (data, args, handlers) => {
(handlers.variables?.embeddableTitle as string) ??
handlers.getExecutionContext?.()?.description,
},
canNavigateToLens: Boolean(handlers.variables.canNavigateToLens),
syncColors: handlers?.isSyncColorsEnabled?.() ?? false,
syncTooltips: handlers?.isSyncTooltipsEnabled?.() ?? false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface XYChartProps {
args: XYProps;
syncTooltips: boolean;
syncColors: boolean;
canNavigateToLens?: boolean;
}

export interface XYRender {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ declare global {
}
}

export type XYChartRenderProps = XYChartProps & {
export type XYChartRenderProps = Omit<XYChartProps, 'canNavigateToLens'> & {
chartsThemeService: ChartsPluginSetup['theme'];
chartsActiveCursorService: ChartsPluginStart['activeCursor'];
data: DataPublicPluginStart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ interface XyChartRendererDeps {
const extractCounterEvents = (
originatingApp: string,
{ layers, yAxisConfigs }: XYChartProps['args'],
canNavigateToLens: boolean,
services: {
getDataLayers: typeof getDataLayers;
}
Expand Down Expand Up @@ -149,6 +150,7 @@ const extractCounterEvents = (
(aggregateLayers.length === 1 && dataLayer.splitAccessors?.length)
? 'aggregate_bucket'
: undefined,
canNavigateToLens ? `render_${byTypes.mixedXY ? 'mixed_xy' : type}_convertable` : undefined,
]
.filter(Boolean)
.map((item) => `render_${originatingApp}_${item}`);
Expand Down Expand Up @@ -188,9 +190,14 @@ export const getXyChartRenderer = ({
const visualizationType = extractVisualizationType(executionContext);

if (deps.usageCollection && containerType && visualizationType) {
const uiEvents = extractCounterEvents(visualizationType, config.args, {
getDataLayers,
});
const uiEvents = extractCounterEvents(
visualizationType,
config.args,
Boolean(config.canNavigateToLens),
{
getDataLayers,
}
);

if (uiEvents) {
deps.usageCollection.reportUiCounter(containerType, METRIC_TYPE.COUNT, uiEvents);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ describe('getConfiguration', () => {
const metricAccessor = 'metric-id';
const breakdownByAccessor = 'bucket-id';
const metrics = [metricAccessor];
const buckets = [breakdownByAccessor];
const buckets = { all: [breakdownByAccessor], customBuckets: {} };
const maxAccessor = 'max-accessor-id';
const collapseFn = 'sum';
expect(
Expand All @@ -69,7 +69,7 @@ describe('getConfiguration', () => {
buckets,
maxAccessor,
columnsWithoutReferenced: [],
bucketCollapseFn: { [metricAccessor]: collapseFn },
bucketCollapseFn: { [collapseFn]: [breakdownByAccessor] },
})
).toEqual({
breakdownByAccessor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,30 @@ export const getConfiguration = (
bucketCollapseFn,
}: {
metrics: string[];
buckets: string[];
buckets: {
all: string[];
customBuckets: Record<string, string>;
};
maxAccessor: string;
columnsWithoutReferenced: Column[];
bucketCollapseFn?: Record<string, string | undefined>;
bucketCollapseFn?: Record<string, string[]>;
}
): MetricVisConfiguration => {
const [metricAccessor] = metrics;
const [breakdownByAccessor] = buckets;
const [breakdownByAccessor] = buckets.all;
const collapseFn = bucketCollapseFn
? Object.keys(bucketCollapseFn).find((key) =>
bucketCollapseFn[key].includes(breakdownByAccessor)
)
: undefined;
return {
layerId,
layerType: 'data',
palette,
metricAccessor,
breakdownByAccessor,
maxAccessor,
collapseFn: Object.values(bucketCollapseFn ?? {})[0],
collapseFn,
subtitle: gauge.labels.show && gauge.style.subText ? gauge.style.subText : undefined,
};
};
44 changes: 25 additions & 19 deletions src/plugins/vis_types/gauge/public/convert_to_lens/gauge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,22 +104,26 @@ describe('convertToLens', () => {
});

test('should return null if metrics count is more than 1', async () => {
mockGetColumnsFromVis.mockReturnValue({
metrics: ['1', '2'],
buckets: [],
columns: [{ columnId: '2' }, { columnId: '1' }],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1', '2'],
buckets: { all: [] },
columns: [{ columnId: '2' }, { columnId: '1' }],
},
]);
const result = await convertToLens(vis, timefilter);
expect(mockGetColumnsFromVis).toBeCalledTimes(1);
expect(result).toBeNull();
});

test('should return null if metric column data type is different from number', async () => {
mockGetColumnsFromVis.mockReturnValue({
metrics: ['1'],
buckets: [],
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'string' }],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1'],
buckets: { all: [] },
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'string' }],
},
]);
const result = await convertToLens(vis, timefilter);
expect(mockGetColumnsFromVis).toBeCalledTimes(1);
expect(result).toBeNull();
Expand All @@ -129,15 +133,17 @@ describe('convertToLens', () => {
layerType: 'data',
};

mockGetColumnsFromVis.mockReturnValue({
metrics: ['1'],
buckets: [],
columns: [{ columnId: '1', dataType: 'number' }],
columnsWithoutReferenced: [
{ columnId: '1', meta: { aggId: 'agg-1' } },
{ columnId: '2', meta: { aggId: 'agg-2' } },
],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1'],
buckets: { all: [] },
columns: [{ columnId: '1', dataType: 'number' }],
columnsWithoutReferenced: [
{ columnId: '1', meta: { aggId: 'agg-1' } },
{ columnId: '2', meta: { aggId: 'agg-2' } },
],
},
]);
mockGetConfiguration.mockReturnValue(config);

const result = await convertToLens(vis, timefilter);
Expand Down
16 changes: 9 additions & 7 deletions src/plugins/vis_types/gauge/public/convert_to_lens/gauge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const convertToLens: ConvertGaugeVisToLensVisualization = async (vis, tim

const percentageModeConfig = getPercentageModeConfig(vis.params.gauge, false);

const result = getColumnsFromVis(
const layers = getColumnsFromVis(
vis,
timefilter,
dataView,
Expand All @@ -63,17 +63,19 @@ export const convertToLens: ConvertGaugeVisToLensVisualization = async (vis, tim
{ dropEmptyRowsInDateHistogram: true, ...percentageModeConfig }
);

if (result === null) {
if (layers === null) {
return null;
}

const [layerConfig] = layers;

// for now, multiple metrics are not supported
if (result.metrics.length > 1 || result.buckets.length) {
if (layerConfig.metrics.length > 1 || layerConfig.buckets.all.length) {
return null;
}

if (result.metrics[0]) {
const metric = result.columns.find(({ columnId }) => columnId === result.metrics[0]);
if (layerConfig.metrics[0]) {
const metric = layerConfig.columns.find(({ columnId }) => columnId === layerConfig.metrics[0]);
if (metric?.dataType !== 'number') {
return null;
}
Expand All @@ -82,11 +84,11 @@ export const convertToLens: ConvertGaugeVisToLensVisualization = async (vis, tim
const layerId = uuid();
const indexPatternId = dataView.id!;

const metricAccessor = result.metrics[0];
const metricAccessor = layerConfig.metrics[0];
const { min, max, isPercentageMode } = percentageModeConfig as PercentageModeConfigWithMinMax;
const minColumn = createStaticValueColumn(isPercentageMode ? 0 : min);
const maxColumn = createStaticValueColumn(isPercentageMode ? 1 : max);
const columns = [...result.columns, minColumn, maxColumn];
const columns = [...layerConfig.columns, minColumn, maxColumn];

return {
type: 'lnsGauge',
Expand Down
54 changes: 31 additions & 23 deletions src/plugins/vis_types/gauge/public/convert_to_lens/goal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,31 +104,37 @@ describe('convertToLens', () => {
});

test('should return null if metrics count is more than 1', async () => {
mockGetColumnsFromVis.mockReturnValue({
metrics: ['1', '2'],
columns: [{ columnId: '2' }, { columnId: '1' }],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1', '2'],
columns: [{ columnId: '2' }, { columnId: '1' }],
},
]);
const result = await convertToLens(vis, timefilter);
expect(mockGetColumnsFromVis).toBeCalledTimes(1);
expect(result).toBeNull();
});
test('should return null if buckets count is more than 1', async () => {
mockGetColumnsFromVis.mockReturnValue({
metrics: [],
buckets: ['1', '2'],
columns: [{ columnId: '2' }, { columnId: '1' }],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: [],
buckets: { all: ['1', '2'] },
columns: [{ columnId: '2' }, { columnId: '1' }],
},
]);
const result = await convertToLens(vis, timefilter);
expect(mockGetColumnsFromVis).toBeCalledTimes(1);
expect(result).toBeNull();
});

test('should return null if metric column data type is different from number', async () => {
mockGetColumnsFromVis.mockReturnValue({
metrics: ['1'],
buckets: ['2'],
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'string' }],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1'],
buckets: { all: ['2'] },
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'string' }],
},
]);
const result = await convertToLens(vis, timefilter);
expect(mockGetColumnsFromVis).toBeCalledTimes(1);
expect(result).toBeNull();
Expand All @@ -139,15 +145,17 @@ describe('convertToLens', () => {
metricAccessor: '1',
};

mockGetColumnsFromVis.mockReturnValue({
metrics: ['1'],
buckets: ['2'],
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'number' }],
columnsWithoutReferenced: [
{ columnId: '1', meta: { aggId: 'agg-1' } },
{ columnId: '2', meta: { aggId: 'agg-2' } },
],
});
mockGetColumnsFromVis.mockReturnValue([
{
metrics: ['1'],
buckets: { all: ['2'] },
columns: [{ columnId: '2' }, { columnId: '1', dataType: 'number' }],
columnsWithoutReferenced: [
{ columnId: '1', meta: { aggId: 'agg-1' } },
{ columnId: '2', meta: { aggId: 'agg-2' } },
],
},
]);
mockGetConfiguration.mockReturnValue(config);

const result = await convertToLens(vis, timefilter);
Expand Down
16 changes: 9 additions & 7 deletions src/plugins/vis_types/gauge/public/convert_to_lens/goal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const convertToLens: ConvertGoalVisToLensVisualization = async (vis, time

const percentageModeConfig = getPercentageModeConfig(vis.params.gauge, false);

const result = getColumnsFromVis(
const layers = getColumnsFromVis(
vis,
timefilter,
dataView,
Expand All @@ -63,25 +63,27 @@ export const convertToLens: ConvertGoalVisToLensVisualization = async (vis, time
{ dropEmptyRowsInDateHistogram: true, ...percentageModeConfig }
);

if (result === null) {
if (layers === null) {
return null;
}

const [layerConfig] = layers;

// for now, multiple metrics are not supported
if (result.metrics.length > 1 || result.buckets.length > 1) {
if (layerConfig.metrics.length > 1 || layerConfig.buckets.all.length > 1) {
return null;
}

if (result.metrics[0]) {
const metric = result.columns.find(({ columnId }) => columnId === result.metrics[0]);
if (layerConfig.metrics[0]) {
const metric = layerConfig.columns.find(({ columnId }) => columnId === layerConfig.metrics[0]);
if (metric?.dataType !== 'number') {
return null;
}
}
const { isPercentageMode, max } = percentageModeConfig as PercentageModeConfigWithMinMax;
const maxColumn = createStaticValueColumn(isPercentageMode ? 1 : max);

const columns = [...result.columns, maxColumn];
const columns = [...layerConfig.columns, maxColumn];
const layerId = uuid();
const indexPatternId = dataView.id!;

Expand All @@ -100,7 +102,7 @@ export const convertToLens: ConvertGoalVisToLensVisualization = async (vis, time
vis.params,
getPalette(vis.params.gauge, percentageModeConfig, true),
{
...result,
...layerConfig,
maxAccessor: maxColumn.columnId,
}
),
Expand Down
Loading

0 comments on commit 3cb5fed

Please sign in to comment.