From b7f854a06cfbbd13024d8d7ef6f98e681eec07da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jamr=C3=B3z?= Date: Tue, 7 Nov 2023 12:17:02 +0100 Subject: [PATCH] Correlations: Fix incorrect state transitions in transformations editor (#77434) * Extract transformations editor row to a seprate component * Use css object instead of string literals * Update .betterer.results * Post merge fixes * Bring back validation rules * Switch to css/object * Post-merge fixes Ensuring Stack from grafana-ui is used after conflicts with 25779bb6e5cedef712db15b9cc77ab4af68c31dd --- .betterer.results | 4 - .../Forms/TransformationEditorRow.tsx | 202 +++++++++++++++ .../Forms/TransformationsEditor.tsx | 236 ++---------------- 3 files changed, 217 insertions(+), 225 deletions(-) create mode 100644 public/app/features/correlations/Forms/TransformationEditorRow.tsx diff --git a/.betterer.results b/.betterer.results index a3d021c4c4e..02b49d31a6e 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2869,10 +2869,6 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], - "public/app/features/correlations/Forms/TransformationsEditor.tsx:5381": [ - [0, 0, 0, "Styles should be written using objects.", "0"], - [0, 0, 0, "Styles should be written using objects.", "1"] - ], "public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx:5381": [ [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] ], diff --git a/public/app/features/correlations/Forms/TransformationEditorRow.tsx b/public/app/features/correlations/Forms/TransformationEditorRow.tsx new file mode 100644 index 00000000000..e5539204e15 --- /dev/null +++ b/public/app/features/correlations/Forms/TransformationEditorRow.tsx @@ -0,0 +1,202 @@ +import { css } from '@emotion/css'; +import React, { useState } from 'react'; +import { useFormContext, useWatch } from 'react-hook-form'; + +import { Field, Icon, IconButton, Input, Label, Select, Stack, Tooltip, useStyles2 } from '@grafana/ui'; + +import { getSupportedTransTypeDetails, getTransformOptions } from './types'; + +type Props = { + index: number; + value: Record; + readOnly: boolean; + remove: (index?: number | number[]) => void; +}; + +const getStyles = () => ({ + // set fixed position from the top instead of centring as the container + // may get bigger when the for is invalid + removeButton: css({ + marginTop: '25px', + }), +}); + +const TransformationEditorRow = (props: Props) => { + const { index, value: defaultValue, readOnly, remove } = props; + const { control, formState, register, setValue, watch, getValues } = useFormContext(); + + const [keptVals, setKeptVals] = useState<{ expression?: string; mapValue?: string }>({}); + + register(`config.transformations.${index}.type`, { + required: { value: true, message: 'Please select a transformation type' }, + }); + const typeValue = useWatch({ name: `config.transformations.${index}.type`, control }); + + const styles = useStyles2(getStyles); + + const transformOptions = getTransformOptions(); + + return ( + + + + +

The type of transformation that will be applied to the source data.

+ + } + > + +
+
+ } + invalid={!!formState.errors?.config?.transformations?.[index]?.type} + error={formState.errors?.config?.transformations?.[index]?.type?.message} + validationMessageHorizontalOverflow={true} + > + + + + + +

+ Required for regular expression. The expression the transformation will use. Logfmt does not use + further specifications. +

+ + } + > + +
+ + } + invalid={!!formState.errors?.config?.transformations?.[index]?.expression} + error={formState.errors?.config?.transformations?.[index]?.expression?.message} + > + +
+ + + +

+ Optional. Defines the name of the variable. This is currently only valid for regular expressions + with a single, unnamed capture group. +

+ + } + > + +
+ + } + > + +
+ {!readOnly && ( +
+ { + remove(index); + }} + > + Remove + +
+ )} + + ); +}; + +export default TransformationEditorRow; diff --git a/public/app/features/correlations/Forms/TransformationsEditor.tsx b/public/app/features/correlations/Forms/TransformationsEditor.tsx index 5740ff38736..35e6ccb25d0 100644 --- a/public/app/features/correlations/Forms/TransformationsEditor.tsx +++ b/public/app/features/correlations/Forms/TransformationsEditor.tsx @@ -1,48 +1,27 @@ import { css } from '@emotion/css'; -import { compact, fill } from 'lodash'; -import React, { useState } from 'react'; +import React from 'react'; import { useFormContext } from 'react-hook-form'; import { GrafanaTheme2 } from '@grafana/data'; -import { - Button, - Field, - FieldArray, - Icon, - IconButton, - Input, - InputControl, - Label, - Select, - Tooltip, - useStyles2, - Stack, -} from '@grafana/ui'; +import { Button, FieldArray, Stack, useStyles2 } from '@grafana/ui'; -import { getSupportedTransTypeDetails, getTransformOptions } from './types'; +import TransformationsEditorRow from './TransformationEditorRow'; type Props = { readOnly: boolean }; const getStyles = (theme: GrafanaTheme2) => ({ - heading: css` - font-size: ${theme.typography.h5.fontSize}; - font-weight: ${theme.typography.fontWeightRegular}; - `, - // set fixed position from the top instead of centring as the container - // may get bigger when the for is invalid - removeButton: css` - margin-top: 25px; - `, + heading: css({ + fontSize: theme.typography.h5.fontSize, + fontWeight: theme.typography.fontWeightRegular, + }), }); export const TransformationsEditor = (props: Props) => { - const { control, formState, register, setValue, watch, getValues } = useFormContext(); + const { control, register } = useFormContext(); const { readOnly } = props; - const [keptVals, setKeptVals] = useState>([]); const styles = useStyles2(getStyles); - const transformOptions = getTransformOptions(); return ( <> @@ -56,198 +35,13 @@ export const TransformationsEditor = (props: Props) => {
{fields.map((fieldVal, index) => { return ( - - - - -

The type of transformation that will be applied to the source data.

-
- } - > - - - - } - invalid={!!formState.errors?.config?.transformations?.[index]?.type} - error={formState.errors?.config?.transformations?.[index]?.type?.message} - validationMessageHorizontalOverflow={true} - > - { - // input control field is not manipulated with remove, use value from control - return ( - - - - - -

- Required for regular expression. The expression the transformation will use. - Logfmt does not use further specifications. -

- - } - > - -
- - } - invalid={!!formState.errors?.config?.transformations?.[index]?.expression} - error={formState.errors?.config?.transformations?.[index]?.expression?.message} - > - -
- - - -

- Optional. Defines the name of the variable. This is currently only valid for - regular expressions with a single, unnamed capture group. -

- - } - > - -
- - } - > - -
- {!readOnly && ( -
- { - remove(index); - const keptValsCopy: Array<{ expression?: string; mapValue?: string } | undefined> = [ - ...keptVals, - ]; - keptValsCopy[index] = undefined; - setKeptVals(compact(keptValsCopy)); - }} - > - Remove - -
- )} - + ); })}