Add BondedRx component & display bonded value, refactor RecentlyOffline (#923)
* recently offline on own accounts * wip bonded display * RxBonded component * travis-ci * import mistake * redo * RRemove balance (overview) & index (accounts) * Remove session.validators * Re-add displaying only the last offline block * Small setState cleanup (+ State in generic)
This commit is contained in:
parent
7cb6ba12a0
commit
56aef9398b
@ -110,6 +110,7 @@ class Creator extends React.PureComponent<Props, State> {
|
||||
? address
|
||||
: ''
|
||||
}
|
||||
withBonded
|
||||
/>
|
||||
{this.renderInput()}
|
||||
</div>
|
||||
|
||||
@ -43,6 +43,7 @@ class Creator extends React.PureComponent<Props, State> {
|
||||
<AddressSummary
|
||||
className='shrink'
|
||||
value={address}
|
||||
withBonded
|
||||
/>
|
||||
{this.renderInput()}
|
||||
</div>
|
||||
|
||||
@ -93,6 +93,7 @@ class Editor extends React.PureComponent<Props, State> {
|
||||
<AddressSummary
|
||||
className='shrink'
|
||||
value={address || ''}
|
||||
withBonded
|
||||
/>
|
||||
<div className='grow'>
|
||||
<div className='ui--row'>
|
||||
|
||||
@ -91,6 +91,9 @@ class Account extends React.PureComponent<Props, State> {
|
||||
name={name}
|
||||
value={accountId}
|
||||
identIconSize={96}
|
||||
withBonded
|
||||
withIndex={false}
|
||||
withNonce={false}
|
||||
>
|
||||
<div className='staking--Account-expand'>
|
||||
{this.renderButtons()}
|
||||
@ -205,7 +208,8 @@ class Account extends React.PureComponent<Props, State> {
|
||||
<AddressMini
|
||||
key={index}
|
||||
value={nomineeId}
|
||||
withBalance
|
||||
withBalance={false}
|
||||
withBonded
|
||||
/>
|
||||
))
|
||||
}
|
||||
@ -280,7 +284,7 @@ class Account extends React.PureComponent<Props, State> {
|
||||
return (
|
||||
<div className='staking--Account-detail'>
|
||||
<label className='staking--label'>{t('stash')}</label>
|
||||
<AddressMini value={stashId} />
|
||||
<AddressMini withBalance={false} withBonded value={stashId} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -6,13 +6,14 @@ import { DerivedBalancesMap } from '@polkadot/api-derive/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { Nominators, RecentlyOfflineMap } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { AccountId, Balance, Option, StakingLedger } from '@polkadot/types';
|
||||
import { withCalls, withMulti } from '@polkadot/ui-api/with';
|
||||
import { AddressMini, AddressRow } from '@polkadot/ui-app';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { formatBalance, formatNumber } from '@polkadot/util';
|
||||
import { formatBalance } from '@polkadot/util';
|
||||
|
||||
import RecentlyOffline from '../RecentlyOffline';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
@ -88,6 +89,8 @@ class Address extends React.PureComponent<Props, State> {
|
||||
extraInfo={stashActive ? `bonded ${stashActive}` : undefined}
|
||||
name={this.getDisplayName()}
|
||||
value={stashId}
|
||||
withBalance={false}
|
||||
withBonded
|
||||
withCopy={false}
|
||||
withNonce={false}
|
||||
>
|
||||
@ -122,12 +125,6 @@ class Address extends React.PureComponent<Props, State> {
|
||||
: defaultName;
|
||||
}
|
||||
|
||||
private toggleBadge = (): void => {
|
||||
const { badgeExpanded } = this.state;
|
||||
|
||||
this.setState({ badgeExpanded: !badgeExpanded });
|
||||
}
|
||||
|
||||
private renderKeys () {
|
||||
const { t } = this.props;
|
||||
const { bondedId, sessionId } = this.state;
|
||||
@ -180,7 +177,7 @@ class Address extends React.PureComponent<Props, State> {
|
||||
<AddressMini
|
||||
key={accountId.toString()}
|
||||
value={accountId}
|
||||
withBalance
|
||||
withBonded
|
||||
/>
|
||||
)}
|
||||
</details>
|
||||
@ -188,35 +185,17 @@ class Address extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
private renderOffline () {
|
||||
const { recentlyOffline, t } = this.props;
|
||||
const { badgeExpanded, stashId } = this.state;
|
||||
const { recentlyOffline } = this.props;
|
||||
const { stashId } = this.state;
|
||||
|
||||
if (!stashId || !recentlyOffline[stashId]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const offline = recentlyOffline[stashId];
|
||||
const count = offline.reduce((total, { count }) => total.add(count), new BN(0));
|
||||
|
||||
const blockNumbers = offline.map(({ blockNumber }) => `#${formatNumber(blockNumber)}`);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={['recentlyOffline', badgeExpanded ? 'expand' : ''].join(' ')}
|
||||
onClick={this.toggleBadge}
|
||||
>
|
||||
<div className='badge'>
|
||||
{count.toString()}
|
||||
</div>
|
||||
<div className='detail'>
|
||||
{t('Reported offline {{count}} times, last at {{blockNumber}}', {
|
||||
replace: {
|
||||
count: count.toString(),
|
||||
blockNumber: blockNumbers[blockNumbers.length - 1]
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<RecentlyOffline offline={offline} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,48 +85,7 @@
|
||||
}
|
||||
|
||||
.recentlyOffline {
|
||||
position: absolute;
|
||||
bottom: 0.75rem;
|
||||
font-size: 12px;
|
||||
cursor: help;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
right: 0.75rem;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
background: red;
|
||||
color: #eee;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2);
|
||||
transition: all ease .2s;
|
||||
|
||||
& > * {
|
||||
line-height: 22px;
|
||||
overflow: hidden;
|
||||
transition: all ease 0.25;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-weight: bold;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.detail {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&.expand {
|
||||
width: 300px;
|
||||
|
||||
.badge {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.detail {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
packages/app-staking/src/RecentlyOffline.tsx
Normal file
60
packages/app-staking/src/RecentlyOffline.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
// Copyright 2017-2019 @polkadot/app-staking 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 { OfflineStatus } from './types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
offline: Array<OfflineStatus>
|
||||
};
|
||||
|
||||
type State = {
|
||||
isOpen: boolean
|
||||
};
|
||||
|
||||
class RecentlyOffline extends React.PureComponent<Props, State> {
|
||||
state: State = {
|
||||
isOpen: false
|
||||
};
|
||||
|
||||
render () {
|
||||
const { offline, t } = this.props;
|
||||
const { isOpen } = this.state;
|
||||
|
||||
const count = offline.reduce((total, { count }) => total.add(count), new BN(0));
|
||||
const blockNumbers = offline.map(({ blockNumber }) => `#${formatNumber(blockNumber)}`);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={['staking--Account-recentlyOffline', isOpen ? 'expand' : ''].join(' ')}
|
||||
onClick={this.toggleOpen}
|
||||
>
|
||||
<div className='badge'>
|
||||
{count.toString()}
|
||||
</div>
|
||||
<div className='detail'>
|
||||
{t('Reported offline {{count}} times, last at {{blockNumber}}', {
|
||||
replace: {
|
||||
count,
|
||||
blockNumber: blockNumbers[blockNumbers.length - 1]
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private toggleOpen = (): void => {
|
||||
this.setState(({ isOpen }) => ({
|
||||
isOpen: !isOpen
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(RecentlyOffline);
|
||||
@ -131,3 +131,48 @@
|
||||
margin-bottom: -0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.staking--Account-recentlyOffline {
|
||||
position: absolute;
|
||||
bottom: 0.75rem;
|
||||
font-size: 12px;
|
||||
cursor: help;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
right: 0.75rem;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
background: red;
|
||||
color: #eee;
|
||||
border-radius: 16px;
|
||||
box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2);
|
||||
transition: all ease .2s;
|
||||
|
||||
& > * {
|
||||
line-height: 22px;
|
||||
overflow: hidden;
|
||||
transition: all ease 0.25;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-weight: bold;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.detail {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
&.expand {
|
||||
width: 300px;
|
||||
|
||||
.badge {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.detail {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { AccountId, AccountIndex, Address, Balance } from '@polkadot/types';
|
||||
|
||||
import { classes, toShortAddress } from './util';
|
||||
import BalanceDisplay from './Balance';
|
||||
import BondedDisplay from './Bonded';
|
||||
import IdentityIcon from './IdentityIcon';
|
||||
|
||||
type Props = BareProps & {
|
||||
@ -19,7 +20,8 @@ type Props = BareProps & {
|
||||
isShort?: boolean,
|
||||
value?: AccountId | AccountIndex | Address | string,
|
||||
withAddress?: boolean,
|
||||
withBalance?: boolean
|
||||
withBalance?: boolean,
|
||||
withBonded?: boolean
|
||||
};
|
||||
|
||||
export default class AddressMini extends React.PureComponent<Props> {
|
||||
@ -46,6 +48,7 @@ export default class AddressMini extends React.PureComponent<Props> {
|
||||
{children}
|
||||
</div>
|
||||
{this.renderBalance()}
|
||||
{this.renderBonded()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -77,4 +80,20 @@ export default class AddressMini extends React.PureComponent<Props> {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderBonded () {
|
||||
const { value, withBonded = false } = this.props;
|
||||
|
||||
if (!withBonded || !value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<BondedDisplay
|
||||
className='ui--AddressSummary-balance'
|
||||
label=''
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ class AddressRow extends AddressSummary {
|
||||
<div className='ui--AddressRow-details'>
|
||||
{this.renderAddress()}
|
||||
{this.renderBalance()}
|
||||
{this.renderExtra()}
|
||||
{this.renderBonded()}
|
||||
{this.renderNonce()}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -12,17 +12,20 @@ import BaseIdentityIcon from '@polkadot/ui-identicon';
|
||||
|
||||
import { classes, toShortAddress } from './util';
|
||||
import BalanceDisplay from './Balance';
|
||||
import BondedDisplay from './Bonded';
|
||||
import IdentityIcon from './IdentityIcon';
|
||||
import translate from './translate';
|
||||
|
||||
export type Props = I18nProps & {
|
||||
accounts_idAndIndex?: [AccountId?, AccountIndex?],
|
||||
balance?: Balance | Array<Balance>,
|
||||
bonded?: Balance | Array<Balance>,
|
||||
children?: React.ReactNode,
|
||||
extraInfo?: React.ReactNode,
|
||||
name?: string,
|
||||
value: AccountId | AccountIndex | Address | string | null,
|
||||
withBalance?: boolean,
|
||||
withBonded?: boolean,
|
||||
withIndex?: boolean,
|
||||
identIconSize?: number,
|
||||
isShort?: boolean,
|
||||
@ -50,7 +53,7 @@ class AddressSummary extends React.PureComponent<Props> {
|
||||
{this.renderAccountId()}
|
||||
{this.renderAccountIndex()}
|
||||
{this.renderBalance()}
|
||||
{this.renderExtra()}
|
||||
{this.renderBonded()}
|
||||
{this.renderNonce()}
|
||||
</div>
|
||||
{this.renderChildren()}
|
||||
@ -113,10 +116,10 @@ class AddressSummary extends React.PureComponent<Props> {
|
||||
}
|
||||
|
||||
protected renderAccountIndex () {
|
||||
const { accounts_idAndIndex = [] } = this.props;
|
||||
const { accounts_idAndIndex = [], withIndex = true } = this.props;
|
||||
const [, accountIndex] = accounts_idAndIndex;
|
||||
|
||||
if (!accountIndex) {
|
||||
if (!accountIndex || !withIndex) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -151,17 +154,21 @@ class AddressSummary extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
protected renderExtra () {
|
||||
const { extraInfo } = this.props;
|
||||
protected renderBonded () {
|
||||
const { accounts_idAndIndex = [], t, value, withBonded } = this.props;
|
||||
const [_accountId] = accounts_idAndIndex;
|
||||
const accountId = _accountId || value;
|
||||
|
||||
if (!extraInfo) {
|
||||
if (!withBonded || !accountId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='ui--AddressSummary-extra'>
|
||||
{extraInfo}
|
||||
</div>
|
||||
<BondedDisplay
|
||||
className='ui--AddressSummary-bonded'
|
||||
label={t('bonded ')}
|
||||
value={accountId}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
35
packages/ui-app/src/Bonded.tsx
Normal file
35
packages/ui-app/src/Bonded.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app 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 { BareProps } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { AccountId, AccountIndex, Address } from '@polkadot/types';
|
||||
import RxBonded from '@polkadot/ui-reactive/Bonded';
|
||||
|
||||
import { classes } from './util';
|
||||
|
||||
export type Props = BareProps & {
|
||||
label?: string,
|
||||
value?: AccountId | AccountIndex | Address | string | Uint8Array | null,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
export default class BondedDisplay extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { value, className, label, style } = this.props;
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<RxBonded
|
||||
className={classes('ui--Bonded', className)}
|
||||
label={label}
|
||||
value={value}
|
||||
style={style}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,8 @@ header .ui--Button-Group {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.ui--AddressMini .ui--Balance {
|
||||
.ui--AddressMini .ui--Balance,
|
||||
.ui--AddressMini .ui--Bonded {
|
||||
font-size: 0.75rem;
|
||||
margin-top: -0.5rem;
|
||||
text-align: right;
|
||||
@ -113,13 +114,20 @@ header .ui--Button-Group {
|
||||
|
||||
.ui--Balance,
|
||||
.ui--AddressSummary-balance,
|
||||
.ui--AddressSummary-extra,
|
||||
.ui--AddressSummary-bonded,
|
||||
.ui--AddressSummary-nonce {
|
||||
font-weight: 100;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.ui--AddressSummary-balance {
|
||||
.ui--Bonded {
|
||||
opacity: 1;
|
||||
color: green;
|
||||
}
|
||||
|
||||
.ui--AddressSummary-data+.ui--AddressSummary-balance,
|
||||
.ui--AddressSummary-data+.ui--AddressSummary-bonded,
|
||||
.ui--AddressSummary-data+.ui--AddressSummary-nonce {
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
|
||||
51
packages/ui-reactive/src/Bonded.tsx
Normal file
51
packages/ui-reactive/src/Bonded.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-reactive 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 { AccountId, AccountIndex, Address, Option, StakingLedger } from '@polkadot/types';
|
||||
import { BareProps, CallProps } from '@polkadot/ui-api/types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { withCalls } from '@polkadot/ui-api';
|
||||
import { formatBalance } from '@polkadot/util';
|
||||
|
||||
type Props = BareProps & CallProps & {
|
||||
children?: React.ReactNode,
|
||||
value?: AccountId | AccountIndex | Address | string | Uint8Array | null,
|
||||
label?: string,
|
||||
staking_ledger?: Option<StakingLedger>
|
||||
};
|
||||
|
||||
class BondedDisplay extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { children, className, label = '', style, staking_ledger } = this.props;
|
||||
|
||||
if (!staking_ledger || staking_ledger.isNone) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { active: bonded } = staking_ledger.unwrap();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
{label}{
|
||||
bonded
|
||||
? formatBalance(bonded)
|
||||
: '0'
|
||||
}{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withCalls<Props>(
|
||||
['query.staking.bonded', {
|
||||
paramName: 'value',
|
||||
transform: (value) => value.unwrapOr(null)
|
||||
}],
|
||||
['query.staking.ledger', { paramName: 'staking_bonded' }]
|
||||
)(BondedDisplay);
|
||||
Loading…
Reference in New Issue
Block a user