From 705646c8f907c140be8d2ad63518c6a6831523f2 Mon Sep 17 00:00:00 2001 From: Kristina Durivage Date: Wed, 24 Sep 2025 16:29:42 -0500 Subject: [PATCH] Handle old dashboards with transformation filters --- packages/grafana-data/src/index.ts | 3 ++- .../src/transformations/transformers/ids.ts | 8 ++++++++ .../transformations/transformers/joinByField.ts | 4 ++-- .../src/transformations/transformers/merge.ts | 3 ++- .../src/transformations/transformers/reduce.ts | 3 ++- .../transformers/seriesToRows.ts | 3 ++- .../src/transformations/transformers/utils.ts | 6 ++++++ .../PanelDataTransformationsTab.tsx | 17 +++++++++++++++-- .../transformers/joinByLabels/joinByLabels.ts | 11 +++++++++-- 9 files changed, 48 insertions(+), 10 deletions(-) diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index 269dba30b62..a010e60bab4 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -268,6 +268,7 @@ export { fuzzySearch } from './utils/fuzzySearch'; // Transformations export { standardTransformers } from './transformations/transformers'; +export { getTransformationLegacyRefId } from './transformations/transformers/utils'; export { fieldMatchers, frameMatchers, @@ -277,7 +278,7 @@ export { getValueMatcher, } from './transformations/matchers'; export { type FieldValueMatcherConfig } from './transformations/matchers/fieldValueMatcher'; -export { DataTransformerID } from './transformations/transformers/ids'; +export { DataTransformerID, refIDDependentIDs } from './transformations/transformers/ids'; export { MatcherID, FieldMatcherID, FrameMatcherID, ValueMatcherID } from './transformations/matchers/ids'; export { ReducerID, diff --git a/packages/grafana-data/src/transformations/transformers/ids.ts b/packages/grafana-data/src/transformations/transformers/ids.ts index cc2b76fae69..9088cb5cbdf 100644 --- a/packages/grafana-data/src/transformations/transformers/ids.ts +++ b/packages/grafana-data/src/transformations/transformers/ids.ts @@ -44,3 +44,11 @@ export enum DataTransformerID { regression = 'regression', groupToNestedTable = 'groupToNestedTable', } + +export const refIDDependentIDs = [ + DataTransformerID.joinByField, + DataTransformerID.merge, + DataTransformerID.reduce, + DataTransformerID.seriesToRows, + DataTransformerID.joinByLabels, +]; diff --git a/packages/grafana-data/src/transformations/transformers/joinByField.ts b/packages/grafana-data/src/transformations/transformers/joinByField.ts index 734c113b8fa..9670cfe3a80 100644 --- a/packages/grafana-data/src/transformations/transformers/joinByField.ts +++ b/packages/grafana-data/src/transformations/transformers/joinByField.ts @@ -7,6 +7,7 @@ import { FieldMatcherID } from '../matchers/ids'; import { DataTransformerID } from './ids'; import { joinDataFrames } from './joinDataFrames'; +import { getTransformationLegacyRefId } from './utils'; export enum JoinMode { outer = 'outer', // best for time series, non duplicated join on values @@ -43,8 +44,7 @@ export const joinByFieldTransformer: SynchronousDataTransformerInfo frame.refId).join('-')}`; + joined.refId = options.refId ?? getTransformationLegacyRefId(DataTransformerID.joinByField, data); return [joined]; } } diff --git a/packages/grafana-data/src/transformations/transformers/merge.ts b/packages/grafana-data/src/transformations/transformers/merge.ts index 0089d41fa96..982da5e5835 100644 --- a/packages/grafana-data/src/transformations/transformers/merge.ts +++ b/packages/grafana-data/src/transformations/transformers/merge.ts @@ -6,6 +6,7 @@ import { DataFrame, Field } from '../../types/dataFrame'; import { DataTransformerInfo, TransformationApplicabilityLevels } from '../../types/transformations'; import { DataTransformerID } from './ids'; +import { getTransformationLegacyRefId } from './utils'; interface ValuePointer { key: string; @@ -46,7 +47,7 @@ export const mergeTransformer: DataTransformerInfo = { const fieldIndexByName: Record> = {}; const fieldNamesForKey: string[] = []; const dataFrame = new MutableDataFrame({ - refId: options.refId ?? `${DataTransformerID.merge}-${data.map((frame) => frame.refId).join('-')}`, + refId: options.refId ?? getTransformationLegacyRefId(DataTransformerID.merge, data), fields: [], }); diff --git a/packages/grafana-data/src/transformations/transformers/reduce.ts b/packages/grafana-data/src/transformations/transformers/reduce.ts index eb73e19f5f5..706d6799c54 100644 --- a/packages/grafana-data/src/transformations/transformers/reduce.ts +++ b/packages/grafana-data/src/transformations/transformers/reduce.ts @@ -10,6 +10,7 @@ import { getFieldMatcher } from '../matchers'; import { alwaysFieldMatcher, notTimeFieldMatcher } from '../matchers/predicates'; import { DataTransformerID } from './ids'; +import { getTransformationLegacyRefId } from './utils'; export enum ReduceTransformerMode { SeriesToRows = 'seriesToRows', // default @@ -61,7 +62,7 @@ export const reduceTransformer: DataTransformerInfo = ? [ { ...res, - refId: options.refId ?? `${DataTransformerID.reduce}-${data.map((frame) => frame.refId).join('-')}`, + refId: options.refId ?? getTransformationLegacyRefId(DataTransformerID.reduce, data), }, ] : []; diff --git a/packages/grafana-data/src/transformations/transformers/seriesToRows.ts b/packages/grafana-data/src/transformations/transformers/seriesToRows.ts index 2fb675511f0..c737006c592 100644 --- a/packages/grafana-data/src/transformations/transformers/seriesToRows.ts +++ b/packages/grafana-data/src/transformations/transformers/seriesToRows.ts @@ -15,6 +15,7 @@ import { import { DataTransformerInfo } from '../../types/transformations'; import { DataTransformerID } from './ids'; +import { getTransformationLegacyRefId } from './utils'; export interface SeriesToRowsTransformerOptions { refId?: string; @@ -40,7 +41,7 @@ export const seriesToRowsTransformer: DataTransformerInfo = {}; const targetFields = new Set(); const dataFrame = new MutableDataFrame({ - refId: options.refId ?? `${DataTransformerID.seriesToRows}-${data.map((frame) => frame.refId).join('-')}`, + refId: options.refId ?? getTransformationLegacyRefId(DataTransformerID.seriesToRows, data), fields: [], }); const metricField: Field = { diff --git a/packages/grafana-data/src/transformations/transformers/utils.ts b/packages/grafana-data/src/transformations/transformers/utils.ts index 9aa4d96a9e8..740d43f1ef2 100644 --- a/packages/grafana-data/src/transformations/transformers/utils.ts +++ b/packages/grafana-data/src/transformations/transformers/utils.ts @@ -1,6 +1,8 @@ import { DataFrame } from '../../types/dataFrame'; import { SpecialValue } from '../../types/transformations'; +import { DataTransformerID } from './ids'; + /** * Retrieve the maximum number of fields in a series of a dataframe. */ @@ -33,3 +35,7 @@ export function getSpecialValue(specialValue: SpecialValue) { return ''; } } + +export const getTransformationLegacyRefId = (transformationId: DataTransformerID, data: DataFrame[]) => { + return `${transformationId}-${data.map((frame) => frame.refId).join('-')}`; +}; diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx index 46ffcfe4741..54772f16943 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataTransformationsTab.tsx @@ -2,7 +2,15 @@ import { css } from '@emotion/css'; import { DragDropContext, DropResult, Droppable } from '@hello-pangea/dnd'; import { useState } from 'react'; -import { DataTransformerConfig, getNextRefId, GrafanaTheme2, PanelData } from '@grafana/data'; +import { + DataTransformerConfig, + DataTransformerID, + getTransformationLegacyRefId, + getNextRefId, + GrafanaTheme2, + PanelData, + refIDDependentIDs, +} from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { Trans, t } from '@grafana/i18n'; import { @@ -179,7 +187,12 @@ function TransformationsEditor({ transformations, model, data }: TransformationE // populate refIds for any transformations that don't have them const refLessTransformations = transformations.filter((transformation) => transformation.refId === undefined); refLessTransformations.forEach((transformation) => { - transformation.refId = getNextRefId(transformations, 'T-'); + const transformationId: DataTransformerID = transformation.id as DataTransformerID; + if (refIDDependentIDs.includes(transformationId)) { + transformation.refId = getTransformationLegacyRefId(transformationId, data.series); + } else { + transformation.refId = getNextRefId(transformations, 'T-'); + } }); return ( diff --git a/public/app/features/transformers/joinByLabels/joinByLabels.ts b/public/app/features/transformers/joinByLabels/joinByLabels.ts index 338dc039d90..60f8cae378c 100644 --- a/public/app/features/transformers/joinByLabels/joinByLabels.ts +++ b/public/app/features/transformers/joinByLabels/joinByLabels.ts @@ -1,6 +1,13 @@ import { map } from 'rxjs/operators'; -import { DataFrame, DataTransformerID, Field, FieldType, SynchronousDataTransformerInfo } from '@grafana/data'; +import { + DataFrame, + DataTransformerID, + Field, + FieldType, + getTransformationLegacyRefId, + SynchronousDataTransformerInfo, +} from '@grafana/data'; import { t } from '@grafana/i18n'; import { getDistinctLabels } from '../utils'; @@ -112,7 +119,7 @@ export function joinByLabels(options: JoinByLabelsTransformOptions, data: DataFr const frame: DataFrame = { fields: [], length: nameValues[0].length, - refId: options.refId ?? `${DataTransformerID.joinByLabels}-${data.map((frame) => frame.refId).join('-')}`, + refId: options.refId ?? getTransformationLegacyRefId(DataTransformerID.joinByLabels, data), }; for (let i = 0; i < join.length; i++) { frame.fields.push({