mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Transformations: Enable / disable toggle for transformation rows (#36668)
* Disable transform feature * Change icon * Added more clear way to show it's disabled
This commit is contained in:
parent
5d01add7da
commit
beca793008
packages/grafana-data/src
public/app
core/components/QueryOperationRow
features/dashboard/components/TransformationsEditor
@ -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');
|
||||
});
|
||||
});
|
||||
});
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,10 @@ export interface DataTransformerConfig<TOptions = any> {
|
||||
* Unique identifier of transformer
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* Disabled transformations are skipped
|
||||
*/
|
||||
disabled?: boolean;
|
||||
/**
|
||||
* Options to be passed to the transformer
|
||||
*/
|
||||
|
@ -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<QueryOperationRowProps> = ({
|
||||
onClose,
|
||||
onOpen,
|
||||
isOpen,
|
||||
disabled,
|
||||
draggable,
|
||||
index,
|
||||
id,
|
||||
@ -80,7 +82,7 @@ export const QueryOperationRow: React.FC<QueryOperationRowProps> = ({
|
||||
/>
|
||||
{title && (
|
||||
<div className={styles.titleWrapper} onClick={onRowToggle} aria-label="Query operation row title">
|
||||
<div className={styles.title}>{titleElement}</div>
|
||||
<div className={cx(styles.title, disabled && styles.disabled)}>{titleElement}</div>
|
||||
</div>
|
||||
)}
|
||||
{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};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -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<TransformationOperationRowProp
|
||||
}) => {
|
||||
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<TransformationOperationRowProp
|
||||
active={showHelp}
|
||||
/>
|
||||
<QueryOperationAction title="Debug" disabled={!isOpen} icon="bug" onClick={toggleDebug} active={showDebug} />
|
||||
<QueryOperationAction
|
||||
title="Disable/Enable transformation"
|
||||
icon={disabled ? 'eye-slash' : 'eye'}
|
||||
onClick={() => onDisableToggle(index)}
|
||||
active={disabled}
|
||||
/>
|
||||
<QueryOperationAction title="Remove" icon="trash-alt" onClick={() => onRemove(index)} />
|
||||
</HorizontalGroup>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<QueryOperationRow id={id} index={index} title={uiConfig.name} draggable actions={renderActions}>
|
||||
<QueryOperationRow
|
||||
id={id}
|
||||
index={index}
|
||||
title={uiConfig.name}
|
||||
draggable
|
||||
actions={renderActions}
|
||||
disabled={disabled}
|
||||
>
|
||||
{showHelp && <OperationRowHelp markdown={prepMarkdown(uiConfig)} />}
|
||||
<TransformationEditor
|
||||
debugMode={showDebug}
|
||||
@ -72,8 +97,8 @@ function prepMarkdown(uiConfig: TransformerRegistryItem<any>) {
|
||||
return `
|
||||
${helpMarkdown}
|
||||
|
||||
<a href="https://grafana.com/docs/grafana/latest/panels/transformations/?utm_source=grafana" target="_blank" rel="noreferrer">
|
||||
Read more on the documentation site
|
||||
</a>
|
||||
Go the <a href="https://grafana.com/docs/grafana/latest/panels/transformations/?utm_source=grafana" target="_blank" rel="noreferrer">
|
||||
transformation documentation
|
||||
</a> for more.
|
||||
`;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user