Skip to content

Commit 86f8d8c

Browse files
markov00paulinashakirova
authored andcommitted
[Lens as code] Fix waffle chart legend values not roundtripping through the API (elastic#269774)
## Summary fix elastic#268819 The waffle chart is the only partition chart that lets users show/hide metric values in the legend. However, the API transform layer was missing the mapping between the API legend.values field and the internal legendStats state — meaning this setting was silently lost when converting to/from the API format. This adds bidirectional mapping: - `legend.values: ['absolute']` → `legendStats: ['value']` (show values) - `legend.values` omitted → `legendStats: []` (hide values) For existing saved objects where `legendStats` is `undefined` (which renders as "show values" by default), serializing to API now correctly emits `legend.values: ['absolute']`.
1 parent 613f82f commit 86f8d8c

2 files changed

Lines changed: 105 additions & 0 deletions

File tree

src/platform/packages/shared/kbn-lens-embeddable-utils/config_builder/tests/partition/partition.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,77 @@ describe('Partition', () => {
203203
expect(apiOutput.metrics[0].color).toEqual(AUTO_COLOR);
204204
});
205205
});
206+
207+
describe('waffle legend values', () => {
208+
const baseDataSource = {
209+
type: AS_CODE_DATA_VIEW_SPEC_TYPE,
210+
index_pattern: 'test-index',
211+
time_field: '@timestamp',
212+
} as const;
213+
214+
const baseWaffleConfig = {
215+
type: 'waffle',
216+
title: 'Waffle legend test',
217+
data_source: baseDataSource,
218+
metrics: [{ operation: 'count', empty_as_null: false }],
219+
group_by: [
220+
{
221+
operation: 'terms',
222+
fields: ['tags.keyword'],
223+
limit: 3,
224+
},
225+
],
226+
sampling: 1,
227+
ignore_global_filters: false,
228+
} satisfies WaffleConfig;
229+
230+
it('should map legend.values: ["absolute"] to legendStats: ["value"] in state', () => {
231+
const config = {
232+
...baseWaffleConfig,
233+
legend: { values: ['absolute'] as ['absolute'] },
234+
} satisfies WaffleConfig;
235+
236+
const builder = new LensConfigBuilder();
237+
const lensState = builder.fromAPIFormat(config);
238+
const vizState = lensState.state.visualization as LensPartitionVisualizationState;
239+
240+
expect(vizState.layers[0].legendStats).toEqual(['value']);
241+
});
242+
243+
it('should map omitted legend.values to legendStats: [] in state', () => {
244+
const builder = new LensConfigBuilder();
245+
const lensState = builder.fromAPIFormat(baseWaffleConfig);
246+
const vizState = lensState.state.visualization as LensPartitionVisualizationState;
247+
248+
expect(vizState.layers[0].legendStats).toEqual([]);
249+
});
250+
251+
it('should roundtrip legend.values: ["absolute"] correctly', () => {
252+
const config = {
253+
...baseWaffleConfig,
254+
legend: { values: ['absolute'] as ['absolute'] },
255+
} satisfies WaffleConfig;
256+
257+
const builder = new LensConfigBuilder();
258+
const lensState = builder.fromAPIFormat(config);
259+
const apiOutput = builder.toAPIFormat(lensState) as WaffleConfig;
260+
261+
expect(apiOutput.legend?.values).toEqual(['absolute']);
262+
});
263+
264+
it('should roundtrip omitted legend.values correctly', () => {
265+
const builder = new LensConfigBuilder();
266+
const lensState = builder.fromAPIFormat(baseWaffleConfig);
267+
const apiOutput = builder.toAPIFormat(lensState) as WaffleConfig;
268+
269+
expect(apiOutput.legend?.values).toBeUndefined();
270+
});
271+
272+
it('should serialize existing waffle state without legendStats as legend.values: ["absolute"]', () => {
273+
const builder = new LensConfigBuilder(undefined, true);
274+
const apiOutput = builder.toAPIFormat(waffleLegacyBasicState) as WaffleConfig;
275+
276+
expect(apiOutput.legend?.values).toEqual(['absolute']);
277+
});
278+
});
206279
});

src/platform/packages/shared/kbn-lens-embeddable-utils/config_builder/transforms/charts/partition.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,34 @@ function convertAPILegendDisplayOption(
232232
return { legendDisplay: legend?.visibility === 'visible' ? 'show' : 'hide', ...legendOptions };
233233
}
234234

235+
/**
236+
* Waffle is the only partition chart that supports showing/hiding metric values in the legend.
237+
* Internally, Lens uses `legendStats` (empty array = hidden, ['value'] = shown).
238+
* The API schema represents this as `legend.values: ['absolute']` (shown) or omitted (hidden).
239+
*/
240+
function convertWaffleLegendValuesToState(
241+
values: NonNullable<WaffleConfig['legend']>['values']
242+
): LensPartitionLayerState['legendStats'] {
243+
if (values?.includes('absolute')) {
244+
return ['value'];
245+
}
246+
return [];
247+
}
248+
249+
/**
250+
* Converts internal `legendStats` back to the API `legend.values` field for waffle charts.
251+
* When `legendStats` is undefined (legacy saved objects), values are shown by default
252+
* (matching the rendering behavior in `getLegendStats`), so we emit `['absolute']`.
253+
*/
254+
function convertLegendStatsToWaffleAPIValues(
255+
legendStats: LensPartitionLayerState['legendStats']
256+
): NonNullable<WaffleConfig['legend']>['values'] {
257+
if (legendStats === undefined || legendStats.includes('value')) {
258+
return ['absolute'];
259+
}
260+
return undefined;
261+
}
262+
235263
function convertAPIStaticColorToLensState(config: PartitionConfig) {
236264
if (isAPIMosaicChartLayer(config)) {
237265
return undefined;
@@ -381,6 +409,7 @@ function buildVisualizationState(
381409
...sharedState,
382410
...(!isLegacyColor && { ...colorMapping }),
383411
categoryDisplay: 'default',
412+
legendStats: convertWaffleLegendValuesToState(config.legend?.values),
384413
},
385414
],
386415
};
@@ -468,6 +497,9 @@ function fromLensStateToSharedPartitionAPI(
468497
truncate_after_lines: getLegendTruncateAfterLines(layerState),
469498
nested: isStateWaffleChart(visualization) ? undefined : layerState.nestedLegend,
470499
size: legendSizeCompat.toAPI(layerState.legendSize),
500+
values: isStateWaffleChart(visualization)
501+
? convertLegendStatsToWaffleAPIValues(layerState.legendStats)
502+
: undefined,
471503
});
472504

473505
return stripUndefined({

0 commit comments

Comments
 (0)