From 05bde8509a4b3c9ded05b1cb47550ea3d2fdaf8f Mon Sep 17 00:00:00 2001 From: rmawatson <=> Date: Wed, 23 Jul 2025 02:30:17 +0000 Subject: [PATCH] Added ability to paste the value of other fields using {field} syntax --- .betterer.results | 4 ++-- .../transform-data/index.md | 2 +- .../transformers/formatString.ts | 24 ++++++++++++++----- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/.betterer.results b/.betterer.results index f4cd2232eef..7f4870cd73c 100644 --- a/.betterer.results +++ b/.betterer.results @@ -3810,10 +3810,10 @@ exports[`better eslint`] = { "public/app/plugins/panel/geomap/layers/basemaps/esri.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], - "public/app/plugins/panel/geomap/layers/data/geojsonDynamic.ts:5381": [ + "public/app/plugins/panel/geomap/layersgeojsonDynamic.ts:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], - "public/app/plugins/panel/geomap/layers/data/routeLayer.tsx:5381": [ + "public/app/plugins/panel/geomap/layersrouteLayer.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] ], "public/app/plugins/panel/geomap/layers/registry.ts:5381": [ diff --git a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md index 48beaa8e77f..f5c591f43c6 100644 --- a/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md +++ b/docs/sources/panels-visualizations/query-transform-data/transform-data/index.md @@ -578,7 +578,7 @@ Use this transformation to customize the output of a string field. This transfor - **Kebab case** - Formats all characters in the string in lowercase and uses dashes instead of spaces between words. - **Trim** - Removes all leading and trailing spaces from the string. - **Substring** - Returns a substring of the string, using the specified start and end positions. -- **Affix** - Add a prefix or suffix string to the string. +- **Affix** - Add a prefix or suffix string to the string. Allows pasting the value of other fields when provided {field} as the affix expression. This transformation provides a convenient way to standardize and tailor the presentation of string data for better visualization and analysis. diff --git a/packages/grafana-data/src/transformations/transformers/formatString.ts b/packages/grafana-data/src/transformations/transformers/formatString.ts index 17011ff1eee..ddd302e9d5e 100644 --- a/packages/grafana-data/src/transformations/transformers/formatString.ts +++ b/packages/grafana-data/src/transformations/transformers/formatString.ts @@ -18,7 +18,7 @@ export enum FormatStringOutput { KebabCase = 'Kebab Case', Trim = 'Trim', Substring = 'Substring', - Affix = 'Affix' + Affix = 'Affix', } export interface FormatStringTransformerOptions { @@ -39,8 +39,8 @@ const splitToCapitalWords = (input: string) => { }; export const getFormatStringFunction = (options: FormatStringTransformerOptions) => { - return (field: Field) => - field.values.map((value: string) => { + return (field: Field, allFields: Field[]) => + field.values.map((value: string, index: number) => { switch (options.outputFormat) { case FormatStringOutput.UpperCase: return value.toUpperCase(); @@ -64,7 +64,19 @@ export const getFormatStringFunction = (options: FormatStringTransformerOptions) case FormatStringOutput.Substring: return value.substring(options.substringStart, options.substringEnd); case FormatStringOutput.Affix: - return (options.stringPrefix ?? "") + value + (options.stringSuffix ?? ""); + let prefix = { value: options.stringPrefix ?? '' }; + let suffix = { value: options.stringSuffix ?? '' }; + [prefix, suffix].map((affix) => { + const matches = [...affix.value.matchAll(/\{([\w\d\._-]+)\}/g)]; + matches.forEach((match) => { + const fieldName = match[1]; + const matchingField = allFields.find((field) => field.name === fieldName); + if (matchingField) { + affix.value = affix.value.replace(`{${fieldName}}`, matchingField.values[index]); + } + }); + }); + return prefix.value + value + suffix.value; } }); }; @@ -111,12 +123,12 @@ export const formatStringTransformer: DataTransformerInfo string[]) => + (fieldMatches: FieldMatcher, formatStringFunction: (field: Field, allFields: Field[]) => string[]) => (frame: DataFrame, allFrames: DataFrame[]) => { return frame.fields.map((field) => { // Find the configured field if (fieldMatches(field, frame, allFrames)) { - const newVals = formatStringFunction(field); + const newVals = formatStringFunction(field, frame.fields); return { ...field,