Commit e8e17bb1 authored by tom goriunov's avatar tom goriunov Committed by GitHub

The possibility to query a contract with an empty array (#1943)

* The possibility to query a contract with an empty array

Fixes #1880

* update screenshots
parent c20b7f86
......@@ -19,14 +19,15 @@ interface Props {
path: string;
className?: string;
isDisabled: boolean;
isOptional?: boolean;
level: number;
}
const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDisabled, level }: Props) => {
const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDisabled, isOptional: isOptionalProp, level }: Props) => {
const ref = React.useRef<HTMLInputElement>(null);
const isNativeCoin = data.fieldType === 'native_coin';
const isOptional = isNativeCoin;
const isOptional = isOptionalProp || isNativeCoin;
const argTypeMatchInt = React.useMemo(() => matchInt(data.type), [ data.type ]);
const validate = useValidateField({ isOptional, argType: data.type, argTypeMatchInt });
......
......@@ -106,6 +106,7 @@ const ContractMethodFieldInputArray = ({
onRemoveClick={ !hasFixedSize && registeredIndices.length > 1 ? handleRemoveButtonClick : undefined }
index={ registeredIndex }
isDisabled={ isDisabled }
isOptional={ registeredIndices.length === 1 }
/>
);
}) }
......@@ -133,7 +134,7 @@ const ContractMethodFieldInputArray = ({
// primitive value array
return (
<Flex flexDir={{ base: 'column', md: 'row' }} alignItems="flex-start" columnGap={ 3 } px="6px">
{ !isArrayElement && <ContractMethodFieldLabel data={ data } level={ level }/> }
{ !isArrayElement && <ContractMethodFieldLabel data={ data } level={ level } isOptional={ registeredIndices.length === 1 }/> }
<Flex flexDir="column" rowGap={ 1 } w="100%">
{ registeredIndices.map((registeredIndex, index) => {
const itemData = transformDataForArrayItem(data, index);
......@@ -147,6 +148,7 @@ const ContractMethodFieldInputArray = ({
level={ level }
px={ 0 }
isDisabled={ isDisabled }
isOptional={ registeredIndices.length === 1 }
/>
{ !hasFixedSize && registeredIndices.length > 1 &&
<ContractMethodArrayButton index={ registeredIndex } onClick={ handleRemoveButtonClick } type="remove" my="6px"/> }
......
......@@ -14,9 +14,10 @@ interface Props extends Pick<AccordionProps, 'onAddClick' | 'onRemoveClick' | 'i
basePath: string;
level: number;
isDisabled: boolean;
isOptional?: boolean;
}
const ContractMethodFieldInputTuple = ({ data, basePath, level, isDisabled, ...accordionProps }: Props) => {
const ContractMethodFieldInputTuple = ({ data, basePath, level, isDisabled, isOptional, ...accordionProps }: Props) => {
const { formState: { errors } } = useFormContext();
const fieldsWithErrors = Object.keys(errors);
const isInvalid = fieldsWithErrors.some((field) => field.startsWith(basePath));
......@@ -64,6 +65,7 @@ const ContractMethodFieldInputTuple = ({ data, basePath, level, isDisabled, ...a
data={ component }
path={ `${ basePath }:${ index }` }
isDisabled={ isDisabled }
isOptional={ isOptional }
level={ level }
/>
);
......
......@@ -46,4 +46,32 @@ describe('transformFormDataToMethodArgs', () => {
'2',
]);
});
it('should leave the arg if it is an empty array', () => {
const formData = {
// simple array
'0:0': undefined,
// nested array
'1:0:0': undefined,
'1:1:0': '1',
'1:1:1': '2',
// array in a tuple
'2:0': 'duck',
'2:1:0': undefined,
};
const result = transformFormDataToMethodArgs(formData);
expect(result).toEqual([
[],
[
[],
[ '1', '2' ],
],
[
'duck',
[],
],
]);
});
});
......@@ -78,22 +78,20 @@ export function transformFormDataToMethodArgs(formData: ContractMethodFormFields
for (const field in formData) {
const value = formData[field];
if (value !== undefined) {
_set(result, field.replaceAll(':', '.'), value);
}
_set(result, field.replaceAll(':', '.'), value);
}
return filterOurEmptyItems(result);
return filterOutEmptyItems(result);
}
function filterOurEmptyItems(array: Array<unknown>): Array<unknown> {
function filterOutEmptyItems(array: Array<unknown>): Array<unknown> {
// The undefined value may occur in two cases:
// 1. When an optional form field is left blank by the user.
// The only optional field is the native coin value, which is safely handled in the form submit handler.
// 2. When the user adds and removes items from a field array.
// In this scenario, empty items need to be filtered out to maintain the correct sequence of arguments.
return array
.map((item) => Array.isArray(item) ? filterOurEmptyItems(item) : item)
.map((item) => Array.isArray(item) ? filterOutEmptyItems(item) : item)
.filter((item) => item !== undefined);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment