Show proxied with no accounts (#2959)

* Display proxied with no local attached

* Allow anybody to submit call on final

* Proxy indicator
This commit is contained in:
Jaco Greeff 2020-06-15 16:48:34 +02:00 committed by GitHub
parent 66cee9a03c
commit 5374a784f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 47 deletions

View File

@ -29,6 +29,7 @@ import RecoverAccount from './modals/RecoverAccount';
import RecoverSetup from './modals/RecoverSetup';
import Transfer from './modals/Transfer';
import useMultisigApprovals from './useMultisigApprovals';
import useProxies from './useProxies';
interface Props extends SortedAccount {
className?: string;
@ -73,7 +74,8 @@ function Account ({ account: { address, meta }, className = '', filter, isFavori
transform: (opt: Option<RecoveryConfig>) => opt.unwrapOr(null)
});
const multiInfos = useMultisigApprovals(address);
const { flags: { isDevelopment, isExternal, isHardware, isInjected, isMultisig }, genesisHash, name: accName, onSetGenesisHash, tags } = useAccountInfo(address);
const proxyInfo = useProxies(address);
const { flags: { isDevelopment, isExternal, isHardware, isInjected, isMultisig, isProxied }, genesisHash, name: accName, onSetGenesisHash, tags } = useAccountInfo(address);
const [{ democracyUnlockTx }, setUnlockableIds] = useState<DemocracyUnlockable>({ democracyUnlockTx: null, ids: [] });
const [isVisible, setIsVisible] = useState(true);
const [isBackupOpen, toggleBackup] = useToggle();
@ -227,6 +229,15 @@ function Account ({ account: { address, meta }, className = '', filter, isFavori
type='brown'
/>
)}
{isProxied && !proxyInfo.hasOwned && (
<Badge
hover={t<string>('Proxied account has no owned proxies')}
info='0'
isInline
isTooltip
type='brown'
/>
)}
</td>
<td className='address'>
<AddressSmall value={address} />

View File

@ -240,7 +240,6 @@ function Overview ({ className = '', onStatusChange }: Props): React.ReactElemen
footer={footer}
header={header}
>
{}
{sortedAccounts.map(({ account, isFavorite }): React.ReactNode => (
<Account
account={account}

View File

@ -78,19 +78,22 @@ function MultisigApprove ({ className = '', onClose, ongoing, threshold, who }:
);
}, [signatory, who]);
// filter the who by those not approved yet that is an actual account we own. In the case of
// Filter the who by those not approved yet that is an actual account we own. In the case of
// rejections, we defer to the the first approver, since he is the only one to send the cancel
// On reaching threshold, we include all possible signatories in the list
useEffect((): void => {
const hasThreshold = multisig && (multisig.approvals.length >= threshold);
setWhoFilter(
who
.map((w) => registry.createType('AccountId', w).toString())
.filter((w) => allAccounts.some((a) => a === w) && multisig && (
type === 'nay'
? multisig.approvals[0].eq(w)
: !multisig.approvals.some((a) => a.eq(w))
: hasThreshold || !multisig.approvals.some((a) => a.eq(w))
))
);
}, [allAccounts, multisig, type, who]);
}, [allAccounts, multisig, threshold, type, who]);
// based on the type, multisig, others create the tx. This can be either an approval or final call
useEffect((): void => {

View File

@ -2,16 +2,16 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ProxyType } from '@polkadot/types/interfaces';
import { ActionStatus } from '@polkadot/react-components/Status/types';
import { ModalProps } from '../../types';
import React, { useCallback, useState, useEffect } from 'react';
import React, { useCallback, useState } from 'react';
import { Button, Input, InputAddressSimple, Modal } from '@polkadot/react-components';
import { useAccounts, useApi } from '@polkadot/react-hooks';
import { useApi } from '@polkadot/react-hooks';
import keyring from '@polkadot/ui-keyring';
import { useTranslation } from '../../translate';
import useProxies from '../useProxies';
interface Props extends ModalProps {
className?: string;
@ -24,17 +24,6 @@ interface CreateOptions {
tags?: string[];
}
interface Proxy {
address: string;
isOwned: boolean;
type: ProxyType;
}
interface ProxyState {
hasOwned: boolean;
proxies: Proxy[];
}
function createProxy (address: string, { genesisHash, name, tags = [] }: CreateOptions, success: string): ActionStatus {
// we will fill in all the details below
const status = { action: 'create' } as ActionStatus;
@ -55,28 +44,10 @@ function createProxy (address: string, { genesisHash, name, tags = [] }: CreateO
function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.ReactElement<Props> {
const { api, isDevelopment } = useApi();
const { allAccounts } = useAccounts();
const { t } = useTranslation();
const [{ isNameValid, name }, setName] = useState({ isNameValid: false, name: '' });
const [stashAddress, setStashAddress] = useState<string | null>(null);
const [{ hasOwned }, setProxies] = useState<ProxyState>({ hasOwned: false, proxies: [] });
useEffect((): void => {
if (stashAddress) {
api.query.proxy
.proxies(stashAddress)
.then(([_proxies]): void => {
const proxies = _proxies.map(([accountId, type]): Proxy => ({
address: accountId.toString(),
isOwned: allAccounts.includes(accountId.toString()),
type
}));
setProxies({ hasOwned: proxies.some(({ isOwned }) => isOwned), proxies });
})
.catch(console.error);
}
}, [allAccounts, api, stashAddress]);
const { hasOwned } = useProxies(stashAddress);
const _createProxied = useCallback(
(): void => {
@ -96,14 +67,6 @@ function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.Re
[]
);
const _onChangeStash = useCallback(
(address: string | null): void => {
setProxies({ hasOwned: false, proxies: [] });
setStashAddress(address);
},
[]
);
const isValid = isNameValid && !!stashAddress && hasOwned;
return (
@ -120,7 +83,7 @@ function ProxyAdd ({ className = '', onClose, onStatusChange }: Props): React.Re
help={t<string>('The address that you have a valid proxy setup for.')}
isError={!hasOwned}
label={t<string>('proxied account')}
onChange={_onChangeStash}
onChange={setStashAddress}
placeholder={t<string>('stash address')}
/>
</Modal.Column>

View File

@ -0,0 +1,58 @@
// Copyright 2017-2020 @polkadot/app-accounts authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ProxyType } from '@polkadot/types/interfaces';
import { useEffect, useState } from 'react';
import { useAccounts, useApi, useIsMountedRef } from '@polkadot/react-hooks';
interface Proxy {
address: string;
isOwned: boolean;
type: ProxyType;
}
interface State {
hasOwned: boolean;
owned: Proxy[];
proxies: Proxy[];
}
const EMPTY_STATE: State = {
hasOwned: false,
owned: [],
proxies: []
};
export default function useProxies (address?: string | null): State {
const { api } = useApi();
const { allAccounts } = useAccounts();
const mountedRef = useIsMountedRef();
const [known, setState] = useState<State>(EMPTY_STATE);
useEffect((): void => {
setState(EMPTY_STATE);
address &&
api.query.proxy
.proxies(address)
.then(([_proxies]): void => {
const proxies = _proxies.map(([accountId, type]): Proxy => ({
address: accountId.toString(),
isOwned: allAccounts.includes(accountId.toString()),
type
}));
const owned = proxies.filter(({ isOwned }) => isOwned);
mountedRef.current && setState({
hasOwned: owned.length !== 0,
owned,
proxies
});
})
.catch(console.error);
}, [allAccounts, api, address, mountedRef]);
return known;
}