From 11fa7c697e364aeb08c4c343f2bd9b52851b18ec Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Thu, 4 Feb 2021 12:23:05 -0800 Subject: [PATCH] Transformers: add search to transform selection (#30854) --- .../src/selectors/components.ts | 1 + .../TransformationsEditor.test.tsx | 4 +- .../TransformationsEditor.tsx | 194 ++++++++++++------ 3 files changed, 132 insertions(+), 67 deletions(-) diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index a8bc8ba9234..a261cc18ea9 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -122,6 +122,7 @@ export const Components = { modeLabel: 'Transform mode label', calculationsLabel: 'Transform calculations label', }, + searchInput: 'search transformations', }, PageToolbar: { container: () => '.page-toolbar', diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx index 4d1920eed50..5269a9a6d37 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.test.tsx @@ -51,8 +51,8 @@ describe('TransformationsEditor', () => { const addTransformationButton = screen.getByText(buttonLabel); userEvent.click(addTransformationButton); - const picker = screen.getByLabelText(selectors.components.ValuePicker.select(buttonLabel)); - expect(picker).toBeDefined(); + const search = screen.getByLabelText(selectors.components.Transforms.searchInput); + expect(search).toBeDefined(); }); }); diff --git a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx index 191b42b6596..c1324bed2ed 100644 --- a/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx +++ b/public/app/features/dashboard/components/TransformationsEditor/TransformationsEditor.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { ChangeEvent } from 'react'; import { Alert, Button, @@ -8,9 +8,10 @@ import { Themeable, DismissableFeatureInfoBox, useTheme, - ValuePicker, VerticalGroup, withTheme, + Input, + IconButton, } from '@grafana/ui'; import { DataFrame, @@ -40,6 +41,8 @@ interface TransformationsEditorProps extends Themeable { interface State { data: DataFrame[]; transformations: TransformationsEditorTransformation[]; + search: string; + showPicker?: boolean; } class UnThemedTransformationsEditor extends React.PureComponent { @@ -56,9 +59,34 @@ class UnThemedTransformationsEditor extends React.PureComponent) => { + this.setState({ search: event.target.value }); + }; + + onSearchKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + const { search } = this.state; + if (search) { + const lower = search.toLowerCase(); + const filtered = standardTransformersRegistry.list().filter((t) => { + const txt = (t.name + t.description).toLowerCase(); + return txt.indexOf(lower) >= 0; + }); + if (filtered.length > 0) { + this.onTransformationAdd({ value: filtered[0].id }); + } + } + } else if (event.keyCode === 27) { + // Escape key + this.setState({ search: '', showPicker: false }); + event.stopPropagation(); // don't exit the editor + } + }; + buildTransformationIds(transformations: DataTransformerConfig[]) { const transformationCounters: Record = {}; const transformationIds: string[] = []; @@ -113,6 +141,7 @@ class UnThemedTransformationsEditor extends React.PureComponent { - const availableTransformers = standardTransformersRegistry.list().map((t) => { - return { - value: t.transformation.id, - label: t.name, - description: t.description, - }; - }); - - return ( -
- -
- ); - }; - onDragEnd = (result: DropResult) => { const { transformations } = this.state; @@ -208,43 +210,106 @@ class UnThemedTransformationsEditor extends React.PureComponent { + const txt = (t.name + t.description).toLowerCase(); + return txt.indexOf(lower) >= 0; + }); + suffix = ( + <> + {filtered.length} / {xforms.length}    + { + this.setState({ search: '' }); + }} + /> + + ); + + xforms = filtered; + } + + const noTransforms = !transformations?.length; + const showPicker = noTransforms || this.state.showPicker; + if (!suffix && showPicker && !noTransforms) { + suffix = ( + { + this.setState({ showPicker: false }); + }} + /> + ); + } + return ( <> - - + +

+ Transformations allow you to join, calculate, re-order, hide and rename your query results before being + visualized.
+ Many transforms are not suitable if you're using the Graph visualization as it currently only + supports time series.
+ It can help to switch to Table visualization to understand what a transformation is doing.
+

+
+
+ )} + {showPicker ? ( + + + + {xforms.map((t) => { + return ( + Select} + ariaLabel={selectors.components.TransformTab.newTransform(t.name)} + onClick={() => { + this.onTransformationAdd({ value: t.id }); + }} + /> + ); + })} + + ) : ( + } - ariaLabel={selectors.components.TransformTab.newTransform(t.name)} - onClick={() => { - this.onTransformationAdd({ value: t.id }); - }} - /> - ); - })} - + Add transformation + + )} ); } @@ -271,9 +336,8 @@ class UnThemedTransformationsEditor extends React.PureComponent ) : null} - {!hasTransforms && this.renderNoAddedTransformsState()} {hasTransforms && this.renderTransformationEditors()} - {hasTransforms && this.renderTransformationSelector()} + {this.renderTransformsPicker()}