Transformations: Selectively apply transformation to queries (#61735)

This commit is contained in:
Ryan McKinley
2023-01-31 09:06:06 -08:00
committed by GitHub
parent e7bfc4e749
commit bba80b6c7a
19 changed files with 417 additions and 51 deletions

View File

@@ -8,6 +8,7 @@ import {
GrafanaTheme2,
transformDataFrame,
TransformerRegistryItem,
getFrameMatchers,
} from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Icon, JSONFormatter, useStyles2 } from '@grafana/ui';
@@ -37,9 +38,16 @@ export const TransformationEditor = ({
const config = useMemo(() => configs[index], [configs, index]);
useEffect(() => {
const config = configs[index].transformation;
const matcher = config.filter?.options ? getFrameMatchers(config.filter) : undefined;
const inputTransforms = configs.slice(0, index).map((t) => t.transformation);
const outputTransforms = configs.slice(index, index + 1).map((t) => t.transformation);
const inputSubscription = transformDataFrame(inputTransforms, data).subscribe(setInput);
const inputSubscription = transformDataFrame(inputTransforms, data).subscribe((v) => {
if (matcher) {
v = data.filter((v) => matcher(v));
}
setInput(v);
});
const outputSubscription = transformDataFrame(inputTransforms, data)
.pipe(mergeMap((before) => transformDataFrame(outputTransforms, before)))
.subscribe(setOutput);
@@ -56,18 +64,13 @@ export const TransformationEditor = ({
options: { ...uiConfig.transformation.defaultOptions, ...config.transformation.options },
input,
onChange: (opts) => {
onChange(index, { id: config.transformation.id, options: opts });
onChange(index, {
...config.transformation,
options: opts,
});
},
}),
[
uiConfig.editor,
uiConfig.transformation.defaultOptions,
config.transformation.options,
config.transformation.id,
input,
onChange,
index,
]
[uiConfig.editor, uiConfig.transformation.defaultOptions, config.transformation, input, onChange, index]
);
return (

View File

@@ -0,0 +1,55 @@
import { css } from '@emotion/css';
import React, { useMemo } from 'react';
import {
DataFrame,
DataTransformerConfig,
GrafanaTheme2,
StandardEditorContext,
StandardEditorsRegistryItem,
} from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { FrameSelectionEditor } from 'app/plugins/panel/geomap/editor/FrameSelectionEditor';
interface TransformationFilterProps {
index: number;
config: DataTransformerConfig;
data: DataFrame[];
onChange: (index: number, config: DataTransformerConfig) => void;
}
export const TransformationFilter = ({ index, data, config, onChange }: TransformationFilterProps) => {
const styles = useStyles2(getStyles);
const context = useMemo(() => {
// eslint-disable-next-line
return { data } as StandardEditorContext<unknown>;
}, [data]);
return (
<div className={styles.wrapper}>
<h5>Apply tranformation to</h5>
<FrameSelectionEditor
value={config.filter!}
context={context}
// eslint-disable-next-line
item={{} as StandardEditorsRegistryItem}
onChange={(filter) => onChange(index, { ...config, filter })}
/>
</div>
);
};
const getStyles = (theme: GrafanaTheme2) => {
const borderRadius = theme.shape.borderRadius();
return {
wrapper: css`
padding: ${theme.spacing(2)};
border: 2px solid ${theme.colors.background.secondary};
border-top: none;
border-radius: 0 0 ${borderRadius} ${borderRadius};
position: relative;
top: -4px;
`,
};
};

View File

@@ -1,7 +1,7 @@
import React, { useCallback } from 'react';
import { useToggle } from 'react-use';
import { DataFrame, DataTransformerConfig, TransformerRegistryItem } from '@grafana/data';
import { DataFrame, DataTransformerConfig, TransformerRegistryItem, FrameMatcherID } from '@grafana/data';
import { HorizontalGroup } from '@grafana/ui';
import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
@@ -12,6 +12,7 @@ import {
import { PluginStateInfo } from 'app/features/plugins/components/PluginStateInfo';
import { TransformationEditor } from './TransformationEditor';
import { TransformationFilter } from './TransformationFilter';
import { TransformationsEditorTransformation } from './types';
interface TransformationOperationRowProps {
@@ -24,7 +25,7 @@ interface TransformationOperationRowProps {
onChange: (index: number, config: DataTransformerConfig) => void;
}
export const TransformationOperationRow: React.FC<TransformationOperationRowProps> = ({
export const TransformationOperationRow = ({
onRemove,
index,
id,
@@ -32,10 +33,12 @@ export const TransformationOperationRow: React.FC<TransformationOperationRowProp
configs,
uiConfig,
onChange,
}) => {
}: TransformationOperationRowProps) => {
const [showDebug, toggleDebug] = useToggle(false);
const [showHelp, toggleHelp] = useToggle(false);
const disabled = configs[index].transformation.disabled;
const filter = configs[index].transformation.filter != null;
const showFilter = filter || data.length > 1;
const onDisableToggle = useCallback(
(index: number) => {
@@ -48,6 +51,20 @@ export const TransformationOperationRow: React.FC<TransformationOperationRowProp
[onChange, configs]
);
// Adds or removes the frame filter
const toggleFilter = useCallback(() => {
let current = { ...configs[index].transformation };
if (current.filter) {
delete current.filter;
} else {
current.filter = {
id: FrameMatcherID.byRefId,
options: '', // empty string will not do anything
};
}
onChange(index, current);
}, [onChange, index, configs]);
const renderActions = ({ isOpen }: QueryOperationRowRenderProps) => {
return (
<HorizontalGroup align="center" width="auto">
@@ -58,6 +75,7 @@ export const TransformationOperationRow: React.FC<TransformationOperationRowProp
onClick={toggleHelp}
active={showHelp}
/>
{showFilter && <QueryOperationAction title="Filter" icon="filter" onClick={toggleFilter} active={filter} />}
<QueryOperationAction title="Debug" disabled={!isOpen} icon="bug" onClick={toggleDebug} active={showDebug} />
<QueryOperationAction
title="Disable/Enable transformation"
@@ -80,6 +98,9 @@ export const TransformationOperationRow: React.FC<TransformationOperationRowProp
disabled={disabled}
>
{showHelp && <OperationRowHelp markdown={prepMarkdown(uiConfig)} />}
{filter && (
<TransformationFilter index={index} config={configs[index].transformation} data={data} onChange={onChange} />
)}
<TransformationEditor
debugMode={showDebug}
index={index}