diff --git a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.test.ts b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.test.ts index 2580b277be1..c8270a61134 100644 --- a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.test.ts +++ b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.test.ts @@ -216,6 +216,22 @@ describe('timeSeriesTableTransformer', () => { expect(results[0].fields[0].values[0].fields[0].values[0]).toBe(10); expect(results[0].fields[0].values[0].fields[1].values[0]).toBe(2); }); + + it('Will correctly fill in gaps in labels', () => { + const series = [ + getTimeSeries('A', { instance: 'A', pod: 'AA' }), + getTimeSeries('A', { instance: 'B' }), + getTimeSeries('A', { instance: 'C', pod: 'CC' }), + ]; + + const results = timeSeriesToTableTransform({}, series); + expect(results).toHaveLength(1); + const result = results[0]; + expect(result.refId).toBe('A'); + expect(result.fields).toHaveLength(3); + expect(result.fields[0].values).toEqual(['A', 'B', 'C']); + expect(result.fields[1].values).toEqual(['AA', '', 'CC']); + }); }); function assertFieldsEqual(field1: Field, field2: Field) { diff --git a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts index 399e1a76c1f..dfc82b6c819 100644 --- a/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts +++ b/public/app/features/transformers/timeSeriesTable/timeSeriesTableTransformer.ts @@ -143,6 +143,30 @@ export function timeSeriesToTableTransform(options: TimeSeriesTableTransformerOp // Intialize object for this refId refId2trends[refId] = {}; + // Initialize labels object for this refId + refId2labelz[refId] = {}; + + // Collect all existing label names across frames + // so we can fill in nulls for frames that don't + // have a particular label + const labelNames: string[] = []; + + framesForRef.forEach((frame) => { + frame.fields.forEach((field) => { + if (field.type !== FieldType.number) { + return; + } + if (field.labels) { + Object.keys(field.labels).forEach((labelName) => { + if (!labelNames.includes(labelName)) { + refId2labelz[refId][labelName] = newField(labelName, FieldType.string); + labelNames.push(labelName); + } + }); + } + }); + }); + for (let i = 0; i < framesForRef.length; i++) { const frame = framesForRef[i]; @@ -196,19 +220,9 @@ export function timeSeriesToTableTransform(options: TimeSeriesTableTransformerOp // If there are labels add them to the appropriate fields // Because we iterate each frame - if (field.labels !== undefined) { - for (const [labelKey, labelValue] of Object.entries(field.labels)) { - if (refId2labelz[refId] === undefined) { - refId2labelz[refId] = {}; - } - - if (refId2labelz[refId][labelKey] === undefined) { - refId2labelz[refId][labelKey] = newField(labelKey, FieldType.string); - } - - refId2labelz[refId][labelKey].values.push(labelValue); - } - } + labelNames.forEach((labelName) => { + refId2labelz[refId][labelName].values.push(field.labels?.[labelName] ?? ''); + }); } } }