From 59df27cd276f3a50cd778e8711a96ea5c81ca6ce Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Tue, 7 Nov 2023 15:05:05 +0100 Subject: [PATCH] Transformations: Convert calculate field transformer editor to functional component (#77777) convert class based transformer editor to functional component --- .betterer.results | 3 +- .../CalculateFieldTransformerEditor.tsx | 374 ++++++++---------- 2 files changed, 168 insertions(+), 209 deletions(-) diff --git a/.betterer.results b/.betterer.results index 6e40be30205..2f500ac2f0b 100644 --- a/.betterer.results +++ b/.betterer.results @@ -5087,8 +5087,7 @@ exports[`better eslint`] = { [0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "2"], [0, 0, 0, "Do not use any type assertions.", "3"], - [0, 0, 0, "Do not use any type assertions.", "4"], - [0, 0, 0, "Do not use any type assertions.", "5"] + [0, 0, 0, "Do not use any type assertions.", "4"] ], "public/app/features/transformers/editors/ConvertFieldTypeTransformerEditor.tsx:5381": [ [0, 0, 0, "Do not use any type assertions.", "0"] diff --git a/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx b/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx index 83769c26603..00cb8dbeb7d 100644 --- a/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx +++ b/public/app/features/transformers/editors/CalculateFieldTransformerEditor.tsx @@ -1,5 +1,5 @@ import { defaults } from 'lodash'; -import React, { ChangeEvent } from 'react'; +import React, { ChangeEvent, useEffect, useState } from 'react'; import { identity, of, OperatorFunction } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -52,7 +52,6 @@ import { NumberInput } from 'app/core/components/OptionsUI/NumberInput'; interface CalculateFieldTransformerEditorProps extends TransformerUIProps {} interface CalculateFieldTransformerEditorState { - include: string[]; names: string[]; selected: string[]; } @@ -75,47 +74,30 @@ const okTypes = new Set([FieldType.time, FieldType.number, FieldType. const labelWidth = 16; -export class CalculateFieldTransformerEditor extends React.PureComponent< - CalculateFieldTransformerEditorProps, - CalculateFieldTransformerEditorState -> { - constructor(props: CalculateFieldTransformerEditorProps) { - super(props); +export const CalculateFieldTransformerEditor = (props: CalculateFieldTransformerEditorProps) => { + const { options, onChange, input } = props; + const configuredOptions = options?.reduce?.include; - this.state = { - include: props.options?.reduce?.include || [], - names: [], - selected: [], - }; - } + const [state, setState] = useState({ names: [], selected: [] }); - componentDidMount() { - this.initOptions(); - } - - componentDidUpdate(oldProps: CalculateFieldTransformerEditorProps) { - if (this.props.input !== oldProps.input) { - this.initOptions(); - } - } - - private initOptions() { - const { options } = this.props; - const configuredOptions = options?.reduce?.include || []; + useEffect(() => { const ctx = { interpolate: (v: string) => v }; - const subscription = of(this.props.input) + const subscription = of(input) .pipe( standardTransformers.ensureColumnsTransformer.operator(null, ctx), - this.extractAllNames(), - this.getVariableNames(), - this.extractNamesAndSelected(configuredOptions) + extractAllNames(), + getVariableNames(), + extractNamesAndSelected(configuredOptions || []) ) .subscribe(({ selected, names }) => { - this.setState({ names, selected }, () => subscription.unsubscribe()); + setState({ names, selected }); }); - } + return () => { + subscription.unsubscribe(); + }; + }, [input, configuredOptions]); - private getVariableNames(): OperatorFunction { + const getVariableNames = (): OperatorFunction => { if (!cfg.featureToggles.transformationsVariableSupport) { return identity; } @@ -127,9 +109,9 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< return input; }) ); - } + }; - private extractAllNames(): OperatorFunction { + const extractAllNames = (): OperatorFunction => { return (source) => source.pipe( map((input) => { @@ -154,11 +136,11 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< return allNames; }) ); - } + }; - private extractNamesAndSelected( + const extractNamesAndSelected = ( configuredOptions: string[] - ): OperatorFunction { + ): OperatorFunction => { return (source) => source.pipe( map((allNames) => { @@ -179,28 +161,16 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< return { names, selected }; }) ); - } + }; - onToggleReplaceFields = (e: React.FormEvent) => { - const { options } = this.props; - this.props.onChange({ + const onToggleReplaceFields = (e: React.FormEvent) => { + onChange({ ...options, replaceFields: e.currentTarget.checked, }); }; - onToggleRowIndexAsPercentile = (e: React.FormEvent) => { - const { options } = this.props; - this.props.onChange({ - ...options, - index: { - asPercentile: e.currentTarget.checked, - }, - }); - }; - - onModeChanged = (value: SelectableValue) => { - const { options, onChange } = this.props; + const onModeChanged = (value: SelectableValue) => { const mode = value.value ?? CalculateFieldMode.BinaryOperation; if (mode === CalculateFieldMode.WindowFunctions) { options.window = options.window ?? defaultWindowOptions; @@ -211,67 +181,42 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onAliasChanged = (evt: ChangeEvent) => { - const { options } = this.props; - this.props.onChange({ + const onAliasChanged = (evt: ChangeEvent) => { + onChange({ ...options, alias: evt.target.value, }); }; //--------------------------------------------------------- - // Cumulative functions + // Row index //--------------------------------------------------------- - updateReduceOptions = (v: ReduceOptions) => { - const { options, onChange } = this.props; + const onToggleRowIndexAsPercentile = (e: React.FormEvent) => { onChange({ ...options, - reduce: v, + index: { + asPercentile: e.currentTarget.checked, + }, }); }; - onFieldToggle = (fieldName: string) => { - const { selected } = this.state; - if (selected.indexOf(fieldName) > -1) { - this.onChange(selected.filter((s) => s !== fieldName)); - } else { - this.onChange([...selected, fieldName]); - } - }; - - onChange = (selected: string[]) => { - this.setState({ selected }); - const { reduce } = this.props.options; - this.updateReduceOptions({ - ...reduce!, - include: selected, - }); - }; - - onStatsChange = (stats: string[]) => { - const reducer = stats.length ? (stats[0] as ReducerID) : ReducerID.sum; - - const { reduce } = this.props.options; - this.updateReduceOptions({ ...reduce, reducer }); - }; - - renderRowIndex(options?: IndexOptions) { + const renderRowIndex = (options?: IndexOptions) => { return ( <> - + ); - } + }; //--------------------------------------------------------- // Window functions //--------------------------------------------------------- - updateWindowOptions = (v: WindowOptions) => { - const { options, onChange } = this.props; + const updateWindowOptions = (v: WindowOptions) => { + const { options, onChange } = props; onChange({ ...options, mode: CalculateFieldMode.WindowFunctions, @@ -279,26 +224,26 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onWindowFieldChange = (v: SelectableValue) => { - const { window } = this.props.options; - this.updateWindowOptions({ + const onWindowFieldChange = (v: SelectableValue) => { + const { window } = options; + updateWindowOptions({ ...window!, field: v.value!, }); }; - onWindowSizeChange = (v?: number) => { - const { window } = this.props.options; - this.updateWindowOptions({ + const onWindowSizeChange = (v?: number) => { + const { window } = options; + updateWindowOptions({ ...window!, windowSize: v && window?.windowSizeMode === WindowSizeMode.Percentage ? v / 100 : v, }); }; - onWindowSizeModeChange = (val: string) => { - const { window } = this.props.options; + const onWindowSizeModeChange = (val: string) => { + const { window } = options; const mode = val as WindowSizeMode; - this.updateWindowOptions({ + updateWindowOptions({ ...window!, windowSize: window?.windowSize ? mode === WindowSizeMode.Percentage @@ -309,23 +254,23 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onWindowStatsChange = (stats: string[]) => { + const onWindowStatsChange = (stats: string[]) => { const reducer = stats.length ? (stats[0] as ReducerID) : ReducerID.sum; - const { window } = this.props.options; - this.updateWindowOptions({ ...window, reducer }); + const { window } = options; + updateWindowOptions({ ...window, reducer }); }; - onTypeChange = (val: string) => { - const { window } = this.props.options; - this.updateWindowOptions({ + const onTypeChange = (val: string) => { + const { window } = options; + updateWindowOptions({ ...window!, windowAlignment: val as WindowAlignment, }); }; - renderWindowFunctions(options?: WindowOptions) { - const { names } = this.state; + const renderWindowFunctions = (options?: WindowOptions) => { + const { names } = state; options = defaults(options, { reducer: ReducerID.sum }); const selectOptions = names.map((v) => ({ label: v, value: v })); const typeOptions = [ @@ -345,7 +290,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< options={selectOptions} className="min-width-18" value={options?.field} - onChange={this.onWindowFieldChange} + onChange={onWindowFieldChange} /> @@ -353,7 +298,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< allowMultiple={false} className="width-18" stats={[options.reducer]} - onChange={this.onWindowStatsChange} + onChange={onWindowStatsChange} defaultStat={ReducerID.mean} filterOptions={(ext) => ext.id === ReducerID.mean || ext.id === ReducerID.variance || ext.id === ReducerID.stdDev @@ -364,14 +309,14 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< ); - } + }; //--------------------------------------------------------- // Reduce by Row //--------------------------------------------------------- - onReducerStatsChange = (stats: string[]) => { - const reducer = stats.length ? (stats[0] as ReducerID) : ReducerID.sum; - - const { reduce } = this.props.options; - this.updateReduceOptions({ ...reduce, reducer }); + const updateReduceOptions = (v: ReduceOptions) => { + const { onChange } = props; + onChange({ + ...options, + reduce: v, + }); }; - renderReduceRow(options?: ReduceOptions) { - const { names, selected } = this.state; + const onFieldToggle = (fieldName: string) => { + const { selected } = state; + if (selected.indexOf(fieldName) > -1) { + onReduceFieldsChanged(selected.filter((s) => s !== fieldName)); + } else { + onReduceFieldsChanged([...selected, fieldName]); + } + }; + + const onReduceFieldsChanged = (selected: string[]) => { + setState({ ...state, ...{ selected } }); + const { reduce } = options; + updateReduceOptions({ + ...reduce!, + include: selected, + }); + }; + + const onStatsChange = (stats: string[]) => { + const reducer = stats.length ? (stats[0] as ReducerID) : ReducerID.sum; + + const { reduce } = options; + updateReduceOptions({ ...reduce, reducer }); + }; + + const renderReduceRow = (options?: ReduceOptions) => { + const { names, selected } = state; options = defaults(options, { reducer: ReducerID.sum }); return ( @@ -422,7 +393,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< { - this.onFieldToggle(o); + onFieldToggle(o); }} label={o} selected={selected.indexOf(o) > -1} @@ -436,27 +407,26 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< allowMultiple={false} className="width-18" stats={[options.reducer]} - onChange={this.onStatsChange} + onChange={onStatsChange} defaultStat={ReducerID.sum} /> ); - } + }; //--------------------------------------------------------- // Cumulative Operator //--------------------------------------------------------- - onCumulativeStatsChange = (stats: string[]) => { + const onCumulativeStatsChange = (stats: string[]) => { const reducer = stats.length ? (stats[0] as ReducerID) : ReducerID.sum; - const { reduce } = this.props.options; - this.updateCumulativeOptions({ ...reduce, reducer }); + const { cumulative } = options; + updateCumulativeOptions({ ...cumulative, reducer }); }; - updateCumulativeOptions = (v: CumulativeOptions) => { - const { options, onChange } = this.props; + const updateCumulativeOptions = (v: CumulativeOptions) => { onChange({ ...options, mode: CalculateFieldMode.CumulativeFunctions, @@ -464,16 +434,16 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onCumulativeFieldChange = (v: SelectableValue) => { - const { cumulative } = this.props.options; - this.updateCumulativeOptions({ + const onCumulativeFieldChange = (v: SelectableValue) => { + const { cumulative } = options; + updateCumulativeOptions({ ...cumulative!, field: v.value!, }); }; - renderCumulativeFunctions(options?: CumulativeOptions) { - const { names } = this.state; + const renderCumulativeFunctions = (options?: CumulativeOptions) => { + const { names } = state; options = defaults(options, { reducer: ReducerID.sum }); const selectOptions = names.map((v) => ({ label: v, value: v })); @@ -485,7 +455,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< options={selectOptions} className="min-width-18" value={options?.field} - onChange={this.onCumulativeFieldChange} + onChange={onCumulativeFieldChange} /> @@ -493,21 +463,20 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< allowMultiple={false} className="width-18" stats={[options.reducer]} - onChange={this.onCumulativeStatsChange} + onChange={onCumulativeStatsChange} defaultStat={ReducerID.sum} filterOptions={(ext) => ext.id === ReducerID.sum || ext.id === ReducerID.mean} /> ); - } + }; //--------------------------------------------------------- // Binary Operator //--------------------------------------------------------- - updateBinaryOptions = (v: BinaryOptions) => { - const { options, onChange } = this.props; + const updateBinaryOptions = (v: BinaryOptions) => { onChange({ ...options, mode: CalculateFieldMode.BinaryOperation, @@ -515,36 +484,36 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onBinaryLeftChanged = (v: SelectableValue) => { - const { binary } = this.props.options; - this.updateBinaryOptions({ + const onBinaryLeftChanged = (v: SelectableValue) => { + const { binary } = options; + updateBinaryOptions({ ...binary!, left: v.value!, }); }; - onBinaryRightChanged = (v: SelectableValue) => { - const { binary } = this.props.options; - this.updateBinaryOptions({ + const onBinaryRightChanged = (v: SelectableValue) => { + const { binary } = options; + updateBinaryOptions({ ...binary!, right: v.value!, }); }; - onBinaryOperationChanged = (v: SelectableValue) => { - const { binary } = this.props.options; - this.updateBinaryOptions({ + const onBinaryOperationChanged = (v: SelectableValue) => { + const { binary } = options; + updateBinaryOptions({ ...binary!, operator: v.value!, }); }; - renderBinaryOperation(options?: BinaryOptions) { + const renderBinaryOperation = (options?: BinaryOptions) => { options = defaults(options, { operator: BinaryOperationID.Add }); let foundLeft = !options?.left; let foundRight = !options?.right; - const names = this.state.names.map((v) => { + const names = state.names.map((v) => { if (v === options?.left) { foundLeft = true; } @@ -570,7 +539,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< options={leftNames} className="min-width-18" value={options?.left} - onChange={this.onBinaryLeftChanged} + onChange={onBinaryLeftChanged} /> @@ -578,7 +547,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< className="width-4" options={ops} value={options.operator ?? ops[0].value} - onChange={this.onBinaryOperationChanged} + onChange={onBinaryOperationChanged} /> @@ -588,20 +557,19 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< className="min-width-10" options={rightNames} value={options?.right} - onChange={this.onBinaryRightChanged} + onChange={onBinaryRightChanged} /> ); - } + }; //--------------------------------------------------------- // Unary Operator //--------------------------------------------------------- - updateUnaryOptions = (v: UnaryOptions) => { - const { options, onChange } = this.props; + const updateUnaryOptions = (v: UnaryOptions) => { onChange({ ...options, mode: CalculateFieldMode.UnaryOperation, @@ -609,27 +577,27 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< }); }; - onUnaryOperationChanged = (v: SelectableValue) => { - const { unary } = this.props.options; - this.updateUnaryOptions({ + const onUnaryOperationChanged = (v: SelectableValue) => { + const { unary } = options; + updateUnaryOptions({ ...unary!, operator: v.value!, }); }; - onUnaryValueChanged = (v: SelectableValue) => { - const { unary } = this.props.options; - this.updateUnaryOptions({ + const onUnaryValueChanged = (v: SelectableValue) => { + const { unary } = options; + updateUnaryOptions({ ...unary!, fieldName: v.value!, }); }; - renderUnaryOperation(options?: UnaryOptions) { + const renderUnaryOperation = (options?: UnaryOptions) => { options = defaults(options, { operator: UnaryOperationID.Abs }); let found = !options?.fieldName; - const names = this.state.names.map((v) => { + const names = state.names.map((v) => { if (v === options?.fieldName) { found = true; } @@ -646,7 +614,7 @@ export class CalculateFieldTransformerEditor extends React.PureComponent< <> - v.value === mode)} - onChange={this.onModeChanged} - /> - - {mode === CalculateFieldMode.BinaryOperation && this.renderBinaryOperation(options.binary)} - {mode === CalculateFieldMode.UnaryOperation && this.renderUnaryOperation(options.unary)} - {mode === CalculateFieldMode.ReduceRow && this.renderReduceRow(options.reduce)} - {mode === CalculateFieldMode.CumulativeFunctions && this.renderCumulativeFunctions(options.cumulative)} - {mode === CalculateFieldMode.WindowFunctions && this.renderWindowFunctions(options.window)} - {mode === CalculateFieldMode.Index && this.renderRowIndex(options.index)} - - - - - - - - ); - } -} + return ( + <> + + + + + + + + ); +}; export const calculateFieldTransformRegistryItem: TransformerRegistryItem = { id: DataTransformerID.calculateField,