Allow ABI removal on upload (#3869)
This commit is contained in:
parent
d8846f50b4
commit
ee7a4de77d
@ -71,7 +71,6 @@ function Add ({ onClose }: Props): React.ReactElement {
|
||||
isValid={isAbiValid}
|
||||
onChange={onChangeAbi}
|
||||
onRemove={onRemoveAbi}
|
||||
withLabel
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={onClose}>
|
||||
|
||||
@ -9,8 +9,7 @@ import { Button, Card, Forget } from '@polkadot/react-components';
|
||||
import { useApi, useCall, useToggle } from '@polkadot/react-hooks';
|
||||
import { Option } from '@polkadot/types';
|
||||
|
||||
import { ABI, CodeRow } from '../shared';
|
||||
import RemoveABI from '../RemoveABI';
|
||||
import { CodeRow, Messages } from '../shared';
|
||||
import store from '../store';
|
||||
import useAbi from '../useAbi';
|
||||
import { useTranslation } from '../translate';
|
||||
@ -26,8 +25,7 @@ function Code ({ className, code, onShowDeploy }: Props): React.ReactElement<Pro
|
||||
const { api } = useApi();
|
||||
const optCode = useCall<Option<Codec>>(api.query.contracts.codeStorage, [code.json.codeHash]);
|
||||
const [isForgetOpen, toggleIsForgetOpen] = useToggle();
|
||||
const [isRemoveABIOpen, toggleIsRemoveABIOpen] = useToggle();
|
||||
const { contractAbi, isAbiError, isAbiSupplied, isAbiValid, onChangeAbi, onRemoveAbi } = useAbi([code.json.abi, code.contractAbi], code.json.codeHash, true);
|
||||
const { contractAbi } = useAbi([code.json.abi, code.contractAbi], code.json.codeHash, true);
|
||||
|
||||
const _onShowDeploy = useCallback(
|
||||
() => onShowDeploy(code.json.codeHash, 0),
|
||||
@ -78,27 +76,13 @@ function Code ({ className, code, onShowDeploy }: Props): React.ReactElement<Pro
|
||||
</CodeRow>
|
||||
</Forget>
|
||||
)}
|
||||
{isRemoveABIOpen && (
|
||||
<RemoveABI
|
||||
code={code}
|
||||
key='modal-remove-abi'
|
||||
onClose={toggleIsRemoveABIOpen}
|
||||
onRemove={onRemoveAbi}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</td>
|
||||
<td className='all top'>
|
||||
<ABI
|
||||
<Messages
|
||||
contractAbi={contractAbi}
|
||||
isError={isAbiError}
|
||||
isFull
|
||||
isSupplied={isAbiSupplied}
|
||||
isValid={isAbiValid}
|
||||
onChange={onChangeAbi}
|
||||
onRemove={toggleIsRemoveABIOpen}
|
||||
onSelectConstructor={_onDeployConstructor}
|
||||
withMessages={false}
|
||||
withConstructors
|
||||
/>
|
||||
</td>
|
||||
<td className='start together'>
|
||||
|
||||
@ -97,7 +97,6 @@ function Upload ({ onClose }: Props): React.ReactElement {
|
||||
isValid={isAbiValid}
|
||||
onChange={onChangeAbi}
|
||||
onRemove={onRemoveAbi}
|
||||
withLabel
|
||||
/>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={onClose}>
|
||||
|
||||
@ -92,12 +92,11 @@ function Add ({ onClose }: Props): React.ReactElement {
|
||||
<ABI
|
||||
contractAbi={contractAbi}
|
||||
errorText={errorText}
|
||||
isError={isAbiError}
|
||||
isError={isAbiError || !isAbiValid}
|
||||
isSupplied={isAbiSupplied}
|
||||
isValid={isAbiValid}
|
||||
onChange={onChangeAbi}
|
||||
onRemove={onRemoveAbi}
|
||||
withLabel
|
||||
/>
|
||||
</AddressRow>
|
||||
</Modal.Content>
|
||||
|
||||
@ -131,7 +131,6 @@ function Deploy ({ codeHash, constructorIndex = 0, onClose, setConstructorIndex
|
||||
isValid={isAbiValid}
|
||||
onChange={onChangeAbi}
|
||||
onRemove={onRemoveAbi}
|
||||
withLabel
|
||||
/>
|
||||
)}
|
||||
{contractAbi && (
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { Abi } from '@polkadot/api-contract';
|
||||
import { InputFile, Labelled } from '@polkadot/react-components';
|
||||
import { IconLink, InputFile, Labelled } from '@polkadot/react-components';
|
||||
|
||||
import Messages from './Messages';
|
||||
import { useTranslation } from '../translate';
|
||||
@ -23,62 +23,54 @@ interface Props {
|
||||
onRemove?: () => void;
|
||||
onRemoved?: () => void;
|
||||
onSelect?: () => void;
|
||||
onSelectConstructor?: (constructorIndex?: number) => void;
|
||||
onSelectConstructor?: (index?: number) => void;
|
||||
withConstructors?: boolean;
|
||||
withLabel?: boolean;
|
||||
withMessages?: boolean;
|
||||
}
|
||||
|
||||
function renderMessages ({ contractAbi, onRemove, onSelectConstructor, withConstructors = true, withLabel, withMessages = true }: Props): React.ReactNode {
|
||||
return (
|
||||
<Messages
|
||||
contractAbi={contractAbi}
|
||||
isLabelled={withLabel}
|
||||
onRemove={onRemove}
|
||||
onSelectConstructor={onSelectConstructor}
|
||||
withConstructors={withConstructors}
|
||||
withMessages={withMessages}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const NOOP = (): void => undefined;
|
||||
|
||||
function ABI (props: Props): React.ReactElement<Props> {
|
||||
const { className, contractAbi, errorText, isDisabled, isError, isFull, isValid, onChange, withLabel } = props;
|
||||
function ABI ({ className, contractAbi, errorText, isDisabled, isError, isFull, isValid, onChange, onRemove = NOOP, onSelectConstructor, withConstructors = true, withLabel = true, withMessages = true }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const help = t('The ABI for the WASM code. The ABI is required and stored for future operations such as sending messages.');
|
||||
const label = t('contract ABI');
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{
|
||||
(contractAbi && isValid)
|
||||
? (
|
||||
withLabel
|
||||
? (
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
>
|
||||
{renderMessages(props)}
|
||||
</Labelled>
|
||||
)
|
||||
: renderMessages(props)
|
||||
)
|
||||
: (
|
||||
<InputFile
|
||||
help={help}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
isFull={isFull}
|
||||
label={label}
|
||||
onChange={onChange}
|
||||
placeholder={errorText || t<string>('click to select or drag and drop a JSON ABI file')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
return (contractAbi && isValid)
|
||||
? (
|
||||
<Labelled
|
||||
className={className}
|
||||
help={t<string>('This is the ABI as supplied. Any calls to the contract will use this information for encoding.')}
|
||||
label={t<string>('contract ABI')}
|
||||
labelExtra={onRemove && (
|
||||
<IconLink
|
||||
icon='trash'
|
||||
label={t<string>('Remove ABI')}
|
||||
onClick={onRemove}
|
||||
/>
|
||||
)}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<Messages
|
||||
contractAbi={contractAbi}
|
||||
isLabelled={withLabel}
|
||||
onSelectConstructor={onSelectConstructor}
|
||||
withConstructors={withConstructors}
|
||||
withMessages={withMessages}
|
||||
/>
|
||||
</Labelled>
|
||||
)
|
||||
: (
|
||||
<div className={className}>
|
||||
<InputFile
|
||||
help={t<string>('The ABI for the WASM code. The ABI is required and stored for future operations such as sending messages.')}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
isFull={isFull}
|
||||
label={t<string>('contract ABI')}
|
||||
onChange={onChange}
|
||||
placeholder={errorText || t<string>('click to select or drag and drop a JSON ABI file')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(ABI);
|
||||
|
||||
@ -8,7 +8,7 @@ import { ThemeProps } from '@polkadot/react-components/types';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Abi, ContractPromise } from '@polkadot/api-contract';
|
||||
import { Expander, IconLink } from '@polkadot/react-components';
|
||||
import { Expander } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
import { Option } from '@polkadot/types';
|
||||
|
||||
@ -20,16 +20,13 @@ export interface Props {
|
||||
contract?: ContractPromise;
|
||||
contractAbi: Abi;
|
||||
isLabelled?: boolean;
|
||||
isRemovable?: boolean;
|
||||
isWatching?: boolean;
|
||||
onRemove?: () => void;
|
||||
onSelect?: (messageIndex: number, resultCb: (messageIndex: number, result?: ContractCallOutcome) => void) => void;
|
||||
onSelectConstructor?: (constructorIndex: number) => void;
|
||||
withConstructors?: boolean;
|
||||
withMessages?: boolean;
|
||||
}
|
||||
|
||||
const NOOP = (): void => undefined;
|
||||
const READ_ADDR = '0x'.padEnd(66, '0');
|
||||
|
||||
function sortMessages (messages: AbiMessage[]): [AbiMessage, number][] {
|
||||
@ -44,7 +41,7 @@ function sortMessages (messages: AbiMessage[]): [AbiMessage, number][] {
|
||||
);
|
||||
}
|
||||
|
||||
function Messages ({ className = '', contract, contractAbi: { constructors, messages }, isLabelled, isRemovable, isWatching, onRemove = NOOP, onSelect, onSelectConstructor, withConstructors, withMessages } : Props): React.ReactElement<Props> {
|
||||
function Messages ({ className = '', contract, contractAbi: { constructors, messages }, isLabelled, isWatching, onSelect, onSelectConstructor, withConstructors, withMessages } : Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const optInfo = useCall<Option<ContractInfo>>(contract && api.query.contracts.contractInfoOf, [contract?.address]);
|
||||
@ -86,7 +83,7 @@ function Messages ({ className = '', contract, contractAbi: { constructors, mess
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={`ui--Messages ${className} ${isLabelled ? 'labelled' : ''}`}>
|
||||
<div className={`ui--Messages ${className}${isLabelled ? ' isLabelled' : ''}`}>
|
||||
{withConstructors && (
|
||||
<Expander summary={t<string>('Constructors ({{count}})', { replace: { count: constructors.length } })}>
|
||||
{sortMessages(constructors).map(([message, index]) => (
|
||||
@ -115,14 +112,6 @@ function Messages ({ className = '', contract, contractAbi: { constructors, mess
|
||||
))}
|
||||
</Expander>
|
||||
)}
|
||||
{isRemovable && (
|
||||
<IconLink
|
||||
className='remove-abi'
|
||||
icon='remove'
|
||||
label={t<string>('Remove ABI')}
|
||||
onClick={onRemove}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -130,16 +119,7 @@ function Messages ({ className = '', contract, contractAbi: { constructors, mess
|
||||
export default React.memo(styled(Messages)(({ theme }: ThemeProps) => `
|
||||
padding-bottom: 0.75rem !important;
|
||||
|
||||
.remove-abi {
|
||||
float: right;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
&:hover, &:hover :not(i) {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&.labelled {
|
||||
&.isLabelled {
|
||||
background: ${theme.bgInput};
|
||||
box-sizing: border-box;
|
||||
border: 1px solid rgba(34,36,38,.15);
|
||||
|
||||
@ -38,10 +38,7 @@ export default function useAbi (initialValue: [string | null | undefined, Abi |
|
||||
try {
|
||||
setAbi([json, new Abi(json), true, true]);
|
||||
|
||||
codeHash && store.saveCode(
|
||||
codeHash,
|
||||
{ abi: json }
|
||||
);
|
||||
codeHash && store.saveCode(codeHash, { abi: json });
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@ -57,10 +54,7 @@ export default function useAbi (initialValue: [string | null | undefined, Abi |
|
||||
setAbi([null, null, false, false]);
|
||||
setError([false, null]);
|
||||
|
||||
codeHash && store.saveCode(
|
||||
codeHash,
|
||||
{ abi: null }
|
||||
);
|
||||
codeHash && store.saveCode(codeHash, { abi: null });
|
||||
},
|
||||
[codeHash]
|
||||
);
|
||||
|
||||
@ -66,46 +66,44 @@ export {
|
||||
AddressRow
|
||||
};
|
||||
|
||||
export default React.memo(
|
||||
styled(AddressRow)`
|
||||
button.u.ui--Icon.editButton {
|
||||
padding: 0em .3em .3em .3em;
|
||||
color: #2e86ab;
|
||||
background: none;
|
||||
/*trick to let the button in the flow but keep the content centered regardless*/
|
||||
margin-left: -2em;
|
||||
position: relative;
|
||||
right: -2.3em;
|
||||
z-index: 1;
|
||||
export default React.memo(styled(AddressRow)`
|
||||
button.u.ui--Icon.editButton {
|
||||
padding: 0em .3em .3em .3em;
|
||||
color: #2e86ab;
|
||||
background: none;
|
||||
/*trick to let the button in the flow but keep the content centered regardless*/
|
||||
margin-left: -2em;
|
||||
position: relative;
|
||||
right: -2.3em;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.editSpan {
|
||||
white-space: nowrap;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
.editSpan {
|
||||
white-space: nowrap;
|
||||
.ui--AddressRow-balances {
|
||||
display: flex;
|
||||
.column {
|
||||
display: block;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
label,
|
||||
.result {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.ui--AddressRow-balances {
|
||||
display: flex;
|
||||
.column {
|
||||
display: block;
|
||||
|
||||
label,
|
||||
.result {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
> span {
|
||||
text-align: left;
|
||||
}
|
||||
> span {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.ui--AddressRow-placeholder {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`
|
||||
);
|
||||
.ui--AddressRow-placeholder {
|
||||
opacity: 0.5;
|
||||
}
|
||||
`);
|
||||
|
||||
@ -25,20 +25,14 @@ function IconLink ({ className = '', href, icon, label, onClick, rel, target }:
|
||||
rel={rel}
|
||||
target={target}
|
||||
>
|
||||
{icon && <Icon className={icon} />}
|
||||
{icon && <Icon icon={icon} />}
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(styled(IconLink)`
|
||||
font-size: 0.9rem !important;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
||||
i {
|
||||
text-decoration: none;
|
||||
}
|
||||
.ui--Icon {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
`);
|
||||
|
||||
@ -103,26 +103,30 @@ export default function useAccountInfo (value: string | null, isContract = false
|
||||
|
||||
useEffect((): void => {
|
||||
if (value) {
|
||||
const accountOrAddress = keyring.getAccount(value) || keyring.getAddress(value);
|
||||
const isOwned = isAccount(value);
|
||||
const isInContacts = isAddress(value);
|
||||
try {
|
||||
const accountOrAddress = keyring.getAccount(value) || keyring.getAddress(value);
|
||||
const isOwned = isAccount(value);
|
||||
const isInContacts = isAddress(value);
|
||||
|
||||
setGenesisHash(accountOrAddress?.meta.genesisHash || null);
|
||||
setFlags((flags): AddressFlags => ({
|
||||
...flags,
|
||||
isDevelopment: accountOrAddress?.meta.isTesting || false,
|
||||
isEditable: !!(!identity?.display && (isInContacts || accountOrAddress?.meta.isMultisig || (accountOrAddress && !(accountOrAddress.meta.isInjected || accountOrAddress.meta.isHardware)))) || false,
|
||||
isExternal: !!accountOrAddress?.meta.isExternal || false,
|
||||
isHardware: !!accountOrAddress?.meta.isHardware || false,
|
||||
isInContacts,
|
||||
isInjected: !!accountOrAddress?.meta.isInjected || false,
|
||||
isMultisig: !!accountOrAddress?.meta.isMultisig || false,
|
||||
isOwned,
|
||||
isProxied: !!accountOrAddress?.meta.isProxied || false
|
||||
}));
|
||||
setMeta(accountOrAddress?.meta);
|
||||
setName(accountOrAddress?.meta.name || '');
|
||||
setSortedTags(accountOrAddress?.meta.tags ? (accountOrAddress.meta.tags as string[]).sort() : []);
|
||||
setGenesisHash(accountOrAddress?.meta.genesisHash || null);
|
||||
setFlags((flags): AddressFlags => ({
|
||||
...flags,
|
||||
isDevelopment: accountOrAddress?.meta.isTesting || false,
|
||||
isEditable: !!(!identity?.display && (isInContacts || accountOrAddress?.meta.isMultisig || (accountOrAddress && !(accountOrAddress.meta.isInjected || accountOrAddress.meta.isHardware)))) || false,
|
||||
isExternal: !!accountOrAddress?.meta.isExternal || false,
|
||||
isHardware: !!accountOrAddress?.meta.isHardware || false,
|
||||
isInContacts,
|
||||
isInjected: !!accountOrAddress?.meta.isInjected || false,
|
||||
isMultisig: !!accountOrAddress?.meta.isMultisig || false,
|
||||
isOwned,
|
||||
isProxied: !!accountOrAddress?.meta.isProxied || false
|
||||
}));
|
||||
setMeta(accountOrAddress?.meta);
|
||||
setName(accountOrAddress?.meta.name || '');
|
||||
setSortedTags(accountOrAddress?.meta.tags ? (accountOrAddress.meta.tags as string[]).sort() : []);
|
||||
} catch (error) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}, [identity, isAccount, isAddress, value]);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user