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

Merge pull request #1483 from blockscout/tom2drum/issue-1476

Tuple item names are not displayed in the new UI
parents b5242959 6aab3d9b
...@@ -14,7 +14,7 @@ export const read: Array<SmartContractReadMethod> = [ ...@@ -14,7 +14,7 @@ export const read: Array<SmartContractReadMethod> = [
method_id: '70a08231', method_id: '70a08231',
name: 'FLASHLOAN_PREMIUM_TOTAL', name: 'FLASHLOAN_PREMIUM_TOTAL',
outputs: [ outputs: [
{ internalType: 'uint256', name: '', type: 'uint256' }, { internalType: 'uint256', name: 'amount', type: 'uint256' },
], ],
payable: false, payable: false,
stateMutability: 'view', stateMutability: 'view',
...@@ -97,7 +97,7 @@ export const read: Array<SmartContractReadMethod> = [ ...@@ -97,7 +97,7 @@ export const read: Array<SmartContractReadMethod> = [
export const readResultSuccess: SmartContractQueryMethodReadSuccess = { export const readResultSuccess: SmartContractQueryMethodReadSuccess = {
is_error: false, is_error: false,
result: { result: {
names: [ 'uint256' ], names: [ 'amount' ],
output: [ output: [
{ type: 'uint256', value: '42' }, { type: 'uint256', value: '42' },
], ],
......
...@@ -97,10 +97,10 @@ export interface SmartContractMethodOutput extends SmartContractMethodInput { ...@@ -97,10 +97,10 @@ export interface SmartContractMethodOutput extends SmartContractMethodInput {
export interface SmartContractQueryMethodReadSuccess { export interface SmartContractQueryMethodReadSuccess {
is_error: false; is_error: false;
result: { result: {
names: Array<string>; names: Array<string | [ string, Array<string> ]>;
output: Array<{ output: Array<{
type: string; type: string;
value: string; value: string | Array<unknown>;
}>; }>;
}; };
} }
......
import { Box, Button, chakra, Flex, Text } from '@chakra-ui/react'; import { Box, Button, chakra, Flex } from '@chakra-ui/react';
import _fromPairs from 'lodash/fromPairs'; import _fromPairs from 'lodash/fromPairs';
import React from 'react'; import React from 'react';
import type { SubmitHandler } from 'react-hook-form'; import type { SubmitHandler } from 'react-hook-form';
...@@ -158,7 +158,17 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit, ...@@ -158,7 +158,17 @@ const ContractMethodCallable = <T extends SmartContractMethod>({ data, onSubmit,
{ 'outputs' in data && !isWrite && data.outputs.length > 0 && ( { 'outputs' in data && !isWrite && data.outputs.length > 0 && (
<Flex mt={ 3 }> <Flex mt={ 3 }>
<IconSvg name="arrows/down-right" boxSize={ 5 } mr={ 1 }/> <IconSvg name="arrows/down-right" boxSize={ 5 } mr={ 1 }/>
<Text>{ data.outputs.map(({ type }) => type).join(', ') }</Text> <p>
{ data.outputs.map(({ type, name }, index) => {
return (
<>
<chakra.span fontWeight={ 500 }>{ name } </chakra.span>
<span>{ name ? `(${ type })` : type }</span>
{ index < data.outputs.length - 1 && <span>, </span> }
</>
);
}) }
</p>
</Flex> </Flex>
) } ) }
{ result && <ResultComponent item={ data } result={ result } onSettle={ handleTxSettle }/> } { result && <ResultComponent item={ data } result={ result } onSettle={ handleTxSettle }/> }
......
...@@ -99,3 +99,34 @@ test('success', async({ mount }) => { ...@@ -99,3 +99,34 @@ test('success', async({ mount }) => {
await expect(component).toHaveScreenshot(); await expect(component).toHaveScreenshot();
}); });
test('complex success', async({ mount }) => {
const result: ContractMethodReadResult = {
is_error: false,
result: {
names: [
[
'data',
[ 'totalSupply', 'owner', 'symbol' ],
],
'supports721',
'page',
],
output: [
{
type: 'tuple[uint256,address,string]',
value: [ 1000, '0xe150519ae293922cfe6217feba3add4726f5e851', 'AOC_INCUBATORS' ],
},
{ type: 'bool', value: 'true' },
{ type: 'uint256[]', value: [ 1, 2, 3, 4, 5 ] },
],
},
};
const component = await mount(
<TestApp>
<ContractReadResult item={ item } onSettle={ onSettle } result={ result }/>
</TestApp>,
);
await expect(component).toHaveScreenshot();
});
...@@ -2,17 +2,55 @@ import { Alert, Box, chakra, useColorModeValue } from '@chakra-ui/react'; ...@@ -2,17 +2,55 @@ import { Alert, Box, chakra, useColorModeValue } from '@chakra-ui/react';
import React from 'react'; import React from 'react';
import type { ContractMethodReadResult } from './types'; import type { ContractMethodReadResult } from './types';
import type { SmartContractReadMethod } from 'types/api/contract'; import type { SmartContractQueryMethodReadSuccess, SmartContractReadMethod } from 'types/api/contract';
import hexToUtf8 from 'lib/hexToUtf8'; import hexToUtf8 from 'lib/hexToUtf8';
const TUPLE_TYPE_REGEX = /\[(.+)\]/;
const ContractReadResultError = ({ children }: {children: React.ReactNode}) => { const ContractReadResultError = ({ children }: {children: React.ReactNode}) => {
return ( return (
<Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" wordBreak="break-word" whiteSpace="pre-wrap"> <Alert status="error" mt={ 3 } p={ 4 } borderRadius="md" fontSize="sm" wordBreak="break-word" whiteSpace="pre-wrap">
{ children } { children }
</Alert> </Alert>
); );
};
interface ItemProps {
output: SmartContractQueryMethodReadSuccess['result']['output'][0];
name: SmartContractQueryMethodReadSuccess['result']['names'][0];
}
const ContractReadResultItem = ({ output, name }: ItemProps) => {
if (Array.isArray(name)) {
const [ structName, argNames ] = name;
const argTypes = output.type.match(TUPLE_TYPE_REGEX)?.[1].split(',');
return (
<>
<p>
<chakra.span fontWeight={ 500 }> { structName }</chakra.span>
<span> ({ output.type }) :</span>
</p>
{ argNames.map((argName, argIndex) => {
return (
<p key={ argName }>
<chakra.span fontWeight={ 500 }> { argName }</chakra.span>
<span>{ argTypes?.[argIndex] ? ` (${ argTypes[argIndex] })` : '' } : { String(output.value[argIndex]) }</span>
</p>
);
}) }
</>
);
}
return (
<p>
<span> </span>
{ name && <chakra.span fontWeight={ 500 }>{ name } </chakra.span> }
<span>({ output.type }) : { String(output.value) }</span>
</p>
);
}; };
interface Props { interface Props {
...@@ -53,14 +91,12 @@ const ContractReadResult = ({ item, result, onSettle }: Props) => { ...@@ -53,14 +91,12 @@ const ContractReadResult = ({ item, result, onSettle }: Props) => {
} }
return ( return (
<Box mt={ 3 } p={ 4 } borderRadius="md" bgColor={ resultBgColor } fontSize="sm"> <Box mt={ 3 } p={ 4 } borderRadius="md" bgColor={ resultBgColor } fontSize="sm" whiteSpace="break-spaces" wordBreak="break-all">
<p> <p>
[ <chakra.span fontWeight={ 600 }>{ 'name' in item ? item.name : '' }</chakra.span> method response ] [ <chakra.span fontWeight={ 500 }>{ 'name' in item ? item.name : '' }</chakra.span> method response ]
</p> </p>
<p>[</p> <p>[</p>
{ result.result.output.map(({ type, value }, index) => ( { result.result.output.map((output, index) => <ContractReadResultItem key={ index } output={ output } name={ result.result.names[index] }/>) }
<chakra.p key={ index } whiteSpace="break-spaces" wordBreak="break-all"> { type }: { String(value) }</chakra.p>
)) }
<p>]</p> <p>]</p>
</Box> </Box>
); );
......
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