From c09f0db57072dfb3e0b453f67b64d6e7d5c76f23 Mon Sep 17 00:00:00 2001 From: dualfroz Date: Sun, 18 Oct 2026 07:17:46 +0200 Subject: [PATCH] Transformations: Match only the field spelled time when Time is configured When the configured name is Time and the frame has a field named time (or the other way round), the fallback still matched every time field. Now it only matches the field with the other spelling, and keeps matching any time field when no field goes by either name. --- .../matchers/nameMatcher.test.ts | 8 +++++++ .../transformations/matchers/nameMatcher.ts | 22 +++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts index 95b4daa..6ef80f5 100644 --- a/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.test.ts @@ -484,6 +484,14 @@ it('Should only match the field named time when the frame has more time fields', expect(namesMatcher(frame.fields[0], frame, [frame])).toBeTruthy(); expect(namesMatcher(frame.fields[1], frame, [frame])).toBeFalsy(); expect(namesMatcher(frame.fields[2], frame, [frame])).toBeTruthy(); + + const aliasMatcher = getFieldMatcher({ + id: FieldMatcherID.byName, + options: 'Time', + }); + expect(aliasMatcher(frame.fields[0], frame, [frame])).toBeTruthy(); + expect(aliasMatcher(frame.fields[1], frame, [frame])).toBeFalsy(); + expect(aliasMatcher(frame.fields[2], frame, [frame])).toBeFalsy(); }); describe('Fields returned by query with refId', () => { diff --git a/packages/grafana-data/src/transformations/matchers/nameMatcher.ts b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts index 03f1739..46a656c 100644 --- a/packages/grafana-data/src/transformations/matchers/nameMatcher.ts +++ b/packages/grafana-data/src/transformations/matchers/nameMatcher.ts @@ -115,16 +115,20 @@ function fieldNameFallback(fields: Set) { ); }; } else if (fields.has('Time') || fields.has('time')) { - const timeNames = ['Time', 'time'].filter((name) => fields.has(name)); + const timeNames = ['Time', 'time']; + const configuredNames = timeNames.filter((name) => fields.has(name)); fallback = (field: Field, frame: DataFrame, allFrames: DataFrame[]) => { - return ( - frame.meta?.typeVersion == null && - field.type === FieldType.time && - // A field that already carries the name is matched directly, so other time fields must not be pulled in - !frame.fields.some( - (f) => timeNames.includes(f.name) || timeNames.includes(getFieldDisplayName(f, frame, allFrames)) - ) - ); + if (frame.meta?.typeVersion != null || field.type !== FieldType.time) { + return false; + } + const hasName = (f: Field, names: string[]) => + names.includes(f.name) || names.includes(getFieldDisplayName(f, frame, allFrames)); + // A field that already carries the configured name is matched directly, so other time fields must not be pulled in + if (frame.fields.some((f) => hasName(f, configuredNames))) { + return false; + } + // Time and time stand in for each other, so only a field with the other spelling is matched when there is one + return frame.fields.some((f) => hasName(f, timeNames)) ? hasName(field, timeNames) : true; }; }