diff --git a/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts b/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts index f19b6b0ccb7..121a0391818 100644 --- a/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts +++ b/packages/grafana-data/src/transformations/transformers/joinDataFrames.ts @@ -56,6 +56,11 @@ export interface JoinOptions { */ keepOriginIndices?: boolean; + /** + * @internal -- keep any pre-cached state.displayName + */ + keepDisplayNames?: boolean; + /** * @internal -- Optionally specify a join mode (outer or inner) */ @@ -223,8 +228,10 @@ export function joinDataFrames(options: JoinOptions): DataFrame | undefined { for (const field of fields) { a.push(field.values); originalFields.push(field); - // clear field displayName state - delete field.state?.displayName; + if (!options.keepDisplayNames) { + // clear field displayName state + delete field.state?.displayName; + } // store frame field order for tabular data join frameFieldsOrder.push(fieldsOrder); fieldsOrder++; diff --git a/public/app/core/components/GraphNG/utils.ts b/public/app/core/components/GraphNG/utils.ts index 030ea9722db..64cd07e1b6d 100644 --- a/public/app/core/components/GraphNG/utils.ts +++ b/public/app/core/components/GraphNG/utils.ts @@ -110,6 +110,11 @@ export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers joinBy: dimFields.x, keep: dimFields.y, keepOriginIndices: true, + + // the join transformer force-deletes our state.displayName cache unless keepDisplayNames: true + // https://github.com/grafana/grafana/pull/31121 + // https://github.com/grafana/grafana/pull/71806 + keepDisplayNames: true, }); if (alignedFrame) { diff --git a/public/app/core/components/TimelineChart/utils.ts b/public/app/core/components/TimelineChart/utils.ts index 6aab7e2478e..0b71fb59073 100644 --- a/public/app/core/components/TimelineChart/utils.ts +++ b/public/app/core/components/TimelineChart/utils.ts @@ -21,6 +21,7 @@ import { getFieldConfigWithMinMax, ThresholdsMode, TimeRange, + cacheFieldDisplayNames, } from '@grafana/data'; import { maybeSortFrame } from '@grafana/data/src/transformations/transformers/joinDataFrames'; import { applyNullInsertThreshold } from '@grafana/data/src/transformations/transformers/nulls/nullInsertThreshold'; @@ -437,6 +438,9 @@ export function prepareTimelineFields( if (!series?.length) { return { warn: 'No data in response' }; } + + cacheFieldDisplayNames(series); + let hasTimeseries = false; const frames: DataFrame[] = []; diff --git a/public/app/plugins/panel/timeseries/utils.ts b/public/app/plugins/panel/timeseries/utils.ts index 9a235db97d9..73d74ec00c9 100644 --- a/public/app/plugins/panel/timeseries/utils.ts +++ b/public/app/plugins/panel/timeseries/utils.ts @@ -10,6 +10,7 @@ import { isBooleanUnit, SortedVector, TimeRange, + cacheFieldDisplayNames, } from '@grafana/data'; import { convertFieldType } from '@grafana/data/src/transformations/transformers/convertFieldType'; import { applyNullInsertThreshold } from '@grafana/data/src/transformations/transformers/nulls/nullInsertThreshold'; @@ -82,6 +83,8 @@ export function prepareGraphableFields( return null; } + cacheFieldDisplayNames(series); + let useNumericX = xNumFieldIdx != null; // Make sure the numeric x field is first in the frame