From bff61b3dd1e9c7e2969a7d5bde88076261d4507a Mon Sep 17 00:00:00 2001 From: Ruggero Cino Date: Fri, 29 Nov 2024 13:23:06 +0100 Subject: [PATCH] Fix processing of bool types, cleanup strings --- src/modules/assets/copy/modulesCopy.ts | 22 +++++++------------ .../proposalActionsDecoder.stories.tsx | 7 +++++- .../proposalActionsDecoder.tsx | 17 ++++++-------- .../proposalActionsDecoderField.tsx | 13 +++++++---- .../proposalActionsDecoderTextField.tsx | 6 ++++- .../proposalActionsDecoderTextFieldEdit.tsx | 6 ++--- .../proposalActionsDecoderTextFieldWatch.tsx | 1 - .../proposalActionsDecoderUtils.ts | 18 +++++++-------- .../proposalActionsItem.stories.tsx | 5 +++++ 9 files changed, 51 insertions(+), 44 deletions(-) diff --git a/src/modules/assets/copy/modulesCopy.ts b/src/modules/assets/copy/modulesCopy.ts index 94ab7bd5..32edf1d7 100644 --- a/src/modules/assets/copy/modulesCopy.ts +++ b/src/modules/assets/copy/modulesCopy.ts @@ -48,20 +48,14 @@ export const modulesCopy = { RAW: 'Raw', }, }, - proposalActionsItemDecodedView: { - valueHelper: 'Amount of ETH to transfer in the transaction', - valueLabel: 'Value', - }, - proposalActionsItemFormField: { - required: (label: string) => `${label} is required.`, - boolean: (label: string) => `${label} must be set to "true" or "false".`, - address: (label: string) => `${label} is not a valid address.`, - }, - proposalActionsItemRawView: { - to: 'To', - data: 'Data', - value: 'Value', - copyButton: 'Copy data', + proposalActionsDecoder: { + copyData: 'Copy data', + add: 'Add', + validation: { + required: (label: string) => `${label} is required.`, + boolean: (label: string) => `${label} must be set to "true" or "false".`, + address: (label: string) => `${label} is not a valid address.`, + }, }, proposalActionChangeMembers: { summary: 'Summary', diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.stories.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.stories.tsx index 4d1deb8f..a22c5a8c 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.stories.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.stories.tsx @@ -3,7 +3,11 @@ import type { Meta, StoryObj } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; import { generateProposalAction } from '../proposalActionsTestUtils'; import { ProposalActionsDecoder } from './proposalActionsDecoder'; -import { ProposalActionsDecoderView, type IProposalActionsDecoderProps } from './proposalActionsDecoder.api'; +import { + ProposalActionsDecoderMode, + ProposalActionsDecoderView, + type IProposalActionsDecoderProps, +} from './proposalActionsDecoder.api'; const defaultRender = (props: IProposalActionsDecoderProps) => { const methods = useForm({ mode: 'onTouched', defaultValues: props.action }); @@ -74,6 +78,7 @@ export const Default: Story = { export const ReadOnly: Story = { args: { view: ProposalActionsDecoderView.DECODED, + mode: ProposalActionsDecoderMode.READ, action: generateProposalAction({ inputData: { function: 'approve', diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.tsx index b7ba1d68..7a3cb655 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoder.tsx @@ -27,19 +27,20 @@ export const ProposalActionsDecoder: React.FC = (p const { value, data, inputData } = action; const { copy } = useGukModulesContext(); - const { watch, setValue } = useFormContext(mode === ProposalActionsDecoderMode.EDIT); const dataFieldName = proposalActionsDecoderUtils.getFieldName('data', formPrefix) as 'data'; const updateEncodedData = useCallback( (formValues: DeepPartial) => { - const functionParameters = formValues.inputData?.parameters?.map((parameter) => parameter?.value); - const actionAbi = [{ type: 'function', name: inputData?.function, inputs: inputData?.parameters }]; + const functionParameters = proposalActionsDecoderUtils.formValuesToFunctionParameters(formValues); + const actionAbi = [{ type: 'function', inputs: inputData?.parameters }]; let data = '0x'; try { data = encodeFunctionData({ abi: actionAbi, args: functionParameters }); + } catch (error: unknown) { + // Form values are not valid, ignore error. } finally { // @ts-expect-error Limitation of react-hook-form, ignore error setValue(dataFieldName, data); @@ -69,12 +70,7 @@ export const ProposalActionsDecoder: React.FC = (p fieldName="value" mode={mode} formPrefix={formPrefix} - parameter={{ - name: 'value', - notice: copy.proposalActionsItemDecodedView.valueHelper, - value: value, - type: 'uint', - }} + parameter={{ name: 'value', value: value, type: 'uint' }} /> )} = (p mode={mode} formPrefix={formPrefix} parameter={{ name: 'data', value: data, type: 'bytes' }} + // Render the data field as hidden on decoded view to register the field on the form on EDIT mode className={view === ProposalActionsDecoderView.DECODED ? 'hidden' : undefined} component="textarea" /> {view === ProposalActionsDecoderView.RAW && mode === ProposalActionsDecoderMode.READ && ( )} {view === ProposalActionsDecoderView.DECODED && diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderField/proposalActionsDecoderField.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderField/proposalActionsDecoderField.tsx index e79a4809..23c1bfe3 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderField/proposalActionsDecoderField.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderField/proposalActionsDecoderField.tsx @@ -2,6 +2,7 @@ import classNames from 'classnames'; import { useId, useState } from 'react'; import { Button, IconType, InputContainer } from '../../../../../../core'; import { useFormContext } from '../../../../../hooks'; +import { useGukModulesContext } from '../../../../gukModulesProvider'; import type { IProposalActionInputDataParameter } from '../../proposalActionsDefinitions'; import { type IProposalActionsDecoderProps, ProposalActionsDecoderMode } from '../proposalActionsDecoder.api'; import { ProposalActionsDecoderTextField } from '../proposalActionsDecoderTextField'; @@ -31,6 +32,7 @@ export const ProposalActionsDecoderField: React.FC const { notice, type, name } = parameter; const inputId = useId(); + const { copy } = useGukModulesContext(); const { setValue, getValues, unregister } = useFormContext(mode === ProposalActionsDecoderMode.EDIT); const isArray = proposalActionsDecoderUtils.isArrayType(type); @@ -73,10 +75,13 @@ export const ProposalActionsDecoderField: React.FC setNestedParameters(newNestedParameters); }; - const inputLabels = !hideLabels ? { label: name, helpText: notice } : undefined; - return ( - +
onClick={handleAddArrayItem} className={classNames('self-start')} > - Add + {copy.proposalActionsDecoder.add} )}
diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextField.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextField.tsx index 5e2a9e02..11bd0e86 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextField.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextField.tsx @@ -11,7 +11,11 @@ export const ProposalActionsDecoderTextField: React.FC; diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldEdit.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldEdit.tsx index d08b6ad2..da2f2bc0 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldEdit.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldEdit.tsx @@ -12,7 +12,7 @@ export const ProposalActionsDecoderTextFieldEdit: React.FC - ); + return ; }; diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldWatch.tsx b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldWatch.tsx index e1f51c86..53059a5d 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldWatch.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderTextField/proposalActionsDecoderTextFieldWatch.tsx @@ -10,7 +10,6 @@ export const ProposalActionsDecoderTextFieldWatch: React.FC>({ name: fieldName }); - const Component = component === 'textarea' ? TextArea : InputText; return ; diff --git a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderUtils.ts b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderUtils.ts index 2a7134cd..32951a20 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderUtils.ts +++ b/src/modules/components/proposal/proposalActions/proposalActionsDecoder/proposalActionsDecoderUtils.ts @@ -1,6 +1,7 @@ +import type { DeepPartial } from 'react-hook-form'; import type { ModulesCopy } from '../../../../assets'; import { addressUtils } from '../../../../utils'; -import type { IProposalActionInputDataParameter } from '../proposalActionsDefinitions'; +import type { IProposalAction, IProposalActionInputDataParameter } from '../proposalActionsDefinitions'; export interface IGetValidationRulesParams { /** @@ -14,7 +15,7 @@ export interface IGetValidationRulesParams { /** * Strings to use for validation errors. */ - errorMessages: ModulesCopy['proposalActionsItemFormField']; + errorMessages: ModulesCopy['proposalActionsDecoder']['validation']; /** * Defines if the field is required or not. */ @@ -38,7 +39,7 @@ class ProposalActionsDecoderUtils { validateValue = (value: ProposalActionsFieldValue = null, params: IGetValidationRulesParams) => { const { type, label, errorMessages } = params; - if (type === 'boolean') { + if (type === 'bool') { return this.validateBoolean(value) || errorMessages.boolean(label); } else if (type === 'address') { return addressUtils.isAddress(value?.toString()) || errorMessages.address(label); @@ -47,13 +48,12 @@ class ProposalActionsDecoderUtils { return undefined; }; - valueSetter = (value: ProposalActionsFieldValue = null, type: string): ProposalActionsFieldValue => { - // Store value as boolean on form when valid, otherwise store it as lowercase string. - if (type === 'boolean') { - return this.validateBoolean(value) ? value === 'true' : value?.toString().toLocaleLowerCase(); - } + formValuesToFunctionParameters = (formValues: DeepPartial): unknown[] | undefined => { + const values = formValues.inputData?.parameters?.map((parameter) => + parameter?.type === 'bool' ? parameter.value === 'true' : parameter?.value, + ); - return value; + return values; }; isArrayType = (type: string) => type.endsWith('[]'); diff --git a/src/modules/components/proposal/proposalActions/proposalActionsItem/proposalActionsItem.stories.tsx b/src/modules/components/proposal/proposalActions/proposalActionsItem/proposalActionsItem.stories.tsx index 189c7243..7abfeae0 100644 --- a/src/modules/components/proposal/proposalActions/proposalActionsItem/proposalActionsItem.stories.tsx +++ b/src/modules/components/proposal/proposalActions/proposalActionsItem/proposalActionsItem.stories.tsx @@ -70,6 +70,11 @@ export const Verified: Story = { type: 'address', value: '0x80CB2f4f9B403C4C418C597d96c95FE14FD344a6', }, + { + name: 'exact', + type: 'bool', + value: false, + }, ], }, }),