('sr25519');
const [publicKey, setPublicKey] = useState(EMPTY_KEY);
const [suri, setSuri] = useState('');
- const [type, setType] = useState('babe');
+ const [keyType, setKeyType] = useState('babe');
+ const keyTypeOpt = useMemo(() => [
+ { text: t('Aura'), value: 'aura' },
+ { text: t('Babe'), value: 'babe' },
+ { text: t('Grandpa'), value: 'gran' },
+ { text: t('I\'m Online'), value: 'imon' },
+ { text: t('Parachains'), value: 'para' }
+ ], [t]);
useEffect((): void => {
- setCrypto(CRYPTO_MAP[type][0]);
- }, [type]);
+ setCrypto(CRYPTO_MAP[keyType][0]);
+ }, [keyType]);
useEffect((): void => {
try {
@@ -56,13 +63,12 @@ function InjectKeys ({ isOpen = true, onClose, t }: Props): React.ReactElement {
+ const _onSubmit = (): void =>
queueRpc({
rpc: { section: 'author', method: 'insertKey' } as any,
- values: [type, suri, publicKey]
+ values: [keyType, suri, publicKey]
});
- };
- const _cryptoOptions = CRYPTO_MAP[type].map((value): { text: string; value: KeypairType } => ({
+ const _cryptoOptions = CRYPTO_MAP[keyType].map((value): { text: string; value: KeypairType } => ({
text: value === 'ed25519'
? t('ed25519, Edwards')
: t('sr15519, Schnorrkel'),
@@ -72,7 +78,6 @@ function InjectKeys ({ isOpen = true, onClose, t }: Props): React.ReactElement
@@ -84,15 +89,9 @@ function InjectKeys ({ isOpen = true, onClose, t }: Props): React.ReactElement
{t('This operation will submit the seed via an RPC call. Do not perform this operation on a public RPC node, but ensure that the node is local, connected to your validator and secure.')}
-
-
-
-
-
-
+
+
);
}
-
-export default translate(InjectKeys);
diff --git a/packages/app-staking/src/Actions/Account/InputValidateAmount.tsx b/packages/app-staking/src/Actions/Account/InputValidateAmount.tsx
index 51ad43dcf526..71986017ce09 100644
--- a/packages/app-staking/src/Actions/Account/InputValidateAmount.tsx
+++ b/packages/app-staking/src/Actions/Account/InputValidateAmount.tsx
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { DerivedBalances } from '@polkadot/api-derive/types';
+import { DerivedBalancesAll } from '@polkadot/api-derive/types';
import { I18nProps } from '@polkadot/react-components/types';
import BN from 'bn.js';
@@ -20,7 +20,7 @@ interface Props extends I18nProps {
function ValidateAmount ({ accountId, onError, value, t }: Props): React.ReactElement | null {
const { api } = useApi();
- const allBalances = useCall(api.derive.balances.all as any, [accountId]);
+ const allBalances = useCall(api.derive.balances.all as any, [accountId]);
const [error, setError] = useState(null);
useEffect((): void => {
diff --git a/packages/app-staking/src/Actions/Account/InputValidationController.tsx b/packages/app-staking/src/Actions/Account/InputValidationController.tsx
index ea0d30700a4a..c06e8b134cd8 100644
--- a/packages/app-staking/src/Actions/Account/InputValidationController.tsx
+++ b/packages/app-staking/src/Actions/Account/InputValidationController.tsx
@@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
import { AccountId, StakingLedger } from '@polkadot/types/interfaces';
import React, { useEffect, useState } from 'react';
@@ -10,9 +9,9 @@ import { Icon } from '@polkadot/react-components';
import { Option } from '@polkadot/types';
import { useApi, useCall } from '@polkadot/react-hooks';
-import translate from '../../translate';
+import { useTranslation } from '../../translate';
-interface Props extends I18nProps {
+interface Props {
accountId: string | null;
controllerId: string | null;
defaultController?: string;
@@ -22,25 +21,20 @@ interface Props extends I18nProps {
const DISTINCT = 'Distinct stash and controller accounts are recommended to ensure fund security.';
-function ValidateController ({ accountId, controllerId, defaultController, isUnsafeChain, onError, t }: Props): React.ReactElement | null {
+export default function ValidateController ({ accountId, controllerId, defaultController, isUnsafeChain, onError }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const { api } = useApi();
const bondedId = useCall(api.query.staking.bonded, [controllerId], {
- transform: (value: Option): string | null => {
- const extracted = value.unwrapOr(null);
-
- return extracted
- ? extracted.toString()
- : null;
- }
+ transform: (value: Option): string | null =>
+ value.isSome
+ ? value.unwrap().toString()
+ : null
});
- const stashId = useCall(api.query.staking.ledger, [controllerId], {
- transform: (value: Option): string | null => {
- const extracted = value.unwrapOr({ stash: null }).stash;
-
- return extracted
- ? extracted.toString()
- : null;
- }
+ const stashId = useCall(controllerId ? api.query.staking.ledger : null, [controllerId], {
+ transform: (value: Option): string | null =>
+ value.isSome
+ ? value.unwrap().stash.toString()
+ : null
});
const [error, setError] = useState(null);
@@ -77,5 +71,3 @@ function ValidateController ({ accountId, controllerId, defaultController, isUns
);
}
-
-export default translate(ValidateController);
diff --git a/packages/app-staking/src/Actions/Account/InputValidationUnstakeThreshold.tsx b/packages/app-staking/src/Actions/Account/InputValidationUnstakeThreshold.tsx
index 754c49d4adaa..7f78f64337ac 100644
--- a/packages/app-staking/src/Actions/Account/InputValidationUnstakeThreshold.tsx
+++ b/packages/app-staking/src/Actions/Account/InputValidationUnstakeThreshold.tsx
@@ -2,20 +2,19 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
-
import BN from 'bn.js';
import React, { useEffect, useState } from 'react';
import { Icon } from '@polkadot/react-components';
-import translate from '../../translate';
+import { useTranslation } from '../../translate';
-interface Props extends I18nProps {
+interface Props {
unstakeThreshold: BN | undefined;
onError: (error: string | null) => void;
}
-function InputValidationUnstakeThreshold ({ onError, t, unstakeThreshold }: Props): React.ReactElement | null {
+export default function InputValidationUnstakeThreshold ({ onError, unstakeThreshold }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const [error, setError] = useState(null);
useEffect((): void => {
@@ -45,5 +44,3 @@ function InputValidationUnstakeThreshold ({ onError, t, unstakeThreshold }: Prop
);
}
-
-export default translate(InputValidationUnstakeThreshold);
diff --git a/packages/app-staking/src/Actions/Account/Nominate.tsx b/packages/app-staking/src/Actions/Account/Nominate.tsx
index ea9b835a927c..53641f2c0bcd 100644
--- a/packages/app-staking/src/Actions/Account/Nominate.tsx
+++ b/packages/app-staking/src/Actions/Account/Nominate.tsx
@@ -3,17 +3,17 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedStakingOverview } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
-import { AddressMulti, Button, InputAddress, Modal, TxButton } from '@polkadot/react-components';
+import { InputAddressMulti, InputAddress, Modal, TxButton } from '@polkadot/react-components';
import { useFavorites } from '@polkadot/react-hooks';
import { STORE_FAVS_BASE } from '../../constants';
-import translate from '../../translate';
+import { useTranslation } from '../../translate';
-interface Props extends I18nProps {
+interface Props {
+ className?: string;
controllerId: string;
next: string[];
nominees?: string[];
@@ -24,7 +24,8 @@ interface Props extends I18nProps {
const MAX_NOMINEES = 16;
-function Nominate ({ className, controllerId, nominees, onClose, next, stakingOverview, stashId, t }: Props): React.ReactElement | null {
+function Nominate ({ className, controllerId, nominees, onClose, next, stakingOverview, stashId }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const [favorites] = useFavorites(STORE_FAVS_BASE);
const [validators, setValidators] = useState([]);
const [selection, setSelection] = useState([]);
@@ -61,7 +62,6 @@ function Nominate ({ className, controllerId, nominees, onClose, next, stakingOv
-
-
-
-
-
-
-
+
+
);
}
-export default translate(
- styled(Nominate)`
- .shortlist {
- display: flex;
- flex-wrap: wrap;
- justify-content: center;
-
- .candidate {
- border: 1px solid #eee;
- border-radius: 0.25rem;
- margin: 0.25rem;
- padding-bottom: 0.25rem;
- padding-right: 0.5rem;
- position: relative;
-
- &::after {
- content: '';
- position: absolute;
- top: 0;
- right: 0;
- border-color: transparent;
- border-style: solid;
- border-radius: 0.25em;
- border-width: 0.25em;
- }
-
- &.isAye {
- background: #fff;
- border-color: #ccc;
- }
-
- &.member::after {
- border-color: green;
- }
-
- &.runnerup::after {
- border-color: steelblue;
- }
-
- .ui--AddressMini-icon {
- z-index: 1;
- }
-
- .candidate-right {
- text-align: right;
- }
+export default styled(Nominate)`
+ .shortlist {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+
+ .candidate {
+ border: 1px solid #eee;
+ border-radius: 0.25rem;
+ margin: 0.25rem;
+ padding-bottom: 0.25rem;
+ padding-right: 0.5rem;
+ position: relative;
+
+ &::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ border-color: transparent;
+ border-style: solid;
+ border-radius: 0.25em;
+ border-width: 0.25em;
+ }
+
+ &.isAye {
+ background: #fff;
+ border-color: #ccc;
+ }
+
+ &.member::after {
+ border-color: green;
+ }
+
+ &.runnerup::after {
+ border-color: steelblue;
+ }
+
+ .ui--AddressMini-icon {
+ z-index: 1;
+ }
+
+ .candidate-right {
+ text-align: right;
}
}
- `
-);
+ }
+`;
diff --git a/packages/app-staking/src/Actions/Account/SetControllerAccount.tsx b/packages/app-staking/src/Actions/Account/SetControllerAccount.tsx
index 8759f7e7c363..490b2e440246 100644
--- a/packages/app-staking/src/Actions/Account/SetControllerAccount.tsx
+++ b/packages/app-staking/src/Actions/Account/SetControllerAccount.tsx
@@ -6,7 +6,7 @@ import { ApiProps } from '@polkadot/react-api/types';
import { I18nProps } from '@polkadot/react-components/types';
import React from 'react';
-import { Button, Icon, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components';
+import { Icon, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components';
import { withApi, withMulti } from '@polkadot/react-api/hoc';
import translate from '../../translate';
@@ -45,7 +45,6 @@ class SetControllerAccount extends TxComponent {
@@ -81,27 +80,19 @@ class SetControllerAccount extends TxComponent {
onError={this.onControllerError}
/>
-
-
-
-
-
-
+
+
);
diff --git a/packages/app-staking/src/Actions/Account/SetRewardDestination.tsx b/packages/app-staking/src/Actions/Account/SetRewardDestination.tsx
index 9439e694abc5..6254007d6ecb 100644
--- a/packages/app-staking/src/Actions/Account/SetRewardDestination.tsx
+++ b/packages/app-staking/src/Actions/Account/SetRewardDestination.tsx
@@ -5,7 +5,7 @@
import { I18nProps } from '@polkadot/react-components/types';
import React from 'react';
-import { Button, Dropdown, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components';
+import { Dropdown, InputAddress, Modal, TxButton, TxComponent } from '@polkadot/react-components';
import { withMulti } from '@polkadot/react-api/hoc';
import translate from '../../translate';
@@ -39,31 +39,22 @@ class SetRewardDestination extends TxComponent {
{this.renderContent()}
-
-
-
-
-
-
+
+
);
diff --git a/packages/app-staking/src/Actions/Account/SetSessionKey.tsx b/packages/app-staking/src/Actions/Account/SetSessionKey.tsx
index 857e97ce07ff..c5990454691f 100644
--- a/packages/app-staking/src/Actions/Account/SetSessionKey.tsx
+++ b/packages/app-staking/src/Actions/Account/SetSessionKey.tsx
@@ -2,16 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
-
import React, { useState } from 'react';
-import { Button, InputAddress, Input, Modal, TxButton } from '@polkadot/react-components';
+import { Input, InputAddress, Modal, TxButton } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import ValidationSessionKey from './InputValidationSessionKey';
-import translate from '../../translate';
+import { useTranslation } from '../../translate';
-interface Props extends I18nProps {
+interface Props {
controllerId: string;
isOpen: boolean;
onClose: () => void;
@@ -21,7 +19,8 @@ interface Props extends I18nProps {
const EMPTY_PROOF = new Uint8Array();
-function SetSessionKey ({ controllerId, isOpen, onClose, sessionIds, stashId, t }: Props): React.ReactElement | null {
+export default function SetSessionKey ({ controllerId, isOpen, onClose, sessionIds, stashId }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const { isSubstrateV2 } = useApi();
const [keysError, setKeysError] = useState(null);
const [keys, setKeys] = useState(
@@ -42,7 +41,6 @@ function SetSessionKey ({ controllerId, isOpen, onClose, sessionIds, stashId, t
@@ -82,37 +80,26 @@ function SetSessionKey ({ controllerId, isOpen, onClose, sessionIds, stashId, t
)
}
-
-
-
-
-
-
+
+
);
}
-
-export default translate(SetSessionKey);
diff --git a/packages/app-staking/src/Actions/Account/Unbond.tsx b/packages/app-staking/src/Actions/Account/Unbond.tsx
index 7bb36dc77331..75e7e79a5bd8 100644
--- a/packages/app-staking/src/Actions/Account/Unbond.tsx
+++ b/packages/app-staking/src/Actions/Account/Unbond.tsx
@@ -11,7 +11,7 @@ import BN from 'bn.js';
import React from 'react';
import styled from 'styled-components';
import { Option } from '@polkadot/types';
-import { AddressInfo, Button, InputAddress, InputBalance, Modal, TxButton, TxComponent } from '@polkadot/react-components';
+import { AddressInfo, InputAddress, InputBalance, Modal, TxButton, TxComponent } from '@polkadot/react-components';
import { withCalls, withApi, withMulti } from '@polkadot/react-api/hoc';
import translate from '../../translate';
@@ -63,31 +63,22 @@ class Unbond extends TxComponent {
{this.renderContent()}
-
-
-
-
-
-
+
+
);
diff --git a/packages/app-staking/src/Actions/Account/Validate.tsx b/packages/app-staking/src/Actions/Account/Validate.tsx
index 619a3c354278..703519cc74d3 100644
--- a/packages/app-staking/src/Actions/Account/Validate.tsx
+++ b/packages/app-staking/src/Actions/Account/Validate.tsx
@@ -2,18 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196 } from '@polkadot/types/interfaces';
import { ApiProps } from '@polkadot/react-api/types';
import { I18nProps } from '@polkadot/react-components/types';
import BN from 'bn.js';
import React from 'react';
-import { registry } from '@polkadot/react-api';
import { withApi, withMulti } from '@polkadot/react-api/hoc';
-import { Button, InputAddress, InputBalance, InputNumber, Modal, TxButton, TxComponent } from '@polkadot/react-components';
-import { createType } from '@polkadot/types';
+import { InputAddress, InputNumber, Modal, TxButton, TxComponent } from '@polkadot/react-components';
-import InputValidationUnstakeThreshold from './InputValidationUnstakeThreshold';
import translate from '../../translate';
interface Props extends ApiProps, I18nProps {
@@ -21,15 +17,10 @@ interface Props extends ApiProps, I18nProps {
isOpen: boolean;
onClose: () => void;
stashId: string;
- validatorPrefs?: ValidatorPrefs | ValidatorPrefsTo145 | ValidatorPrefsTo196;
}
interface State {
- hasCommission: boolean;
commission: BN;
- unstakeThreshold: BN;
- unstakeThresholdError: string | null;
- validatorPayment: BN;
}
const COMM_MUL = new BN(10000000);
@@ -37,11 +28,7 @@ const MAX_COMM = new BN(100);
class Validate extends TxComponent {
public state: State = {
- hasCommission: !!(createType(registry, 'ValidatorPrefs').commission),
- commission: new BN(0),
- unstakeThreshold: new BN(3),
- unstakeThresholdError: null,
- validatorPayment: new BN(0)
+ commission: new BN(0)
};
// FIXME Borken with new InputBalance
@@ -85,7 +72,6 @@ class Validate extends TxComponent {
{this.renderContent()}
@@ -95,45 +81,28 @@ class Validate extends TxComponent {
}
private renderButtons (): React.ReactNode {
- const { controllerId, isSubstrateV2, onClose, t } = this.props;
- const { commission, hasCommission, unstakeThreshold, unstakeThresholdError, validatorPayment } = this.state;
+ const { controllerId, onClose, t } = this.props;
+ const { commission } = this.state;
return (
-
-
-
-
-
-
+
+
);
}
private renderContent (): React.ReactNode {
- const { controllerId, isSubstrateV2, stashId, t, validatorPrefs } = this.props;
- const { hasCommission, unstakeThreshold, unstakeThresholdError } = this.state;
- const defaultThreshold = validatorPrefs && (validatorPrefs as ValidatorPrefsTo145).unstakeThreshold && (validatorPrefs as ValidatorPrefsTo145).unstakeThreshold.toBn();
+ const { controllerId, stashId, t } = this.props;
return (
@@ -149,46 +118,15 @@ class Validate extends TxComponent {
isDisabled
label={t('controller account')}
/>
- {!isSubstrateV2 && (
- <>
-
-
- >
- )}
- {
- hasCommission
- ?
- :
- }
+
);
}
@@ -196,18 +134,6 @@ class Validate extends TxComponent {
private onChangeCommission = (commission?: BN): void => {
commission && this.setState({ commission: commission.mul(COMM_MUL) });
}
-
- private onChangePayment = (validatorPayment?: BN): void => {
- validatorPayment && this.setState({ validatorPayment });
- }
-
- private onChangeThreshold = (unstakeThreshold?: BN): void => {
- unstakeThreshold && this.setState({ unstakeThreshold });
- }
-
- private onUnstakeThresholdError = (unstakeThresholdError: string | null): void => {
- this.setState({ unstakeThresholdError });
- }
}
export default withMulti(
diff --git a/packages/app-staking/src/Actions/Account/index.tsx b/packages/app-staking/src/Actions/Account/index.tsx
index 7dde5c34fa02..659ac8072ff9 100644
--- a/packages/app-staking/src/Actions/Account/index.tsx
+++ b/packages/app-staking/src/Actions/Account/index.tsx
@@ -2,7 +2,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { DerivedBalances, DerivedStakingAccount, DerivedStakingOverview, DerivedHeartbeats } from '@polkadot/api-derive/types';
+import { DerivedBalancesAll, DerivedStakingAccount, DerivedStakingOverview, DerivedHeartbeats } from '@polkadot/api-derive/types';
import { AccountId, Exposure, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces';
import { Codec, ITuple } from '@polkadot/types/types';
@@ -89,13 +89,14 @@ function getStakeState (allAccounts: string[], allStashes: string[] | undefined,
function Account ({ allStashes, className, isOwnStash, next, onUpdateType, stakingOverview, stashId }: Props): React.ReactElement {
const { t } = useTranslation();
- const { api, isSubstrateV2 } = useApi();
+ const { api } = useApi();
const { allAccounts } = useAccounts();
const validateInfo = useCall(api.query.staking.validators, [stashId]);
- const balancesAll = useCall(api.derive.balances.all as any, [stashId]);
+ const balancesAll = useCall(api.derive.balances.all as any, [stashId]);
const stakingAccount = useCall(api.derive.staking.account as any, [stashId]);
const [{ controllerId, destination, hexSessionIdQueue, hexSessionIdNext, isLoading, isOwnController, isStashNominating, isStashValidating, nominees, sessionIds, validatorPrefs }, setStakeState] = useState({ controllerId: null, destination: 0, hexSessionIdNext: null, hexSessionIdQueue: null, isLoading: true, isOwnController: false, isStashNominating: false, isStashValidating: false, sessionIds: [] });
- const inactives = useInactives(stashId, nominees);
+ const [activeNoms, setActiveNoms] = useState([]);
+ const inactiveNoms = useInactives(stashId, nominees);
const [isBondExtraOpen, toggleBondExtra] = useToggle();
const [isInjectOpen, toggleInject] = useToggle();
const [isNominateOpen, toggleNominate] = useToggle();
@@ -122,6 +123,12 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
}
}, [allStashes, stakingAccount, stashId, validateInfo]);
+ useEffect((): void => {
+ if (nominees) {
+ setActiveNoms(nominees.filter((id): boolean => !inactiveNoms.includes(id)));
+ }
+ }, [inactiveNoms, nominees]);
+
return (
@@ -209,30 +216,32 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
)
: (
- {isStashNominating && nominees && (
+ {isStashNominating && (
<>
-
- {t('All Nominations ({{count}})', { replace: { count: nominees.length } })}
- {nominees.map((nomineeId, index): React.ReactNode => (
-
- ))}
-
- {inactives.length !== 0 && (
+ {activeNoms.length !== 0 && (
- {t('Inactive nominations ({{count}})', { replace: { count: inactives.length } })}
- {inactives.map((nomineeId, index): React.ReactNode => (
+ {t('Active nominations ({{count}})', { replace: { count: activeNoms.length } })}
+ {activeNoms.map((nomineeId, index): React.ReactNode => (
+
+ ))}
+
+ )}
+ {inactiveNoms.length !== 0 && (
+
+ {t('Inactive nominations ({{count}})', { replace: { count: inactiveNoms.length } })}
+ {inactiveNoms.map((nomineeId, index): React.ReactNode => (
- {(!sessionIds.length || (isSubstrateV2 && hexSessionIdNext === '0x'))
+ {(!sessionIds.length || hexSessionIdNext === '0x')
? (
- {isSubstrateV2 ? t('Change session keys') : t('Change session account')}
+ {t('Change session keys')}
}
{isStashNominating &&
@@ -367,7 +376,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, staki
{t('Set nominees')}
}
- {!isStashNominating && isSubstrateV2 &&
+ {!isStashNominating &&
{t('Inject session keys (advanced)')}
diff --git a/packages/app-staking/src/Actions/NewStake.tsx b/packages/app-staking/src/Actions/NewStake.tsx
index 0d6b188e7529..99ec88e56513 100644
--- a/packages/app-staking/src/Actions/NewStake.tsx
+++ b/packages/app-staking/src/Actions/NewStake.tsx
@@ -9,7 +9,7 @@ import { CalculateBalanceProps } from '../types';
import BN from 'bn.js';
import React from 'react';
import { SubmittableExtrinsic } from '@polkadot/api/promise/types';
-import { Button, Dropdown, InputAddress, InputBalanceBonded, Modal, TxButton, TxComponent } from '@polkadot/react-components';
+import { Dropdown, InputAddress, InputBalanceBonded, Modal, TxButton, TxComponent } from '@polkadot/react-components';
import { withApi, withMulti } from '@polkadot/react-api/hoc';
import translate from '../translate';
@@ -59,7 +59,6 @@ class NewStake extends TxComponent {
@@ -114,26 +113,18 @@ class NewStake extends TxComponent {
value={destination}
/>
-
-
-
-
-
-
+
+
);
diff --git a/packages/app-staking/src/Actions/index.tsx b/packages/app-staking/src/Actions/index.tsx
index 62b625811398..5e1936b12d5e 100644
--- a/packages/app-staking/src/Actions/index.tsx
+++ b/packages/app-staking/src/Actions/index.tsx
@@ -3,7 +3,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
import { AccountId, StakingLedger } from '@polkadot/types/interfaces';
import React, { useEffect, useState } from 'react';
@@ -13,10 +12,11 @@ import { Option } from '@polkadot/types';
import Account from './Account';
import StartStaking from './NewStake';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
allStashes: string[];
+ className?: string;
isVisible: boolean;
recentlyOnline?: DerivedHeartbeats;
next: string[];
@@ -47,7 +47,8 @@ function getStashes (allAccounts: string[], stashTypes: Record,
);
}
-function Actions ({ allStashes, className, isVisible, next, recentlyOnline, stakingOverview, t }: Props): React.ReactElement {
+export default function Actions ({ allStashes, className, isVisible, next, recentlyOnline, stakingOverview }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const queryBonded = useCall[]>(api.query.staking.bonded.multi as any, [allAccounts]);
@@ -109,5 +110,3 @@ function Actions ({ allStashes, className, isVisible, next, recentlyOnline, stak
);
}
-
-export default translate(Actions);
diff --git a/packages/app-staking/src/Overview/Address.tsx b/packages/app-staking/src/Overview/Address.tsx
index acdaeea33629..1297cf1ec2b6 100644
--- a/packages/app-staking/src/Overview/Address.tsx
+++ b/packages/app-staking/src/Overview/Address.tsx
@@ -2,36 +2,35 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { AccountId, Balance, Points, ValidatorPrefsTo196 } from '@polkadot/types/interfaces';
-import { DeriveAccountInfo, DerivedStakingQuery, DerivedHeartbeats } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
+import { AccountId, Balance, Points } from '@polkadot/types/interfaces';
+import { DeriveAccountInfo, DerivedStakingQuery, DerivedHeartbeatAuthor } from '@polkadot/api-derive/types';
import { ValidatorFilter } from '../types';
import BN from 'bn.js';
import React, { useEffect, useState } from 'react';
-import styled from 'styled-components';
+import ApiPromise from '@polkadot/api/promise';
import { AddressMini, AddressSmall, Badge, Icon } from '@polkadot/react-components';
-import { useCall, useApi } from '@polkadot/react-hooks';
+import { useApi, useCall } from '@polkadot/react-hooks';
import { FormatBalance } from '@polkadot/react-query';
import keyring from '@polkadot/ui-keyring';
import { formatNumber } from '@polkadot/util';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
- address: AccountId | string;
- authorsMap: Record;
+interface Props {
+ address: string;
className?: string;
defaultName: string;
filter: ValidatorFilter;
filterName: string;
hasQueries: boolean;
+ heartbeat?: DerivedHeartbeatAuthor;
+ isAuthor?: boolean;
isElected: boolean;
isFavorite: boolean;
- lastAuthors?: string[];
+ lastBlock?: string;
myAccounts: string[];
points?: Points;
- recentlyOnline?: DerivedHeartbeats;
toggleFavorite: (accountId: string) => void;
withNominations?: boolean;
}
@@ -46,102 +45,100 @@ interface StakingState {
stakeTotal?: BN;
stakeOther?: BN;
stakeOwn?: BN;
- stashId: string;
- validatorPayment?: BN;
}
-function Address ({ address, authorsMap, className, filter, filterName, hasQueries, isElected, isFavorite, lastAuthors, myAccounts, points, recentlyOnline, t, toggleFavorite, withNominations = true }: Props): React.ReactElement | null {
+function expandInfo ({ controllerId, nextSessionIds, stakers, validatorPrefs }: DerivedStakingQuery, myAccounts: string[], withNominations = true): StakingState {
+ const nominators = withNominations && stakers
+ ? stakers.others.map(({ who, value }): [AccountId, Balance] => [who, value.unwrap()])
+ : [];
+ const stakeTotal = (stakers && !stakers.total.isEmpty && stakers.total.unwrap()) || undefined;
+ const stakeOwn = (stakers && !stakers.own.isEmpty && stakers.own.unwrap()) || undefined;
+ const stakeOther = (stakeTotal && stakeOwn) ? stakeTotal.sub(stakeOwn) : undefined;
+ const commission = validatorPrefs?.commission?.unwrap();
+
+ return {
+ commission: commission
+ ? `${(commission.toNumber() / 10000000).toFixed(2)}%`
+ : undefined,
+ controllerId: controllerId?.toString(),
+ hasNominators: nominators.length !== 0,
+ isNominatorMe: nominators.some(([who]): boolean =>
+ myAccounts.includes(who.toString())
+ ),
+ nominators,
+ sessionId: nextSessionIds && nextSessionIds[0]?.toString(),
+ stakeOther,
+ stakeOwn,
+ stakeTotal
+ };
+}
+
+function checkFilter (filter: string, hasNominators: boolean, isElected: boolean, isNominatorMe: boolean, heartbeat?: DerivedHeartbeatAuthor): boolean {
+ return (filter === 'hasNominators' && !hasNominators) ||
+ (filter === 'noNominators' && hasNominators) ||
+ (filter === 'hasWarnings' && heartbeat?.isOnline) ||
+ (filter === 'noWarnings' && !heartbeat?.isOnline) ||
+ (filter === 'iNominated' && !isNominatorMe) ||
+ (filter === 'nextSet' && !isElected);
+}
+
+function checkVisibility (api: ApiPromise, address: string, filterName: string, info: DeriveAccountInfo | undefined): boolean {
+ let isVisible = false;
+ const filterLower = filterName.toLowerCase();
+
+ if (filterLower) {
+ if (info) {
+ const { identity, nickname, accountId, accountIndex } = info;
+
+ if (accountId?.toString().includes(filterName) || accountIndex?.toString().includes(filterName)) {
+ isVisible = true;
+ } else if (api.query.identity && api.query.identity.identityOf && identity?.display) {
+ isVisible = identity.display.toLowerCase().includes(filterLower);
+ } else if (nickname) {
+ isVisible = nickname.toLowerCase().includes(filterLower);
+ }
+ }
+
+ if (!isVisible) {
+ const account = keyring.getAddress(address);
+
+ isVisible = account?.meta?.name
+ ? account.meta.name.toLowerCase().includes(filterLower)
+ : false;
+ }
+ } else {
+ isVisible = true;
+ }
+
+ return isVisible;
+}
+
+export default function Address ({ address, className, filter, filterName, hasQueries, heartbeat, isAuthor, isElected, isFavorite, lastBlock, myAccounts, points, toggleFavorite, withNominations }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const { api } = useApi();
// FIXME Any horrors, caused by derive type mismatches
const info = useCall(api.derive.accounts.info as any, [address]);
const stakingInfo = useCall(api.derive.staking.query as any, [address]);
- const [hasActivity, setHasActivity] = useState(true);
- const [{ commission, hasNominators, isNominatorMe, nominators, stashId, stakeOwn, stakeOther, validatorPayment }, setStakingState] = useState({
- hasNominators: false,
- isNominatorMe: false,
- nominators: [],
- stashId: address.toString()
- });
+ const [{ commission, hasNominators, isNominatorMe, nominators, stakeOwn, stakeOther }, setStakingState] = useState({ hasNominators: false, isNominatorMe: false, nominators: [] });
const [isExpanded, setIsExpanded] = useState(false);
const [isVisible, setIsVisible] = useState(true);
useEffect((): void => {
- if (stakingInfo) {
- const { controllerId, nextSessionIds, stakers, stashId, validatorPrefs } = stakingInfo;
- const nominators = withNominations && stakers
- ? stakers.others.map(({ who, value }): [AccountId, Balance] => [who, value.unwrap()])
- : [];
- const stakeTotal = (stakers && !stakers.total.isEmpty && stakers.total.unwrap()) || undefined;
- const stakeOwn = (stakers && !stakers.own.isEmpty && stakers.own.unwrap()) || undefined;
- const stakeOther = (stakeTotal && stakeOwn) ? stakeTotal.sub(stakeOwn) : undefined;
- const commission = validatorPrefs?.commission?.unwrap();
-
- setStakingState({
- commission: commission
- ? `${(commission.toNumber() / 10000000).toFixed(2)}%`
- : undefined,
- controllerId: controllerId?.toString(),
- hasNominators: nominators.length !== 0,
- isNominatorMe: nominators.some(([who]): boolean =>
- myAccounts.includes(who.toString())
- ),
- nominators,
- sessionId: nextSessionIds && nextSessionIds[0]?.toString(),
- stashId: (stashId || address).toString(),
- stakeOther,
- stakeOwn,
- stakeTotal,
- validatorPayment: (validatorPrefs as any as ValidatorPrefsTo196)?.validatorPayment?.unwrap()
- });
- }
+ stakingInfo && setStakingState(
+ expandInfo(stakingInfo, myAccounts, withNominations)
+ );
}, [stakingInfo]);
useEffect((): void => {
- if (recentlyOnline && stashId && recentlyOnline[stashId]) {
- setHasActivity(recentlyOnline[stashId].isOnline);
- }
- }, [recentlyOnline, stashId]);
-
- useEffect((): void => {
- let isVisible = false;
- const filterLower = filterName.toLowerCase();
-
- if ((filter === 'hasNominators' && !hasNominators) || (filter === 'noNominators' && hasNominators) || (filter === 'hasWarnings' && hasActivity) || (filter === 'noWarnings' && !hasActivity) || (filter === 'iNominated' && !isNominatorMe) || (filter === 'nextSet' && !isElected)) {
- isVisible = true;
- } else if (filterLower) {
- if (info) {
- const { identity, nickname, accountId, accountIndex } = info;
-
- if (accountId?.toString().includes(filterName) || accountIndex?.toString().includes(filterName)) {
- isVisible = true;
- } else if (api.query.identity?.identityOf) {
- if (identity?.display) {
- isVisible = identity.display.toLowerCase().includes(filterLower);
- }
- } else if (nickname) {
- isVisible = nickname.toLowerCase().includes(filterLower);
- }
- }
-
- if (!isVisible) {
- const account = keyring.getAddress(address);
-
- isVisible = account?.meta?.name
- ? account.meta.name.toLowerCase().includes(filterLower)
- : false;
- }
- } else {
- isVisible = true;
- }
-
- setIsVisible(isVisible);
- }, [address, filter, filterName, info]);
+ setIsVisible(
+ checkFilter(filter, hasNominators, isElected, isNominatorMe, heartbeat) ||
+ checkVisibility(api, address, filterName, info)
+ );
+ }, [filter, filterName, heartbeat, info, hasNominators, isNominatorMe]);
- const lastBlockNumber = authorsMap[stashId];
- const isAuthor = lastAuthors && lastAuthors.includes(stashId);
- const _onFavorite = (): void => toggleFavorite(stashId);
+ const _onFavorite = (): void => toggleFavorite(address);
const _onQueryStats = (): void => {
- window.location.hash = `/staking/query/${stashId}`;
+ window.location.hash = `/staking/query/${address}`;
};
const _toggleNominators = (event: React.SyntheticEvent): void => {
event.preventDefault();
@@ -169,12 +166,12 @@ function Address ({ address, authorsMap, className, filter, filterName, hasQueri
type='next'
/>
)}
- {recentlyOnline && hasActivity && recentlyOnline[stashId] && (
+ {heartbeat && (heartbeat.blockCount.gtn(0) || heartbeat.hasMessage) && (
}
@@ -185,10 +182,15 @@ function Address ({ address, authorsMap, className, filter, filterName, hasQueri
)}
-
+
- {stakeOwn && {t('own stake')}} value={stakeOwn} />}
+ {stakeOwn && (
+ {t('own stake')}}
+ value={stakeOwn}
+ />
+ )}
{stakeOther && (
@@ -205,16 +207,21 @@ function Address ({ address, authorsMap, className, filter, filterName, hasQueri
)}
)
- : {t('other stake')}} value={stakeOther}> ({formatNumber(nominators.length)})
+ : (
+ {t('other stake')}}
+ value={stakeOther}
+ >
+ ({formatNumber(nominators.length)})
+
+ )
)}
{!isExpanded && (
<>
- {(commission || validatorPayment) && (
- commission
- ? <>{t('commission')} {commission}>
- : {t('commission')}} value={validatorPayment} />
+ {commission && (
+ <>{t('commission')} {commission}>
)}
@@ -223,7 +230,9 @@ function Address ({ address, authorsMap, className, filter, filterName, hasQueri
)}
- {lastBlockNumber && <>{t('last #')} {lastBlockNumber}>}
+ {lastBlock && (
+ <>{t('last #')} {lastBlock}>
+ )}
{hasQueries && api.query.imOnline?.authoredBlocks && (
@@ -238,77 +247,3 @@ function Address ({ address, authorsMap, className, filter, filterName, hasQueri
);
}
-
-export default translate(
- styled(Address)`
- .extras {
- display: inline-block;
- margin-bottom: 0.75rem;
-
- .favorite {
- cursor: pointer;
- display: inline-block;
- margin-left: 0.5rem;
- margin-right: -0.25rem;
-
- &.isSelected {
- color: darkorange;
- }
- }
- }
-
- .blockNumberV1,
- .blockNumberV2 {
- border-radius: 0.25rem;
- font-size: 1.5rem;
- font-weight: 100;
- line-height: 1.5rem;
- opacity: 0.5;
- vertical-align: middle;
- z-index: 1;
-
- &.isCurrent {
- background: #3f3f3f;
- box-shadow: 0 3px 3px rgba(0,0,0,.2);
- color: #eee;
- opacity: 1;
- }
- }
-
- .blockNumberV2 {
- display: inline-block;
- padding: 0.25rem 0;
-
- &.isCurrent {
- margin-right: -0.25rem;
- padding: 0.25rem 0.75rem;
- }
- }
-
- .blockNumberV1 {
- padding: 0.25rem 0.5rem;
- position: absolute;
- right: 0;
- }
-
- .staking--Address-info {
- margin-right: 0.25rem;
- text-align: right;
-
- .staking--label {
- margin: 0 2.25rem -0.75rem 0;
- }
- }
-
- .staking--label.controllerSpacer {
- margin-top: 0.5rem;
- }
-
- .staking--stats {
- bottom: 0.75rem;
- cursor: pointer;
- position: absolute;
- right: 0.5rem;
- }
- `
-);
diff --git a/packages/app-staking/src/Overview/CurrentList.tsx b/packages/app-staking/src/Overview/CurrentList.tsx
index df0447668812..07c8924528c3 100644
--- a/packages/app-staking/src/Overview/CurrentList.tsx
+++ b/packages/app-staking/src/Overview/CurrentList.tsx
@@ -3,19 +3,19 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedHeartbeats, DerivedStakingOverview } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
-import { AccountId, EraPoints, Points } from '@polkadot/types/interfaces';
+import { AccountId } from '@polkadot/types/interfaces';
import { ValidatorFilter } from '../types';
+import { AddressDetails } from './types';
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useMemo, useReducer, useState } from 'react';
import { Dropdown, FilterOverlay, Input, Table } from '@polkadot/react-components';
-import { useAccounts, useApi, useFavorites } from '@polkadot/react-hooks';
+import { useAccounts, useFavorites } from '@polkadot/react-hooks';
import { STORE_FAVS_BASE } from '../constants';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import Address from './Address';
-interface Props extends I18nProps {
+interface Props {
authorsMap: Record;
hasQueries: boolean;
isIntentions: boolean;
@@ -26,78 +26,115 @@ interface Props extends I18nProps {
stakingOverview?: DerivedStakingOverview;
}
-type AccountExtend = [string, boolean, boolean, Points?];
+type AccountExtend = [string, boolean, boolean];
-function filterAccounts (accounts: string[] = [], elected: string[], favorites: string[], without: string[], eraPoints?: EraPoints): AccountExtend[] {
+function sortByFav ([,, isFavA]: AccountExtend, [,, isFavB]: AccountExtend): number {
+ return isFavA === isFavB
+ ? 0
+ : (isFavA ? -1 : 1);
+}
+
+function filterAccounts (accounts: string[] = [], elected: string[], favorites: string[], without: string[]): AccountExtend[] {
return accounts
.filter((accountId): boolean => !without.includes(accountId as any))
- .sort((a, b): number => {
- const isFavA = favorites.includes(a);
- const isFavB = favorites.includes(b);
-
- return isFavA === isFavB
- ? 0
- : (isFavA ? -1 : 1);
- })
- .map((accountId): AccountExtend => {
- const electedIdx = elected.indexOf(accountId);
-
- return [
- accountId,
- elected.includes(accountId),
- favorites.includes(accountId),
- electedIdx !== -1
- ? eraPoints?.individual[electedIdx]
- : undefined
- ];
- });
+ .map((accountId): AccountExtend => [
+ accountId,
+ elected.includes(accountId),
+ favorites.includes(accountId)
+ ])
+ .sort(sortByFav);
}
function accountsToString (accounts: AccountId[]): string[] {
return accounts.map((accountId): string => accountId.toString());
}
-function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAuthors, next, recentlyOnline, stakingOverview, t }: Props): React.ReactElement | null {
- const { isSubstrateV2 } = useApi();
+function reduceDetails (state: Record, _details: AddressDetails | AddressDetails[]): Record {
+ const details = Array.isArray(_details)
+ ? _details
+ : [_details];
+
+ return details.reduce((result, details): Record => {
+ result[details.address] = {
+ ...(state[details.address] || {}),
+ ...details
+ };
+
+ return result;
+ }, { ...state });
+}
+
+export default function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAuthors, next, recentlyOnline, stakingOverview }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const { allAccounts } = useAccounts();
const [favorites, toggleFavorite] = useFavorites(STORE_FAVS_BASE);
const [filter, setFilter] = useState('all');
- const [{ elected, validators, waiting }, setFiltered] = useState<{ elected: AccountExtend[]; validators: AccountExtend[]; waiting: AccountExtend[] }>({ elected: [], validators: [], waiting: [] });
+ const [{ allElected, elected, validators, waiting }, setFiltered] = useState<{ allElected: string[]; elected: AccountExtend[]; validators: AccountExtend[]; waiting: AccountExtend[] }>({ allElected: [], elected: [], validators: [], waiting: [] });
const [nameFilter, setNameFilter] = useState('');
+ const [addressDetails, dispatchDetails] = useReducer(reduceDetails, {});
+ const filterOpts = useMemo(() => [
+ { text: t('Show all validators and intentions'), value: 'all' },
+ { text: t('Show only my nominations'), value: 'iNominated' },
+ { text: t('Show only with nominators'), value: 'hasNominators' },
+ { text: t('Show only without nominators'), value: 'noNominators' },
+ { text: t('Show only with warnings'), value: 'hasWarnings' },
+ { text: t('Show only without warnings'), value: 'noWarnings' },
+ { text: t('Show only elected for next session'), value: 'nextSet' }
+ ], [t]);
useEffect((): void => {
if (isVisible && stakingOverview) {
- const _elected = accountsToString(stakingOverview.currentElected);
+ const allElected = accountsToString(stakingOverview.currentElected);
const _validators = accountsToString(stakingOverview.validators);
- const validators = filterAccounts(_validators, _elected, favorites, [], stakingOverview.eraPoints);
- const elected = isSubstrateV2 ? filterAccounts(_elected, _elected, favorites, _validators) : [];
+ const validators = filterAccounts(_validators, allElected, favorites, []);
+ const elected = filterAccounts(allElected, allElected, favorites, _validators);
setFiltered({
+ allElected,
elected,
validators,
- waiting: filterAccounts(next, [], favorites, _elected)
+ waiting: filterAccounts(next, [], favorites, allElected)
});
}
- }, [favorites, isVisible, next, stakingOverview]);
+ }, [favorites, isVisible, next, stakingOverview?.currentElected, stakingOverview?.validators]);
+
+ useEffect((): void => {
+ if (stakingOverview) {
+ dispatchDetails(validators.map(([address]): AddressDetails => {
+ const electedIdx = allElected.indexOf(address);
+
+ return {
+ address,
+ points: electedIdx !== -1
+ ? stakingOverview.eraPoints?.individual[electedIdx]
+ : undefined
+ };
+ }));
+ }
+ }, [stakingOverview?.eraPoints, allElected, validators]);
- const _renderRows = (addresses: AccountExtend[], defaultName: string, withOnline: boolean): React.ReactNode =>
- addresses.map(([address, isElected, isFavorite, points]): React.ReactNode => (
+ const _renderRows = (addresses: AccountExtend[], defaultName: string, isMain: boolean): React.ReactNode =>
+ addresses.map(([address, isElected, isFavorite]): React.ReactNode => (
@@ -143,5 +172,3 @@ function CurrentList ({ authorsMap, hasQueries, isIntentions, isVisible, lastAut
);
}
-
-export default translate(CurrentList);
diff --git a/packages/app-staking/src/Overview/Summary.tsx b/packages/app-staking/src/Overview/Summary.tsx
index a2fc65e5eae5..d6c937189b22 100644
--- a/packages/app-staking/src/Overview/Summary.tsx
+++ b/packages/app-staking/src/Overview/Summary.tsx
@@ -3,7 +3,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedStakingOverview } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
import React, { useContext } from 'react';
import styled from 'styled-components';
@@ -11,16 +10,18 @@ import SummarySession from '@polkadot/app-explorer/SummarySession';
import { CardSummary, IdentityIcon, SummaryBox } from '@polkadot/react-components';
import { BlockAuthorsContext } from '@polkadot/react-query';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
className?: string;
isVisible: boolean;
next: string[];
stakingOverview?: DerivedStakingOverview;
+ style?: any;
}
-function Summary ({ className, isVisible, next, stakingOverview, style, t }: Props): React.ReactElement {
+function Summary ({ className, isVisible, next, stakingOverview, style }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { lastBlockAuthors, lastBlockNumber } = useContext(BlockAuthorsContext);
return (
@@ -63,18 +64,16 @@ function Summary ({ className, isVisible, next, stakingOverview, style, t }: Pro
);
}
-export default translate(
- styled(Summary)`
- .validator--Account-block-icon {
- margin-right: 0.75rem;
- margin-top: -0.25rem;
- vertical-align: middle;
- }
+export default styled(Summary)`
+ .validator--Account-block-icon {
+ margin-right: 0.75rem;
+ margin-top: -0.25rem;
+ vertical-align: middle;
+ }
- .validator--Summary-authors {
- .validator--Account-block-icon+.validator--Account-block-icon {
- margin-left: -1.5rem;
- }
+ .validator--Summary-authors {
+ .validator--Account-block-icon+.validator--Account-block-icon {
+ margin-left: -1.5rem;
}
- `
-);
+ }
+`;
diff --git a/packages/app-staking/src/Overview/types.ts b/packages/app-staking/src/Overview/types.ts
new file mode 100644
index 000000000000..5dd15942fc39
--- /dev/null
+++ b/packages/app-staking/src/Overview/types.ts
@@ -0,0 +1,10 @@
+// Copyright 2017-2020 @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 { Points } from '@polkadot/types/interfaces';
+
+export interface AddressDetails {
+ address: string;
+ points?: Points;
+}
diff --git a/packages/app-staking/src/Query/Validator.tsx b/packages/app-staking/src/Query/Validator.tsx
index bde688c322d1..5f39b80283e5 100644
--- a/packages/app-staking/src/Query/Validator.tsx
+++ b/packages/app-staking/src/Query/Validator.tsx
@@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
import { Balance, Hash, Exposure } from '@polkadot/types/interfaces';
import { SessionRewards, Slash } from '../types';
@@ -14,10 +13,10 @@ import { getHistoric } from '@polkadot/react-api/util';
import { useApi } from '@polkadot/react-hooks';
import { formatBalance, formatNumber } from '@polkadot/util';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import useBlockCounts from '../useBlockCounts';
-interface Props extends I18nProps {
+interface Props {
className?: string;
sessionRewards: SessionRewards[];
validatorId: string;
@@ -100,7 +99,8 @@ function extractEraSlash (validatorId: string, slashes: Slash[]): BN {
}, new BN(0));
}
-function Validator ({ className, sessionRewards, t, validatorId }: Props): React.ReactElement {
+export default function Validator ({ className, sessionRewards, validatorId }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const blockCounts = useBlockCounts(validatorId, sessionRewards);
const [blocksLabels, setBlocksLabels] = useState([]);
@@ -269,5 +269,3 @@ function Validator ({ className, sessionRewards, t, validatorId }: Props): React
);
}
-
-export default translate(Validator);
diff --git a/packages/app-staking/src/Query/index.tsx b/packages/app-staking/src/Query/index.tsx
index 5cf610c2caaf..ea3d2ba360b8 100644
--- a/packages/app-staking/src/Query/index.tsx
+++ b/packages/app-staking/src/Query/index.tsx
@@ -2,21 +2,22 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
import { SessionRewards } from '../types';
import React, { useState } from 'react';
import { useParams } from 'react-router-dom';
import { Button, InputAddressSimple } from '@polkadot/react-components';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import Validator from './Validator';
-interface Props extends I18nProps {
+interface Props {
+ className?: string;
sessionRewards: SessionRewards[];
}
-function Query ({ className, sessionRewards, t }: Props): React.ReactElement {
+export default function Query ({ className, sessionRewards }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { value } = useParams();
const [validatorId, setValidatorId] = useState(value || null);
@@ -51,5 +52,3 @@ function Query ({ className, sessionRewards, t }: Props): React.ReactElement
);
}
-
-export default translate(Query);
diff --git a/packages/app-staking/src/Targets/Summary.tsx b/packages/app-staking/src/Targets/Summary.tsx
index b91f58e8c29b..6ee1b61d8a07 100644
--- a/packages/app-staking/src/Targets/Summary.tsx
+++ b/packages/app-staking/src/Targets/Summary.tsx
@@ -3,45 +3,34 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Balance } from '@polkadot/types/interfaces';
-import { I18nProps } from '@polkadot/react-components/types';
import BN from 'bn.js';
import React, { useEffect, useState } from 'react';
import { SummaryBox, CardSummary } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
-import { formatBalance } from '@polkadot/util';
+import { FormatBalance } from '@polkadot/react-query';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
lastReward: BN;
totalStaked: BN;
}
interface StakeInfo {
percentage: string;
- staked: string | null;
}
-function Summary ({ lastReward, t, totalStaked }: Props): React.ReactElement {
+export default function Summary ({ lastReward, totalStaked }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const totalInsurance = useCall(api.query.balances.totalIssuance, []);
- const [{ percentage, staked }, setStakeInfo] = useState({ percentage: '-', staked: null });
- const [total, setTotal] = useState(null);
-
- useEffect((): void => {
- if (totalInsurance) {
- setTotal(
- `${formatBalance(totalInsurance, false)}${formatBalance.calcSi(totalInsurance.toString()).value}`
- );
- }
- }, [totalInsurance]);
+ const [{ percentage }, setStakeInfo] = useState({ percentage: '-' });
useEffect((): void => {
if (totalInsurance && totalStaked?.gtn(0)) {
setStakeInfo({
- percentage: `${(totalStaked.muln(10000).div(totalInsurance).toNumber() / 100).toFixed(2)}%`,
- staked: `${formatBalance(totalStaked, false)}${formatBalance.calcSi(totalStaked.toString()).value}`
+ percentage: `${(totalStaked.muln(10000).div(totalInsurance).toNumber() / 100).toFixed(2)}%`
});
}
}, [totalInsurance, totalStaked]);
@@ -50,25 +39,28 @@ function Summary ({ lastReward, t, totalStaked }: Props): React.ReactElement
- {staked || '-'}
+
/
- {total || '-'}
+
{percentage}
- {
- lastReward.gtn(0)
- ? `${formatBalance(lastReward, false)}`
- : '-'
- }
+
);
}
-
-export default translate(Summary);
diff --git a/packages/app-staking/src/Targets/Validator.tsx b/packages/app-staking/src/Targets/Validator.tsx
index 9caf4e849445..7b96fc737bd2 100644
--- a/packages/app-staking/src/Targets/Validator.tsx
+++ b/packages/app-staking/src/Targets/Validator.tsx
@@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.v
-import { I18nProps } from '@polkadot/react-components/types';
import { ValidatorInfo } from './types';
import React from 'react';
@@ -10,14 +9,15 @@ import { AddressSmall, Icon } from '@polkadot/react-components';
import { FormatBalance } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
info: ValidatorInfo;
toggleFavorite: (accountId: string) => void;
}
-function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isFavorite, isNominating, key, numNominators, rankOverall, rewardPayout, validatorPayment }, t, toggleFavorite }: Props): React.ReactElement {
+export default function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isFavorite, isNominating, key, numNominators, rankOverall, rewardPayout, validatorPayment }, toggleFavorite }: Props): React.ReactElement {
+ const { t } = useTranslation();
const _onFavorite = (): void => toggleFavorite(key);
const _onQueryStats = (): void => {
window.location.hash = `/staking/query/${key}`;
@@ -43,10 +43,10 @@ function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissi
: {t('commission')}} value={validatorPayment} />
}
- {t('total stake')}} value={bondTotal} />
- {t('own stake')}} value={bondOwn} />
- {t('other stake')}} value={bondOther} > ({formatNumber(numNominators)})
- {t('payout (est.)')}} value={rewardPayout} />
+ {t('total stake')}} value={bondTotal} />
+ {t('own stake')}} value={bondOwn} />
+ {t('other stake')}} value={bondOther} > ({formatNumber(numNominators)})
+ {t('profit/era est.')}} value={rewardPayout} />
);
}
-
-export default translate(Validator);
diff --git a/packages/app-staking/src/Targets/index.tsx b/packages/app-staking/src/Targets/index.tsx
index 8f6afd457669..f75b58aa8bc0 100644
--- a/packages/app-staking/src/Targets/index.tsx
+++ b/packages/app-staking/src/Targets/index.tsx
@@ -3,7 +3,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { DerivedStakingElected } from '@polkadot/api-derive/types';
-import { I18nProps } from '@polkadot/react-components/types';
import { ValidatorPrefs, ValidatorPrefsTo196 } from '@polkadot/types/interfaces';
import { SessionRewards } from '../types';
import { ValidatorInfo } from './types';
@@ -12,18 +11,19 @@ import BN from 'bn.js';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { registry } from '@polkadot/react-api';
-import { InputBalance, Table } from '@polkadot/react-components';
+import { Icon, InputBalance, Table } from '@polkadot/react-components';
import { useAccounts, useApi, useDebounce, useFavorites, useCall } from '@polkadot/react-hooks';
import { createType } from '@polkadot/types';
import { STORE_FAVS_BASE } from '../constants';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import Summary from './Summary';
import Validator from './Validator';
const PERBILL = new BN(1000000000);
-interface Props extends I18nProps {
+interface Props {
+ className?: string;
sessionRewards: SessionRewards[];
}
@@ -32,11 +32,31 @@ interface AllInfo {
validators: ValidatorInfo[];
}
+type SortBy = 'rankOverall' | 'rankBondOwn' | 'rankBondOther' | 'rankBondTotal' | 'rankComm';
+
function sortValidators (list: ValidatorInfo[]): ValidatorInfo[] {
return list
+ .sort((a, b): number => b.commissionPer - a.commissionPer)
+ .map((info, index): ValidatorInfo => {
+ info.rankComm = index + 1;
+
+ return info;
+ })
+ .sort((a, b): number => b.bondOther.cmp(a.bondOther))
+ .map((info, index): ValidatorInfo => {
+ info.rankBondOther = index + 1;
+
+ return info;
+ })
+ .sort((a, b): number => b.bondOwn.cmp(a.bondOwn))
+ .map((info, index): ValidatorInfo => {
+ info.rankBondOwn = index + 1;
+
+ return info;
+ })
.sort((a, b): number => b.bondTotal.cmp(a.bondTotal))
.map((info, index): ValidatorInfo => {
- info.rankBonded = index + 1;
+ info.rankBondTotal = index + 1;
return info;
})
@@ -59,30 +79,15 @@ function sortValidators (list: ValidatorInfo[]): ValidatorInfo[] {
? cmp
: a.rankReward === b.rankReward
? a.rankPayment === b.rankPayment
- ? a.rankBonded === b.rankBonded
- ? 0
- : a.rankBonded < b.rankBonded
- ? 1
- : -1
- : a.rankPayment < b.rankPayment
- ? 1
- : -1
- : a.rankReward < b.rankReward
- ? 1
- : -1;
+ ? b.rankBondTotal - a.rankBondTotal
+ : b.rankPayment - a.rankPayment
+ : b.rankReward - a.rankReward;
})
.map((info, index): ValidatorInfo => {
info.rankOverall = index + 1;
return info;
- })
- .sort((a, b): number =>
- a.isFavorite === b.isFavorite
- ? 0
- : a.isFavorite
- ? -1
- : 1
- );
+ });
}
function extractInfo (allAccounts: string[], amount: BN = new BN(0), electedInfo: DerivedStakingElected, favorites: string[], lastReward: BN): AllInfo {
@@ -126,7 +131,10 @@ function extractInfo (allAccounts: string[], amount: BN = new BN(0), electedInfo
key,
commissionPer: (((prefs as ValidatorPrefs).commission?.unwrap() || new BN(0)).muln(10000).div(PERBILL).toNumber() / 100),
numNominators: exposure.others.length,
- rankBonded: 0,
+ rankBondOther: 0,
+ rankBondOwn: 0,
+ rankBondTotal: 0,
+ rankComm: 0,
rankOverall: 0,
rankPayment: 0,
rankReward: 0,
@@ -140,7 +148,8 @@ function extractInfo (allAccounts: string[], amount: BN = new BN(0), electedInfo
return { totalStaked, validators };
}
-function Targets ({ className, sessionRewards, t }: Props): React.ReactElement {
+function Targets ({ className, sessionRewards }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const { allAccounts } = useAccounts();
const [_amount, setAmount] = useState(new BN(1000));
@@ -148,8 +157,31 @@ function Targets ({ className, sessionRewards, t }: Props): React.ReactElement({ totalStaked: new BN(0), validators: [] });
+ const [{ sorted, sortBy, sortFromMax }, setSorted] = useState<{ sorted: ValidatorInfo[]; sortBy: SortBy; sortFromMax: boolean }>({ sorted: [], sortBy: 'rankOverall', sortFromMax: true });
const amount = useDebounce(_amount);
+ const _sort = (newSortBy: SortBy, unsorted = validators, isAdjust = true): void => {
+ const newSortFromMax = isAdjust && newSortBy === sortBy ? !sortFromMax : true;
+
+ setSorted({
+ sortBy: newSortBy,
+ sortFromMax: newSortFromMax,
+ sorted: unsorted
+ .sort((a, b): number =>
+ newSortFromMax
+ ? a[newSortBy] - b[newSortBy]
+ : b[newSortBy] - a[newSortBy]
+ )
+ .sort((a, b): number =>
+ a.isFavorite === b.isFavorite
+ ? 0
+ : a.isFavorite
+ ? -1
+ : 1
+ )
+ });
+ };
+
useEffect((): void => {
if (sessionRewards && sessionRewards.length) {
const lastRewardSession = sessionRewards.filter(({ reward }): boolean => reward.gtn(0));
@@ -164,7 +196,10 @@ function Targets ({ className, sessionRewards, t }: Props): React.ReactElement
{
if (electedInfo) {
- setWorkable(extractInfo(allAccounts, amount, electedInfo, favorites, lastReward));
+ const { totalStaked, validators } = extractInfo(allAccounts, amount, electedInfo, favorites, lastReward);
+
+ setWorkable({ totalStaked, validators });
+ _sort('rankOverall', validators, false);
}
}, [allAccounts, amount, electedInfo, favorites, lastReward]);
@@ -174,19 +209,33 @@ function Targets ({ className, sessionRewards, t }: Props): React.ReactElement
- {validators.length
+ {sorted.length
? (
<>
+
+
+
+
+ {['rankComm', 'rankBondTotal', 'rankBondOwn', 'rankBondOther', 'rankOverall'].map((header): React.ReactNode => (
+ _sort(header as 'rankComm')}
+ >
+ ))}
+
+
- {validators.map((info): React.ReactNode =>
+ {sorted.map((info): React.ReactNode =>
[]]): [string[], string[]] {
- return [
- stashes.map((accountId): string => accountId.toString()),
- controllers
- .filter((optId): boolean => optId.isSome)
- .map((accountId): string => accountId.unwrap().toString())
- ];
-}
-
function StakingApp ({ basePath, className }: Props): React.ReactElement {
const { t } = useTranslation();
- const { api, isSubstrateV2 } = useApi();
+ const { api } = useApi();
const { hasAccounts } = useAccounts();
const { pathname } = useLocation();
const [next, setNext] = useState([]);
- const [allStashes, allControllers] = (useCall<[string[], string[]]>(api.derive.staking.controllers, [], {
- defaultValue: EMPTY_ALL,
- transform: transformStakingControllers
- }) as [string[], string[]]);
+ const allStashes = useCall(api.derive.staking.controllers, [], {
+ defaultValue: [],
+ transform: ([stashes]: [AccountId[]]): string[] =>
+ stashes.map((accountId): string => accountId.toString())
+ }) as string[];
const recentlyOnline = useCall(api.derive.imOnline.receivedHeartbeats, []);
const stakingOverview = useCall(api.derive.staking.overview, []);
const sessionRewards = useSessionRewards(MAX_SESSIONS);
const hasQueries = hasAccounts && !!(api.query.imOnline?.authoredBlocks);
- const validators = stakingOverview?.validators;
+ const items = useMemo(() => [
+ {
+ isRoot: true,
+ name: 'overview',
+ text: t('Staking overview')
+ },
+ {
+ name: 'waiting',
+ text: t('Waiting')
+ },
+ {
+ name: 'returns',
+ text: t('Returns')
+ },
+ {
+ name: 'actions',
+ text: t('Account actions')
+ },
+ {
+ hasParams: true,
+ name: 'query',
+ text: t('Validator stats')
+ }
+ ], [t]);
useEffect((): void => {
- validators && setNext(
- isSubstrateV2
- // this is a V2 node currentValidators is a list of stashes
- ? allStashes.filter((address): boolean => !validators.includes(address as any))
- // this is a V1 node currentValidators is a list of controllers
- : allControllers.filter((address): boolean => !validators.includes(address as any))
+ stakingOverview && setNext(
+ allStashes.filter((address): boolean => !stakingOverview.validators.includes(address as any))
);
- }, [allControllers, allStashes, validators]);
+ }, [allStashes, stakingOverview?.validators]);
return (
@@ -76,30 +83,7 @@ function StakingApp ({ basePath, className }: Props): React.ReactElement
: ['query']
: ['actions', 'query']
}
- items={[
- {
- isRoot: true,
- name: 'overview',
- text: t('Staking overview')
- },
- {
- name: 'waiting',
- text: t('Waiting')
- },
- {
- name: 'returns',
- text: t('Returns')
- },
- {
- name: 'actions',
- text: t('Account actions')
- },
- {
- hasParams: true,
- name: 'query',
- text: t('Validator stats')
- }
- ]}
+ items={items}
/>
;
export interface CalculateBalanceProps {
balances_fees?: DerivedFees;
- balances_all?: DerivedBalances;
+ balances_all?: DerivedBalancesAll;
}
export type AccountFilter = 'all' | 'controller' | 'session' | 'stash' | 'unbonded';
diff --git a/packages/app-storage/package.json b/packages/app-storage/package.json
index eb9a5eb31de8..8c59306c3f81 100644
--- a/packages/app-storage/package.json
+++ b/packages/app-storage/package.json
@@ -1,6 +1,6 @@
{
"name": "@polkadot/app-storage",
- "version": "0.39.0-beta.70",
+ "version": "0.40.0-beta.1",
"main": "index.js",
"repository": "https://github.com/polkadot-js/apps.git",
"author": "Jaco Greeff ",
@@ -10,8 +10,8 @@
"contributors": [],
"license": "Apache-2.0",
"dependencies": {
- "@babel/runtime": "^7.7.7",
- "@polkadot/react-components": "^0.39.0-beta.70",
- "@polkadot/react-params": "^0.39.0-beta.70"
+ "@babel/runtime": "^7.8.3",
+ "@polkadot/react-components": "^0.40.0-beta.1",
+ "@polkadot/react-params": "^0.40.0-beta.1"
}
}
diff --git a/packages/app-storage/src/Query.tsx b/packages/app-storage/src/Query.tsx
index f241b3a41bec..0ecc260a4f9c 100644
--- a/packages/app-storage/src/Query.tsx
+++ b/packages/app-storage/src/Query.tsx
@@ -3,7 +3,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { RenderFn, DefaultProps, ComponentRenderer } from '@polkadot/react-api/hoc/types';
-import { I18nProps } from '@polkadot/react-components/types';
import { ConstValue } from '@polkadot/react-components/InputConsts/types';
import { QueryTypes, StorageEntryPromise, StorageModuleQuery } from './types';
@@ -16,9 +15,8 @@ import valueToText from '@polkadot/react-params/valueToText';
import { Compact, Option, Raw } from '@polkadot/types';
import { isU8a, u8aToHex, u8aToString } from '@polkadot/util';
-import translate from './translate';
-
-interface Props extends I18nProps {
+interface Props {
+ className?: string;
onRemove: (id: number) => void;
value: QueryTypes;
}
@@ -214,22 +212,20 @@ function Query ({ className, onRemove, value }: Props): React.ReactElement {
+export default function Consts ({ onAdd }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const [defaultValue] = useState((): ConstValue => {
const section = Object.keys(api.consts)[0];
@@ -54,5 +52,3 @@ function Consts ({ onAdd, t }: Props): React.ReactElement {
);
}
-
-export default translate(Consts);
diff --git a/packages/app-storage/src/Selection/Modules.tsx b/packages/app-storage/src/Selection/Modules.tsx
index 1e819acbd677..bf208f46df00 100644
--- a/packages/app-storage/src/Selection/Modules.tsx
+++ b/packages/app-storage/src/Selection/Modules.tsx
@@ -3,37 +3,71 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { TypeDef } from '@polkadot/types/types';
-import { I18nProps } from '@polkadot/react-components/types';
import { RawParams } from '@polkadot/react-params/types';
-import { ComponentProps, StorageEntryPromise } from '../types';
+import { ComponentProps as Props, StorageEntryPromise } from '../types';
import React, { useState } from 'react';
-import { getTypeDef } from '@polkadot/types';
+import ApiPromise from '@polkadot/api/promise';
import { Button, InputStorage } from '@polkadot/react-components';
-import Params from '@polkadot/react-params';
import { useApi } from '@polkadot/react-hooks';
+import Params from '@polkadot/react-params';
+import { getTypeDef } from '@polkadot/types';
import { isNull, isUndefined } from '@polkadot/util';
-import translate from '../translate';
-
-interface Props extends ComponentProps, I18nProps {}
+import { useTranslation } from '../translate';
type ParamsType = { type: TypeDef }[];
-function areParamsValid (values: RawParams): boolean {
- return values.reduce(
- (isValid: boolean, value): boolean => (
- isValid &&
- !isUndefined(value) &&
- !isUndefined(value.value) &&
- value.isValid),
- true
- );
+interface KeyState {
+ defaultValues: RawParams | undefined | null;
+ isIterable: boolean;
+ key: StorageEntryPromise;
+ params: ParamsType;
+}
+
+function areParamsValid ({ creator: { meta: { type } } }: StorageEntryPromise, values: RawParams): boolean {
+ return values.reduce((isValid: boolean, value): boolean => {
+ return isValid &&
+ !isUndefined(value) &&
+ !isUndefined(value.value) &&
+ value.isValid;
+ }, (
+ type.isDoubleMap
+ ? values.length === 2
+ : values.length === (type.isMap ? 1 : 0)
+ ));
+}
+
+function expandKey (api: ApiPromise, key: StorageEntryPromise): KeyState {
+ const { creator: { meta: { type }, section } } = key;
+
+ return {
+ defaultValues: section === 'session' && type.isDoubleMap
+ ? [{ isValid: true, value: api.consts.session.dedupKeyPrefix.toHex() }]
+ : null,
+ isIterable: type.isMap && type.asMap.linked.isTrue,
+ key,
+ params: type.isDoubleMap
+ ? [
+ { type: getTypeDef(type.asDoubleMap.key1.toString()) },
+ { type: getTypeDef(type.asDoubleMap.key2.toString()) }
+ ]
+ : type.isMap
+ ? [{
+ type: getTypeDef(
+ type.asMap.linked.isTrue
+ ? `Option<${type.asMap.key.toString()}>`
+ : type.asMap.key.toString()
+ )
+ }]
+ : []
+ };
}
-function Modules ({ onAdd, t }: Props): React.ReactElement {
+export default function Modules ({ onAdd }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
- const [{ defaultValues, isIterable, key, params }, setKey] = useState<{ defaultValues: RawParams | undefined | null; isIterable: boolean; key: StorageEntryPromise; params: ParamsType }>({ defaultValues: undefined, isIterable: false, key: api.query.timestamp.now, params: [] });
+ const [{ defaultValues, isIterable, key, params }, setKey] = useState({ defaultValues: undefined, isIterable: false, key: api.query.timestamp.now, params: [] });
const [{ isValid, values }, setValues] = useState<{ isValid: boolean; values: RawParams }>({ isValid: true, values: [] });
const _onAdd = (): void => {
@@ -43,42 +77,13 @@ function Modules ({ onAdd, t }: Props): React.ReactElement {
params: values.filter(({ value }): boolean => !isIterable || !isNull(value))
});
};
- const _onChangeValues = (values: RawParams): void => {
+ const _onChangeValues = (values: RawParams): void =>
setValues({
- isValid: (
- key.creator.meta.type.isDoubleMap
- ? values.length === 2
- : values.length === (key.creator.meta.type.isMap ? 1 : 0)
- ) && areParamsValid(values),
+ isValid: areParamsValid(key, values),
values
});
- };
const _onChangeKey = (key: StorageEntryPromise): void => {
- const asMap = key.creator.meta.type.isMap && key.creator.meta.type.asMap;
- const isIterable = !!asMap && (asMap.kind.isLinkedMap || asMap.kind.isPrefixedMap);
-
- setKey({
- defaultValues: key.creator.section === 'session' && key.creator.meta.type.isDoubleMap
- ? [{ isValid: true, value: api.consts.session.dedupKeyPrefix.toHex() }]
- : null,
- isIterable,
- key,
- params: key.creator.meta.type.isDoubleMap
- ? [
- { type: getTypeDef(key.creator.meta.type.asDoubleMap.key1.toString()) },
- { type: getTypeDef(key.creator.meta.type.asDoubleMap.key2.toString()) }
- ]
- : asMap
- ? [{
- type: getTypeDef(
- isIterable
- ? `Option<${asMap.key.toString()}>`
- : asMap.key.toString()
- )
- }]
- : []
- });
-
+ setKey(expandKey(api, key));
_onChangeValues([]);
};
@@ -112,5 +117,3 @@ function Modules ({ onAdd, t }: Props): React.ReactElement {
);
}
-
-export default translate(Modules);
diff --git a/packages/app-storage/src/Selection/Raw.tsx b/packages/app-storage/src/Selection/Raw.tsx
index 65a9b322eaf2..c566e16d3c18 100644
--- a/packages/app-storage/src/Selection/Raw.tsx
+++ b/packages/app-storage/src/Selection/Raw.tsx
@@ -2,19 +2,17 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
-import { ComponentProps } from '../types';
+import { ComponentProps as Props } from '../types';
import React, { useState } from 'react';
import { Button, Input } from '@polkadot/react-components';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import { u8aToU8a } from '@polkadot/util';
import { Compact } from '@polkadot/types';
-interface Props extends ComponentProps, I18nProps {}
-
-function Raw ({ onAdd, t }: Props): React.ReactElement {
+export default function Raw ({ onAdd }: Props): React.ReactElement {
+ const { t } = useTranslation();
const [{ isValid, key }, setValue] = useState<{ isValid: boolean; key: Uint8Array }>({ isValid: false, key: new Uint8Array([]) });
const _onAdd = (): void => {
@@ -51,5 +49,3 @@ function Raw ({ onAdd, t }: Props): React.ReactElement {
);
}
-
-export default translate(Raw);
diff --git a/packages/app-storage/src/Selection/index.tsx b/packages/app-storage/src/Selection/index.tsx
index 03595350bd0c..b1ea0deeaba4 100644
--- a/packages/app-storage/src/Selection/index.tsx
+++ b/packages/app-storage/src/Selection/index.tsx
@@ -2,28 +2,42 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
import { ComponentProps, QueryTypes, ParitalQueryTypes } from '../types';
-import React from 'react';
+import React, { useMemo } from 'react';
import { Route, Switch } from 'react-router';
import { Tabs } from '@polkadot/react-components';
-import { useApi } from '@polkadot/react-hooks';
import Consts from './Consts';
import Modules from './Modules';
import Raw from './Raw';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
basePath: string;
onAdd: (query: QueryTypes) => void;
}
let id = -1;
-function Selection ({ basePath, onAdd, t }: Props): React.ReactElement {
- const { isSubstrateV2 } = useApi();
+export default function Selection ({ basePath, onAdd }: Props): React.ReactElement {
+ const { t } = useTranslation();
+ const items = useMemo(() => [
+ {
+ isRoot: true,
+ name: 'modules',
+ text: t('Storage')
+ },
+ {
+ name: 'constants',
+ text: t('Constants')
+ },
+ {
+ name: 'raw',
+ text: t('Raw storage')
+ }
+ ], [t]);
+
const _onAdd = (query: ParitalQueryTypes): void => onAdd({ ...query, id: ++id });
const _renderComponent = (Component: React.ComponentType): () => React.ReactNode =>
// eslint-disable-next-line react/display-name
@@ -34,26 +48,7 @@ function Selection ({ basePath, onAdd, t }: Props): React.ReactElement {
@@ -64,5 +59,3 @@ function Selection ({ basePath, onAdd, t }: Props): React.ReactElement {
>
);
}
-
-export default translate(Selection);
diff --git a/packages/app-storage/src/index.css b/packages/app-storage/src/index.css
deleted file mode 100644
index d4f3cb90c7b0..000000000000
--- a/packages/app-storage/src/index.css
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright 2017-2020 @polkadot/app-storage authors & contributors
-/* This software may be modified and distributed under the terms
-/* of the Apache-2.0 license. See the LICENSE file for details. */
-
-.storage--actionrow {
- align-items: center;
- display: flex;
-
- .button {
- margin: 0.25rem;
- }
-
- &.head {
- flex: 1 1 100%;
- margin: 0 auto;
- max-width: 620px;
- }
-}
-
-.storage--actionrow-value {
- flex: 1;
- min-width: 0;
-
- .ui--output {
- word-break: break-all;
- }
-}
-
-.storage--actionrow-buttons {
- flex: 0;
- padding: 0 0.25rem;
-}
diff --git a/packages/app-storage/src/index.tsx b/packages/app-storage/src/index.tsx
index 8c3f9a5096ee..605ad8f1194c 100644
--- a/packages/app-storage/src/index.tsx
+++ b/packages/app-storage/src/index.tsx
@@ -2,27 +2,23 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { AppProps, I18nProps } from '@polkadot/react-components/types';
+import { AppProps as Props } from '@polkadot/react-components/types';
import { QueryTypes } from './types';
-import './index.css';
-
import React, { useState } from 'react';
+import styled from 'styled-components';
import Queries from './Queries';
import Selection from './Selection';
-import translate from './translate';
-
-interface Props extends AppProps, I18nProps {}
-function StorageApp ({ basePath }: Props): React.ReactElement {
+function StorageApp ({ basePath, className }: Props): React.ReactElement {
const [queue, setQueue] = useState([]);
const _onAdd = (query: QueryTypes): void => setQueue([query, ...queue]);
const _onRemove = (id: number): void => setQueue(queue.filter((item): boolean => item.id !== id));
return (
-
+
{
);
}
-export default translate(StorageApp);
+export default styled(StorageApp)`
+ .storage--actionrow {
+ align-items: center;
+ display: flex;
+
+ .button {
+ margin: 0.25rem;
+ }
+
+ &.head {
+ flex: 1 1 100%;
+ margin: 0 auto;
+ max-width: 620px;
+ }
+ }
+
+ .storage--actionrow-value {
+ flex: 1;
+ min-width: 0;
+
+ .ui--output {
+ word-break: break-all;
+ }
+ }
+
+ .storage--actionrow-buttons {
+ flex: 0;
+ padding: 0 0.25rem;
+ }
+`;
diff --git a/packages/app-sudo/package.json b/packages/app-sudo/package.json
index 27176612377e..39306273aad9 100644
--- a/packages/app-sudo/package.json
+++ b/packages/app-sudo/package.json
@@ -1,6 +1,6 @@
{
"name": "@polkadot/app-sudo",
- "version": "0.39.0-beta.70",
+ "version": "0.40.0-beta.1",
"description": "A basic app that shows the ropes on customisation",
"main": "index.js",
"scripts": {},
@@ -11,7 +11,7 @@
],
"license": "Apache-2.0",
"dependencies": {
- "@babel/runtime": "^7.7.7",
- "@polkadot/react-components": "^0.39.0-beta.70"
+ "@babel/runtime": "^7.8.3",
+ "@polkadot/react-components": "^0.40.0-beta.1"
}
}
diff --git a/packages/app-sudo/src/SetKey.tsx b/packages/app-sudo/src/SetKey.tsx
index 89051acb7fb1..72e0cf82eb37 100644
--- a/packages/app-sudo/src/SetKey.tsx
+++ b/packages/app-sudo/src/SetKey.tsx
@@ -9,11 +9,12 @@ import { ComponentProps } from './types';
import styled from 'styled-components';
-import translate from './translate';
+import { useTranslation } from './translate';
interface Props extends I18nProps, ComponentProps {}
-function SetKey ({ allAccounts, className, isMine, sudoKey, t }: Props): React.ReactElement {
+function SetKey ({ allAccounts, className, isMine, sudoKey }: Props): React.ReactElement {
+ const { t } = useTranslation();
const [selected, setSelected] = useState(null);
useEffect((): void => {
@@ -75,21 +76,19 @@ function SetKey ({ allAccounts, className, isMine, sudoKey, t }: Props): React.R
);
}
-export default translate(
- styled(SetKey)`
- align-items: flex-end;
- justify-content: center;
+export default styled(SetKey)`
+ align-items: flex-end;
+ justify-content: center;
- .summary {
- text-align: center;
- }
+ .summary {
+ text-align: center;
+ }
- .sudoInputAddress {
- margin: -0.25rem 0.5rem -0.25rem 0;
- }
+ .sudoInputAddress {
+ margin: -0.25rem 0.5rem -0.25rem 0;
+ }
- .sudoLabelled {
- align-items: center;
- }
- `
-);
+ .sudoLabelled {
+ align-items: center;
+ }
+`;
diff --git a/packages/app-sudo/src/Sudo.tsx b/packages/app-sudo/src/Sudo.tsx
index 35a3da545552..cf9d5c125449 100644
--- a/packages/app-sudo/src/Sudo.tsx
+++ b/packages/app-sudo/src/Sudo.tsx
@@ -53,6 +53,7 @@ class Propose extends TxComponent {
isDisabled={!method || !isValid}
params={method ? [createType(registry, 'Proposal', method)] : []}
ref={this.button}
+ withSpinner
/>
diff --git a/packages/app-sudo/src/index.tsx b/packages/app-sudo/src/index.tsx
index d97f56164379..e00692f1263f 100644
--- a/packages/app-sudo/src/index.tsx
+++ b/packages/app-sudo/src/index.tsx
@@ -3,10 +3,10 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { AppProps, I18nProps } from '@polkadot/react-components/types';
+import { AppProps as Props } from '@polkadot/react-components/types';
import { ComponentProps } from './types';
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useMemo, useState } from 'react';
import { Route, Switch } from 'react-router';
import { Icon, Tabs } from '@polkadot/react-components';
import { useCall, useAccounts, useApi } from '@polkadot/react-hooks';
@@ -14,16 +14,25 @@ import { useCall, useAccounts, useApi } from '@polkadot/react-hooks';
import SetKey from './SetKey';
import Sudo from './Sudo';
-import translate from './translate';
+import { useTranslation } from './translate';
-interface Props extends AppProps, I18nProps {
-}
-
-function SudoApp ({ basePath, t }: Props): React.ReactElement {
+export default function SudoApp ({ basePath }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const sudoKey = useCall(api.query.sudo.key, [], { transform: (k): string => k.toString() });
const { allAccounts } = useAccounts();
const [isMine, setIsMine] = useState(false);
+ const items = useMemo(() => [
+ {
+ isRoot: true,
+ name: 'index',
+ text: t('Sudo access')
+ },
+ {
+ name: 'key',
+ text: t('Set sudo key')
+ }
+ ], [t]);
useEffect((): void => {
setIsMine(!!sudoKey && allAccounts.some((key): boolean => key === sudoKey));
@@ -47,17 +56,7 @@ function SudoApp ({ basePath, t }: Props): React.ReactElement {
{isMine
@@ -79,5 +78,3 @@ function SudoApp ({ basePath, t }: Props): React.ReactElement {
);
}
-
-export default translate(SudoApp);
diff --git a/packages/app-tech-comm/package.json b/packages/app-tech-comm/package.json
index 56bb2c3d16b9..6857ef5938eb 100644
--- a/packages/app-tech-comm/package.json
+++ b/packages/app-tech-comm/package.json
@@ -1,6 +1,6 @@
{
"name": "@polkadot/app-tech-comm",
- "version": "0.39.0-beta.70",
+ "version": "0.40.0-beta.1",
"description": "Council",
"main": "index.js",
"scripts": {},
@@ -10,8 +10,8 @@
],
"license": "Apache-2.0",
"dependencies": {
- "@babel/runtime": "^7.7.7",
- "@polkadot/react-components": "^0.39.0-beta.70",
- "@polkadot/react-query": "^0.39.0-beta.70"
+ "@babel/runtime": "^7.8.3",
+ "@polkadot/react-components": "^0.40.0-beta.1",
+ "@polkadot/react-query": "^0.40.0-beta.1"
}
}
diff --git a/packages/app-tech-comm/src/Overview/Members.tsx b/packages/app-tech-comm/src/Overview/Members.tsx
index 2302f9144259..92395ad9b171 100644
--- a/packages/app-tech-comm/src/Overview/Members.tsx
+++ b/packages/app-tech-comm/src/Overview/Members.tsx
@@ -3,19 +3,20 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { AccountId } from '@polkadot/types/interfaces';
-import { I18nProps } from '@polkadot/react-components/types';
import React from 'react';
import { AddressSmall, Table } from '@polkadot/react-components';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
- members?: AccountId[];
+interface Props {
className?: string;
+ members?: AccountId[];
}
-function Members ({ className, members, t }: Props): React.ReactElement {
+export default function Members ({ className, members }: Props): React.ReactElement {
+ const { t } = useTranslation();
+
return (
{members?.length
@@ -37,5 +38,3 @@ function Members ({ className, members, t }: Props): React.ReactElement
{
);
}
-
-export default translate(Members);
diff --git a/packages/app-tech-comm/src/Overview/Summary.tsx b/packages/app-tech-comm/src/Overview/Summary.tsx
index 79dcaaa69639..9f2dc426deb5 100644
--- a/packages/app-tech-comm/src/Overview/Summary.tsx
+++ b/packages/app-tech-comm/src/Overview/Summary.tsx
@@ -3,8 +3,7 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
-import { ComponentProps } from '../types';
+import { ComponentProps as Props } from '../types';
import React from 'react';
import { SummaryBox, CardSummary } from '@polkadot/react-components';
@@ -12,11 +11,10 @@ import { useApi, useCall } from '@polkadot/react-hooks';
import { u32 } from '@polkadot/types';
import { formatNumber } from '@polkadot/util';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends ComponentProps, I18nProps {}
-
-function Summary ({ className, members, proposals, t }: Props): React.ReactElement {
+export default function Summary ({ className, members, proposals }: Props): React.ReactElement {
+ const { t } = useTranslation();
const { api } = useApi();
const proposalCount = useCall(api.query.technicalCommittee.proposalCount, []);
@@ -36,5 +34,3 @@ function Summary ({ className, members, proposals, t }: Props): React.ReactEleme
);
}
-
-export default translate(Summary);
diff --git a/packages/app-tech-comm/src/Overview/index.tsx b/packages/app-tech-comm/src/Overview/index.tsx
index 3549b117d299..3f484cd82959 100644
--- a/packages/app-tech-comm/src/Overview/index.tsx
+++ b/packages/app-tech-comm/src/Overview/index.tsx
@@ -2,18 +2,14 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
-import { ComponentProps } from '../types';
+import { ComponentProps as Props } from '../types';
import React from 'react';
-import translate from '../translate';
import Members from './Members';
import Summary from './Summary';
-interface Props extends I18nProps, ComponentProps {}
-
-function Overview ({ className, members, proposals }: Props): React.ReactElement {
+export default function Overview ({ className, members, proposals }: Props): React.ReactElement {
return (
);
}
-
-export default translate(Overview);
diff --git a/packages/app-tech-comm/src/Proposals/Proposal.tsx b/packages/app-tech-comm/src/Proposals/Proposal.tsx
index f08676b696c4..09e1f3ead011 100644
--- a/packages/app-tech-comm/src/Proposals/Proposal.tsx
+++ b/packages/app-tech-comm/src/Proposals/Proposal.tsx
@@ -3,7 +3,6 @@
// of the Apache-2.0 license. See the LICENSE file for details.
import { Proposal as ProposalType, Votes } from '@polkadot/types/interfaces';
-import { I18nProps } from '@polkadot/react-components/types';
import React from 'react';
import { AddressMini } from '@polkadot/react-components';
@@ -12,14 +11,16 @@ import ProposalCell from '@polkadot/app-democracy/Overview/ProposalCell';
import { Option } from '@polkadot/types';
import { formatNumber } from '@polkadot/util';
-import translate from '../translate';
+import { useTranslation } from '../translate';
import Voting from './Voting';
-interface Props extends I18nProps {
+interface Props {
+ className?: string;
hash: string;
}
-function Proposal ({ className, hash, t }: Props): React.ReactElement | null {
+export default function Proposal ({ className, hash }: Props): React.ReactElement | null {
+ const { t } = useTranslation();
const { api } = useApi();
const optProposal = useCall>(api.query.technicalCommittee.proposalOf, [hash]);
const votes = useCall >(api.query.technicalCommittee.voting, [hash]);
@@ -72,5 +73,3 @@ function Proposal ({ className, hash, t }: Props): React.ReactElement | n
);
}
-
-export default translate(Proposal);
diff --git a/packages/app-tech-comm/src/Proposals/Propose.tsx b/packages/app-tech-comm/src/Proposals/Propose.tsx
index 64651415b8a8..c64c0a2c3563 100644
--- a/packages/app-tech-comm/src/Proposals/Propose.tsx
+++ b/packages/app-tech-comm/src/Proposals/Propose.tsx
@@ -2,7 +2,6 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
-import { I18nProps } from '@polkadot/react-components/types';
import { TxSource, TxDef } from '@polkadot/react-hooks/types';
import { Call, Proposal } from '@polkadot/types/interfaces';
@@ -13,17 +12,15 @@ import { Extrinsic, InputNumber, TxModalNew as TxModal } from '@polkadot/react-c
import { useApi, useTx } from '@polkadot/react-hooks';
import { createType } from '@polkadot/types';
-import translate from '../translate';
+import { useTranslation } from '../translate';
-interface Props extends I18nProps {
+interface Props {
memberCount?: number;
onClose: () => void;
}
-function Propose ({ t, onClose, memberCount = 0 }: Props): React.ReactElement {
- const _hasThreshold = (threshold?: BN | null): boolean =>
- !!threshold && !threshold.isZero() && threshold.lten(memberCount);
-
+export default function Propose ({ onClose, memberCount = 0 }: Props): React.ReactElement