Skip to content

Commit

Permalink
The possibility to query a contract with an empty array (#1943)
Browse files Browse the repository at this point in the history
* The possibility to query a contract with an empty array

Fixes #1880

* update screenshots
  • Loading branch information
tom2drum authored Jun 10, 2024
1 parent c20b7f8 commit e8e17bb
Show file tree
Hide file tree
Showing 8 changed files with 41 additions and 10 deletions.
5 changes: 3 additions & 2 deletions ui/address/contract/ABI/form/ContractMethodFieldInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ const ContractMethodFieldInputArray = ({
onRemoveClick={ !hasFixedSize && registeredIndices.length > 1 ? handleRemoveButtonClick : undefined }
index={ registeredIndex }
isDisabled={ isDisabled }
isOptional={ registeredIndices.length === 1 }
/>
);
}) }
Expand Down Expand Up @@ -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);
Expand All @@ -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"/> }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -64,6 +65,7 @@ const ContractMethodFieldInputTuple = ({ data, basePath, level, isDisabled, ...a
data={ component }
path={ `${ basePath }:${ index }` }
isDisabled={ isDisabled }
isOptional={ isOptional }
level={ level }
/>
);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions ui/address/contract/ABI/form/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
[],
],
]);
});
});
10 changes: 4 additions & 6 deletions ui/address/contract/ABI/form/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down

0 comments on commit e8e17bb

Please sign in to comment.