From 72a332685ac7cac7dd227ee5c7ced4e16dfb2d8c Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Fri, 14 Jul 2023 18:19:36 -0500 Subject: [PATCH] Heatmap: Use displayName to test if numeric bucket fields (#71407) --- .../prometheus/result_transformer.test.ts | 51 ++++++++++++++++++- .../prometheus/result_transformer.ts | 9 ++-- public/app/plugins/panel/heatmap/fields.ts | 9 ++-- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index 2b4be5767ff..b251c89a1be 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -1,4 +1,5 @@ import { + cacheFieldDisplayNames, createDataFrame, DataFrame, DataQueryRequest, @@ -7,7 +8,7 @@ import { PreferredVisualisationType, } from '@grafana/data'; -import { parseSampleValue, transform, transformDFToTable, transformV2 } from './result_transformer'; +import { parseSampleValue, sortSeriesByLabel, transform, transformDFToTable, transformV2 } from './result_transformer'; import { PromQuery } from './types'; jest.mock('@grafana/runtime', () => ({ @@ -83,6 +84,54 @@ describe('Prometheus Result Transformer', () => { }); }); + describe('sortSeriesByLabel() should use frame.fields[1].state?.displayName when available', () => { + let frames = [ + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [1, 2, 3] }, + { + name: 'Value', + type: FieldType.number, + values: [4, 5, 6], + config: { + displayNameFromDS: '2', + }, + labels: { + offset_days: '2', + }, + }, + ], + }), + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [1, 2, 3] }, + { + name: 'Value', + type: FieldType.number, + values: [7, 8, 9], + config: { + displayNameFromDS: '1', + }, + labels: { + offset_days: '1', + }, + }, + ], + }), + ]; + + it('sorts by displayNameFromDS', () => { + cacheFieldDisplayNames(frames); + + let sorted = frames.slice().sort(sortSeriesByLabel); + + expect(sorted[0]).toEqual(frames[1]); + expect(sorted[1]).toEqual(frames[0]); + }); + }); + describe('transformV2', () => { it('results with time_series format should be enriched with preferredVisualisationType', () => { const request = { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index fefbd37ffe5..cef8a15ae80 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -673,10 +673,13 @@ export function sortSeriesByLabel(s1: DataFrame, s2: DataFrame): number { let le1, le2; try { - // fail if not integer. might happen with bad queries - le1 = parseSampleValue(s1.name ?? s1.fields[1].name); - le2 = parseSampleValue(s2.name ?? s2.fields[1].name); + // the state.displayName conditions are here because we also use this sorting util fn + // in panels where isHeatmapResult was false but we still want to sort numerically-named + // fields after the full unique displayName is cached in field state + le1 = parseSampleValue(s1.fields[1].state?.displayName ?? s1.name ?? s1.fields[1].name); + le2 = parseSampleValue(s2.fields[1].state?.displayName ?? s2.name ?? s2.fields[1].name); } catch (err) { + // fail if not integer. might happen with bad queries console.error(err); return 0; } diff --git a/public/app/plugins/panel/heatmap/fields.ts b/public/app/plugins/panel/heatmap/fields.ts index 87e3593bb83..2da54d1f2b3 100644 --- a/public/app/plugins/panel/heatmap/fields.ts +++ b/public/app/plugins/panel/heatmap/fields.ts @@ -1,4 +1,5 @@ import { + cacheFieldDisplayNames, DataFrame, DataFrameType, Field, @@ -73,6 +74,8 @@ export function prepareHeatmapData( return {}; } + cacheFieldDisplayNames(frames); + const exemplars = annotations?.find((f) => f.name === 'exemplar'); if (getFieldLinks) { @@ -109,7 +112,7 @@ export function prepareHeatmapData( if (!rowsHeatmap) { if (frames.length > 1) { let allNamesNumeric = frames.every( - (frame) => !Number.isNaN(parseSampleValue(frame.name ?? frame.fields[1].name)) + (frame) => !Number.isNaN(parseSampleValue(frame.fields[1].state?.displayName!)) ); if (allNamesNumeric) { @@ -124,10 +127,10 @@ export function prepareHeatmapData( } else { let frame = frames[0]; let numberFields = frame.fields.filter((field) => field.type === FieldType.number); - let allNamesNumeric = numberFields.every((field) => !Number.isNaN(parseSampleValue(field.name))); + let allNamesNumeric = numberFields.every((field) => !Number.isNaN(parseSampleValue(field.state?.displayName!))); if (allNamesNumeric) { - numberFields.sort((a, b) => parseSampleValue(a.name) - parseSampleValue(b.name)); + numberFields.sort((a, b) => parseSampleValue(a.state?.displayName!) - parseSampleValue(b.state?.displayName!)); rowsHeatmap = { ...frame,