From 732f3da33f7c26782a2f9da7aeb8fd55e8bdfb83 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Wed, 22 Mar 2023 11:10:22 -0700 Subject: [PATCH] Transformers: Support adding the row index using calculate field transformer (#65148) --- .../transform-data/index.md | 1 + .../transformers/calculateField.test.ts | 16 +++++++ .../transformers/calculateField.ts | 42 ++++++++++++++----- .../CalculateFieldTransformerEditor.tsx | 1 + 4 files changed, 50 insertions(+), 10 deletions(-) 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 0099b631dfb..4142c06a6ab 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 @@ -89,6 +89,7 @@ Use this transformation to add a new field calculated from two other fields. Eac - **Mode -** Select a mode: - **Reduce row -** Apply selected calculation on each row of selected fields independently. - **Binary option -** Apply basic math operation(sum, multiply, etc) on values in a single row from two selected fields. + - **Index -** Will insert a field with the row index. - **Field name -** Select the names of fields you want to use in the calculation for the new field. - **Calculation -** If you select **Reduce row** mode, then the **Calculation** field appears. Click in the field to see a list of calculation choices you can use to create the new field. For information about available calculations, refer to [Calculation types]({{< relref "../../calculation-types" >}}). - **Operation -** If you select **Binary option** mode, then the **Operation** fields appear. These fields allow you to do basic math operations on values in a single row from two selected fields. You can also use numerical values for binary operations. diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts index 62deb6ea366..d792a07e316 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.test.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.test.ts @@ -222,6 +222,22 @@ describe('calculateField transformer w/ timeseries', () => { }); }); + it('can add index field', async () => { + const cfg = { + id: DataTransformerID.calculateField, + options: { + mode: CalculateFieldMode.Index, + replaceFields: true, + }, + }; + + await expect(transformDataFrame([cfg], [seriesBC])).toEmitValuesWith((received) => { + const data = received[0][0]; + expect(data.fields.length).toEqual(1); + expect(data.fields[0].values.toArray()).toEqual([0, 1]); + }); + }); + it('uses template variable substituion', async () => { const cfg = { id: DataTransformerID.calculateField, diff --git a/packages/grafana-data/src/transformations/transformers/calculateField.ts b/packages/grafana-data/src/transformations/transformers/calculateField.ts index fd5eac8e42b..1f1ac16eca9 100644 --- a/packages/grafana-data/src/transformations/transformers/calculateField.ts +++ b/packages/grafana-data/src/transformations/transformers/calculateField.ts @@ -5,7 +5,7 @@ import { getTimeField } from '../../dataframe/processDataFrame'; import { getFieldDisplayName } from '../../field'; import { DataFrame, DataTransformerInfo, Field, FieldType, NullValueMode, Vector } from '../../types'; import { BinaryOperationID, binaryOperators } from '../../utils/binaryOperators'; -import { ArrayVector, BinaryOperationVector, ConstantVector } from '../../vector'; +import { ArrayVector, BinaryOperationVector, ConstantVector, IndexVector } from '../../vector'; import { AsNumberVector } from '../../vector/AsNumberVector'; import { RowVector } from '../../vector/RowVector'; import { doStandardCalcs, fieldReducers, ReducerID } from '../fieldReducer'; @@ -19,6 +19,7 @@ import { noopTransformer } from './noop'; export enum CalculateFieldMode { ReduceRow = 'reduceRow', BinaryOperation = 'binary', + Index = 'index', } export interface ReduceOptions { @@ -98,6 +99,22 @@ export const calculateFieldTransformer: DataTransformerInfo { + const f = { + name: options.alias ?? 'Row', + type: FieldType.number, + values: new IndexVector(frame.length), + config: { + min: 0, + max: frame.length - 1, + }, + }; + return { + ...frame, + fields: options.replaceFields ? [f] : [...frame.fields, f], + }; + }); } // Nothing configured @@ -235,16 +252,21 @@ export function getNameFromOptions(options: CalculateFieldTransformerOptions) { return options.alias; } - if (options.mode === CalculateFieldMode.BinaryOperation) { - const { binary } = options; - return `${binary?.left ?? ''} ${binary?.operator ?? ''} ${binary?.right ?? ''}`; - } - - if (options.mode === CalculateFieldMode.ReduceRow) { - const r = fieldReducers.getIfExists(options.reduce?.reducer); - if (r) { - return r.name; + switch (options.mode) { + case CalculateFieldMode.BinaryOperation: { + const { binary } = options; + return `${binary?.left ?? ''} ${binary?.operator ?? ''} ${binary?.right ?? ''}`; } + case CalculateFieldMode.ReduceRow: + { + const r = fieldReducers.getIfExists(options.reduce?.reducer); + if (r) { + return r.name; + } + } + break; + case CalculateFieldMode.Index: + return 'Row'; } return 'math'; diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx index 95b35007cf1..f75643f589f 100644 --- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx +++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx @@ -37,6 +37,7 @@ interface CalculateFieldTransformerEditorState { const calculationModes = [ { value: CalculateFieldMode.BinaryOperation, label: 'Binary operation' }, { value: CalculateFieldMode.ReduceRow, label: 'Reduce row' }, + { value: CalculateFieldMode.Index, label: 'Row index' }, ]; const okTypes = new Set([FieldType.time, FieldType.number, FieldType.string]);