From dc4a9318c791ccfe88f0dace74c21be36de6a29d Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Sat, 6 Apr 2019 22:34:17 +0200 Subject: [PATCH] Nominate multiples (#899) * Nominate multiples * Swap columns to stashes, pass through targets to nominate * Nominate Validator -> Nominate Validators --- .../app-staking/src/Account/Nominating.tsx | 80 +++++-------------- packages/app-staking/src/Account/index.tsx | 16 ++-- packages/app-staking/src/Overview/Address.tsx | 49 ++++++++---- .../app-staking/src/Overview/CurrentList.tsx | 4 +- packages/app-staking/src/StakeList.tsx | 18 +++++ packages/app-staking/src/index.tsx | 8 +- packages/app-staking/src/types.ts | 1 + packages/ui-app/src/Dropdown.tsx | 6 +- packages/ui-app/src/InputAddress/index.tsx | 72 ++++++++++++++--- 9 files changed, 153 insertions(+), 101 deletions(-) diff --git a/packages/app-staking/src/Account/Nominating.tsx b/packages/app-staking/src/Account/Nominating.tsx index 4b81ca0474..0770726240 100644 --- a/packages/app-staking/src/Account/Nominating.tsx +++ b/packages/app-staking/src/Account/Nominating.tsx @@ -3,10 +3,10 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { I18nProps } from '@polkadot/ui-app/types'; +import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; import React from 'react'; -import { Button, Input, InputAddress, Modal, TxButton } from '@polkadot/ui-app'; -import keyring from '@polkadot/ui-keyring'; +import { Button, InputAddress, Modal, TxButton } from '@polkadot/ui-app'; import translate from '../translate'; @@ -15,19 +15,16 @@ type Props = I18nProps & { isOpen: boolean, onClose: () => void, intentions: Array, - stashId: string + stashId: string, + targets: Array }; type State = { - isNomineeValid: boolean, - isAddressFormatValid: boolean, nominees: Array }; class Nominating extends React.PureComponent { state: State = { - isNomineeValid: false, - isAddressFormatValid: false, nominees: [] }; @@ -53,7 +50,7 @@ class Nominating extends React.PureComponent { renderButtons () { const { accountId, onClose, t } = this.props; - const { isNomineeValid, nominees } = this.state; + const { nominees } = this.state; return ( @@ -66,7 +63,7 @@ class Nominating extends React.PureComponent { { } renderContent () { - const { accountId, stashId, t } = this.props; - const { isNomineeValid, nominees } = this.state; + const { accountId, stashId, t, targets } = this.props; return ( <> - {t('Nominate Validator')} + {t('Nominate Validators')} { isDisabled label={t('stash account')} /> - - {this.renderErrors()} ); } - private renderErrors () { - const { t } = this.props; - const { isNomineeValid, isAddressFormatValid } = this.state; - const hasError = !isNomineeValid || !isAddressFormatValid; - - if (!hasError) { - return null; - } - - return ( -
- { - !isNomineeValid && isAddressFormatValid - ? t('The address you input is not intending to stake, and is therefore invalid. Please try again with a validator address.') - : null - } - { - !isAddressFormatValid - ? t('The address does not conform to a recognized address format. Please make sure you enter a valid address.') - : null - } -
- ); - } - - private onChangeNominee = (nominee: string) => { - // const { intentions } = this.props; - - let isAddressFormatValid = false; - - try { - keyring.decodeAddress(nominee); - - isAddressFormatValid = true; - } catch (err) { - console.error(err); - } - - this.setState({ - isNomineeValid: isAddressFormatValid, // intentions.includes(nominee), - isAddressFormatValid, - nominees: [nominee] - }); + private onChangeNominees = (nominees: Array) => { + this.setState({ nominees }); } } diff --git a/packages/app-staking/src/Account/index.tsx b/packages/app-staking/src/Account/index.tsx index 16eb7d0bc9..871e57cc0e 100644 --- a/packages/app-staking/src/Account/index.tsx +++ b/packages/app-staking/src/Account/index.tsx @@ -5,6 +5,7 @@ import { DerivedBalancesMap } from '@polkadot/api-derive/types'; import { I18nProps } from '@polkadot/ui-app/types'; import { ApiProps } from '@polkadot/ui-api/types'; +import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; import { Nominators } from '../types'; import React from 'react'; @@ -22,15 +23,16 @@ type Props = ApiProps & I18nProps & { accountId: string, balances: DerivedBalancesMap, balanceArray: (_address: AccountId | string) => Array | undefined, + intentions: Array, + isValidator: boolean, name: string, + nominators: Nominators, session_nextKeyFor?: Option, staking_bonded?: Option, staking_ledger?: Option, staking_stakers?: Exposure, staking_validators?: [ValidatorPrefs], - intentions: Array, - nominators: Nominators, - isValidator: boolean, + targets: Array, validators: Array }; @@ -57,10 +59,7 @@ class Account extends React.PureComponent { stashId: null }; - static getDerivedStateFromProps ({ session_nextKeyFor, staking_bonded, staking_ledger }: Props): Partial { - - // console.error('staking_stakers', JSON.stringify(staking_stakers)); - + static getDerivedStateFromProps ({ session_nextKeyFor, staking_bonded, staking_ledger }: Props, state: State): Partial { return { bondedId: staking_bonded && staking_bonded.isSome ? staking_bonded.unwrap().toString() @@ -256,7 +255,7 @@ class Account extends React.PureComponent { } private renderNominating () { - const { accountId, intentions } = this.props; + const { accountId, intentions, targets } = this.props; const { isNominateOpen, stashId } = this.state; if (!stashId) { @@ -270,6 +269,7 @@ class Account extends React.PureComponent { onClose={this.toggleNominate} intentions={intentions} stashId={stashId} + targets={targets} /> ); } diff --git a/packages/app-staking/src/Overview/Address.tsx b/packages/app-staking/src/Overview/Address.tsx index 4ee96ea1bb..47471911bf 100644 --- a/packages/app-staking/src/Overview/Address.tsx +++ b/packages/app-staking/src/Overview/Address.tsx @@ -29,23 +29,40 @@ type Props = I18nProps & { }; type State = { + stashId: string | null, badgeExpanded: boolean; }; class Address extends React.PureComponent { state: State = { + stashId: null, badgeExpanded: false }; + static getDerivedStateFromProps ({ staking_ledger }: Props): State | null { + if (!staking_ledger || staking_ledger.isNone) { + return null; + } + + return { + stashId: staking_ledger.unwrap().stash.toString() + } as State; + } + render () { - const { address, balanceArray, isAuthor, lastBlock } = this.props; + const { balanceArray, isAuthor, lastBlock } = this.props; + const { stashId } = this.state; + + if (!stashId) { + return null; + } return ( -
+
@@ -63,18 +80,23 @@ class Address extends React.PureComponent { } private getDisplayName = (): string | undefined => { - const { address, defaultName } = this.props; + const { defaultName } = this.props; + const { stashId } = this.state; - const pair = keyring.getAccount(address).isValid() - ? keyring.getAccount(address) - : keyring.getAddress(address); + if (!stashId) { + return defaultName; + } + + const pair = keyring.getAccount(stashId).isValid() + ? keyring.getAccount(stashId) + : keyring.getAddress(stashId); return pair.isValid() ? pair.getMeta().name : defaultName; } - private onClickBadge = (): void => { + private toggleBadge = (): void => { const { badgeExpanded } = this.state; this.setState({ badgeExpanded: !badgeExpanded }); @@ -111,11 +133,8 @@ class Address extends React.PureComponent { } private renderOffline () { - const { recentlyOffline, staking_ledger, t } = this.props; - const { badgeExpanded } = this.state; - const stashId: string | null = staking_ledger && staking_ledger.isSome - ? staking_ledger.unwrap().stash.toString() - : null; + const { recentlyOffline, t } = this.props; + const { badgeExpanded, stashId } = this.state; if (!stashId || !recentlyOffline[stashId]) { return null; @@ -128,7 +147,7 @@ class Address extends React.PureComponent { return (
{count.toString()} diff --git a/packages/app-staking/src/Overview/CurrentList.tsx b/packages/app-staking/src/Overview/CurrentList.tsx index acbe2e81c3..103de7b25c 100644 --- a/packages/app-staking/src/Overview/CurrentList.tsx +++ b/packages/app-staking/src/Overview/CurrentList.tsx @@ -76,7 +76,7 @@ class CurrentList extends React.PureComponent { } })} - {this.renderColumn(current, t('validator'))} + {this.renderColumn(current, t('validator (stash)'))} ); } @@ -87,7 +87,7 @@ class CurrentList extends React.PureComponent { return ( <>

{t('next up')}

- {this.renderColumn(next, t('intention'))} + {this.renderColumn(next, t('intention (stash)'))} ); } diff --git a/packages/app-staking/src/StakeList.tsx b/packages/app-staking/src/StakeList.tsx index 7c9ce928d8..e18231c6db 100644 --- a/packages/app-staking/src/StakeList.tsx +++ b/packages/app-staking/src/StakeList.tsx @@ -7,9 +7,11 @@ import { ComponentProps } from './types'; import React from 'react'; import keyring from '@polkadot/ui-keyring'; +import createOption from '@polkadot/ui-keyring/options/item'; import Account from './Account'; import translate from './translate'; +import { KeyringSectionOption } from '@polkadot/ui-keyring/options/types'; type Props = I18nProps & ComponentProps; @@ -33,6 +35,7 @@ class StakeList extends React.PureComponent { key={address} name={name} nominators={nominators} + targets={this.getTargetOptions()} validators={validators} /> ); @@ -40,6 +43,21 @@ class StakeList extends React.PureComponent {
); } + + private getTargetOptions (): Array { + const { targets } = this.props; + + return targets.map((stashId) => { + const pair = keyring.getAccount(stashId).isValid() + ? keyring.getAccount(stashId) + : keyring.getAddress(stashId); + const name = pair.isValid() + ? pair.getMeta().name + : undefined; + + return createOption(stashId, name); + }); + } } export default translate(StakeList); diff --git a/packages/app-staking/src/index.tsx b/packages/app-staking/src/index.tsx index ca2c97c275..db6bd46f9b 100644 --- a/packages/app-staking/src/index.tsx +++ b/packages/app-staking/src/index.tsx @@ -33,6 +33,7 @@ type State = { intentions: Array, nominators: Nominators, tabs: Array, + targets: Array, validators: Array }; @@ -57,13 +58,12 @@ class App extends React.PureComponent { text: t('Account Actions') } ], + targets: [], validators: [] }; } static getDerivedStateFromProps ({ staking_controllers = [[], []], session_validators = [], staking_nominators = [[], []] }: Props): State { - console.error(staking_controllers[0].map((id) => id.toString())); - return { intentions: staking_controllers[1].filter((optId) => optId.isSome).map((accountId) => accountId.unwrap().toString() @@ -75,6 +75,7 @@ class App extends React.PureComponent { return result; }, {} as Nominators), + targets: staking_controllers[0].map((accountId) => accountId.toString()), validators: session_validators.map((authorityId) => authorityId.toString() ) @@ -107,7 +108,7 @@ class App extends React.PureComponent { private renderComponent (Component: React.ComponentType) { return (): React.ReactNode => { - const { intentions, nominators, validators } = this.state; + const { intentions, nominators, targets, validators } = this.state; const { balances = {} } = this.props; return ( @@ -116,6 +117,7 @@ class App extends React.PureComponent { balanceArray={this.balanceArray} intentions={intentions} nominators={nominators} + targets={targets} validators={validators} /> ); diff --git a/packages/app-staking/src/types.ts b/packages/app-staking/src/types.ts index 54193982d4..e0d6de2cba 100644 --- a/packages/app-staking/src/types.ts +++ b/packages/app-staking/src/types.ts @@ -16,6 +16,7 @@ export type ComponentProps = { balanceArray: (_address: AccountId | string) => Array | undefined, intentions: Array, nominators: Nominators, + targets: Array, validators: Array }; diff --git a/packages/ui-app/src/Dropdown.tsx b/packages/ui-app/src/Dropdown.tsx index d5111bd32c..0e55093bf6 100644 --- a/packages/ui-app/src/Dropdown.tsx +++ b/packages/ui-app/src/Dropdown.tsx @@ -18,11 +18,13 @@ type Props