diff --git a/packages/grafana-data/src/transformations/transformDataFrame.test.ts b/packages/grafana-data/src/transformations/transformDataFrame.test.ts new file mode 100644 index 00000000000..6fefc2ae139 --- /dev/null +++ b/packages/grafana-data/src/transformations/transformDataFrame.test.ts @@ -0,0 +1,75 @@ +import { ReducerID } from './fieldReducer'; +import { DataTransformerID } from './transformers/ids'; +import { toDataFrame } from '../dataframe/processDataFrame'; +import { mockTransformationsRegistry } from '../utils/tests/mockTransformationsRegistry'; +import { reduceTransformer } from './transformers/reduce'; +import { filterFieldsByNameTransformer } from './transformers/filterByName'; +import { transformDataFrame } from './transformDataFrame'; +import { FieldType } from '../types'; + +const seriesAWithSingleField = toDataFrame({ + name: 'A', + fields: [ + { name: 'time', type: FieldType.time, values: [3000, 4000, 5000, 6000] }, + { name: 'temperature', type: FieldType.number, values: [3, 4, 5, 6] }, + ], +}); + +describe('transformDataFrame', () => { + beforeAll(() => { + mockTransformationsRegistry([reduceTransformer, filterFieldsByNameTransformer]); + }); + + it('Applies all transforms', async () => { + const cfg = [ + { + id: DataTransformerID.reduce, + options: { + reducers: [ReducerID.first], + }, + }, + { + id: DataTransformerID.filterFieldsByName, + options: { + include: { + pattern: '/First/', + }, + }, + }, + ]; + + await expect(transformDataFrame(cfg, [seriesAWithSingleField])).toEmitValuesWith((received) => { + const processed = received[0]; + expect(processed[0].length).toEqual(1); + expect(processed[0].fields.length).toEqual(1); + expect(processed[0].fields[0].values.get(0)).toEqual(3); + }); + }); + + it('Skips over disabled transforms', async () => { + const cfg = [ + { + id: DataTransformerID.reduce, + options: { + reducers: [ReducerID.first], + }, + }, + { + id: DataTransformerID.filterFieldsByName, + disabled: true, + options: { + include: { + pattern: '/First/', + }, + }, + }, + ]; + + await expect(transformDataFrame(cfg, [seriesAWithSingleField])).toEmitValuesWith((received) => { + const processed = received[0]; + expect(processed[0].length).toEqual(1); + expect(processed[0].fields.length).toEqual(2); + expect(processed[0].fields[0].values.get(0)).toEqual('temperature'); + }); + }); +}); diff --git a/packages/grafana-data/src/transformations/transformDataFrame.ts b/packages/grafana-data/src/transformations/transformDataFrame.ts index dbcb01915bb..ed829b4385b 100644 --- a/packages/grafana-data/src/transformations/transformDataFrame.ts +++ b/packages/grafana-data/src/transformations/transformDataFrame.ts @@ -60,6 +60,11 @@ export function transformDataFrame(options: DataTransformerConfig[], data: DataF for (let index = 0; index < options.length; index++) { const config = options[index]; + + if (config.disabled) { + continue; + } + operators.push(getOperator(config)); } diff --git a/packages/grafana-data/src/types/transformations.ts b/packages/grafana-data/src/types/transformations.ts index eac4f448506..c1ad5995f61 100644 --- a/packages/grafana-data/src/types/transformations.ts +++ b/packages/grafana-data/src/types/transformations.ts @@ -19,6 +19,10 @@ export interface DataTransformerConfig { * Unique identifier of transformer */ id: string; + /** + * Disabled transformations are skipped + */ + disabled?: boolean; /** * Options to be passed to the transformer */ diff --git a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx index 633cbf0c71f..5326adfa4f4 100644 --- a/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx +++ b/public/app/core/components/QueryOperationRow/QueryOperationRow.tsx @@ -1,7 +1,7 @@ import React, { useState, useCallback } from 'react'; import { Icon, renderOrCallToRender, stylesFactory, useTheme } from '@grafana/ui'; import { GrafanaTheme } from '@grafana/data'; -import { css } from '@emotion/css'; +import { css, cx } from '@emotion/css'; import { useUpdateEffect } from 'react-use'; import { Draggable } from 'react-beautiful-dnd'; @@ -16,6 +16,7 @@ interface QueryOperationRowProps { children: React.ReactNode; isOpen?: boolean; draggable?: boolean; + disabled?: boolean; } export type QueryOperationRowRenderProp = ((props: QueryOperationRowRenderProps) => React.ReactNode) | React.ReactNode; @@ -34,6 +35,7 @@ export const QueryOperationRow: React.FC = ({ onClose, onOpen, isOpen, + disabled, draggable, index, id, @@ -80,7 +82,7 @@ export const QueryOperationRow: React.FC = ({ /> {title && (
-
{titleElement}
+
{titleElement}
)} {headerElementRendered} @@ -167,6 +169,9 @@ const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => { margin-top: ${theme.spacing.inlineFormMargin}; margin-left: ${theme.spacing.lg}; `, + disabled: css` + color: ${theme.colors.textWeak}; + `, }; }); diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx index 2f64bf498ec..2337d7cd75e 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationOperationRow.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useCallback } from 'react'; import { DataFrame, DataTransformerConfig, TransformerRegistryItem } from '@grafana/data'; import { HorizontalGroup } from '@grafana/ui'; @@ -34,6 +34,18 @@ export const TransformationOperationRow: React.FC { const [showDebug, toggleDebug] = useToggle(false); const [showHelp, toggleHelp] = useToggle(false); + const disabled = configs[index].transformation.disabled; + + const onDisableToggle = useCallback( + (index: number) => { + const current = configs[index].transformation; + onChange(index, { + ...current, + disabled: current.disabled ? undefined : true, + }); + }, + [onChange, configs] + ); const renderActions = ({ isOpen }: QueryOperationRowRenderProps) => { return ( @@ -46,13 +58,26 @@ export const TransformationOperationRow: React.FC + onDisableToggle(index)} + active={disabled} + /> onRemove(index)} /> ); }; return ( - + {showHelp && } ) { return ` ${helpMarkdown} - -Read more on the documentation site - +Go the +transformation documentation + for more. `; }