Recent payouts toggle (#4108)

* Recent payouts toggle

* operator exposure

* media--*

* extra toggle padding

* align
This commit is contained in:
Jaco Greeff 2020-11-30 01:50:32 +01:00 committed by GitHub
parent ae3f59568f
commit 837dd58c61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 10 deletions

View File

@ -121,7 +121,7 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
)}
</td>
<td className='number media--1200'>{numNominators || ''}</td>
<td className='number'>
<td className='number media--1100'>
{
isCommission
? `${commissionPer.toFixed(2)}%`
@ -129,7 +129,7 @@ function Validator ({ allSlashes, canSelect, filterName, info, isNominated, isSe
}
</td>
<td className='number together'>{!bondTotal.isZero() && <FormatBalance value={bondTotal} />}</td>
<td className='number together'>{!bondOwn.isZero() && <FormatBalance value={bondOwn} />}</td>
<td className='number together media--900'>{!bondOwn.isZero() && <FormatBalance value={bondOwn} />}</td>
<td className='number together media--1600'>{!bondOther.isZero() && <FormatBalance value={bondOther} />}</td>
<td className='number together'>{(stakedReturnCmp > 0) && <>{stakedReturnCmp.toFixed(2)}%</>}</td>
<td>

View File

@ -9,7 +9,7 @@ import BN from 'bn.js';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import styled from 'styled-components';
import { Button, Icon, Table, Toggle } from '@polkadot/react-components';
import { useApi, useAvailableSlashes, useCall } from '@polkadot/react-hooks';
import { useApi, useAvailableSlashes, useBlocksPerDays, useCall } from '@polkadot/react-hooks';
import ElectionBanner from '../ElectionBanner';
import Filtering from '../Filtering';
@ -31,10 +31,13 @@ interface Props {
}
interface Flags {
daysPayout: BN;
isBabe: boolean;
maxPaid: BN | undefined;
withElected: boolean;
withGroup: boolean;
withIdentity: boolean;
withPayout: boolean;
withoutComm: boolean;
withoutOver: boolean;
}
@ -46,15 +49,18 @@ interface SortState {
const CLASSES: Record<string, string> = {
rankBondOther: 'media--1600',
rankBondOwn: 'media--900',
rankComm: 'media--1100',
rankNumNominators: 'media--1200'
};
const MAX_COMM_FILTER = 20;
const MAX_DAYS = 7;
const SORT_KEYS = ['rankNumNominators', 'rankComm', 'rankBondTotal', 'rankBondOwn', 'rankBondOther', 'rankOverall'];
function filterValidators (validators: ValidatorInfo[], allIdentity: Record<string, DeriveHasIdentity>, { maxPaid, withElected, withGroup, withIdentity, withoutComm, withoutOver }: Flags): ValidatorInfo[] {
function filterValidators (validators: ValidatorInfo[], allIdentity: Record<string, DeriveHasIdentity>, { daysPayout, isBabe, maxPaid, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver }: Flags): ValidatorInfo[] {
const parentIds: string[] = [];
return validators.filter(({ accountId, commissionPer, isElected, isFavorite, numNominators }): boolean => {
return validators.filter(({ accountId, commissionPer, isElected, isFavorite, lastPayout, numNominators }): boolean => {
if (isFavorite) {
return true;
}
@ -63,8 +69,9 @@ function filterValidators (validators: ValidatorInfo[], allIdentity: Record<stri
const thisIdentity = allIdentity[stashId];
if (
(!withIdentity || !!thisIdentity?.hasIdentity) &&
(!withElected || isElected) &&
(!withIdentity || !!thisIdentity?.hasIdentity) &&
(!withPayout || !isBabe || (!!lastPayout && daysPayout.gte(lastPayout))) &&
(!withoutComm || (commissionPer < MAX_COMM_FILTER)) &&
(!withoutOver || !maxPaid || maxPaid.gtn(numNominators))
) {
@ -135,12 +142,14 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
const { t } = useTranslation();
const { api } = useApi();
const allSlashes = useAvailableSlashes();
const daysPayout = useBlocksPerDays(MAX_DAYS);
const ownNominators = useOwnNominators(ownStashes);
const [selected, setSelected] = useState<string[]>([]);
const [{ isQueryFiltered, nameFilter }, setNameFilter] = useState({ isQueryFiltered: false, nameFilter: '' });
const [withElected, setWithElected] = useState(false);
const [withGroup, setWithGroup] = useState(true);
const [withIdentity, setWithIdentity] = useState(false);
const [withPayout, setWithPayout] = useState(true);
const [withoutComm, setWithoutComm] = useState(true);
const [withoutOver, setWithoutOver] = useState(true);
const [{ sortBy, sortFromMax }, setSortBy] = useState<SortState>({ sortBy: 'rankOverall', sortFromMax: true });
@ -158,15 +167,18 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
const flags = useMemo(
() => ({
daysPayout,
isBabe: !!api.consts.babe,
isQueryFiltered,
maxPaid: api.consts.staking?.maxNominatorRewardedPerValidator,
withElected,
withGroup,
withIdentity,
withPayout,
withoutComm,
withoutOver
}),
[api, isQueryFiltered, withElected, withGroup, withIdentity, withoutComm, withoutOver]
[api, daysPayout, isQueryFiltered, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver]
);
const filtered = useMemo(
@ -242,7 +254,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
>
<Toggle
className='staking--buttonToggle'
label={t<string>('limit single operator exposure')}
label={t<string>('limit operator exposure')}
onChange={setWithGroup}
value={withGroup}
/>
@ -252,6 +264,15 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
onChange={setWithoutComm}
value={withoutComm}
/>
{api.consts.babe && (
// FIXME have some sane era defaults for Aura
<Toggle
className='staking--buttonToggle'
label={t<string>('recent payouts')}
onChange={setWithPayout}
value={withPayout}
/>
)}
<Toggle
className='staking--buttonToggle'
label={t<string>('no oversubscribed')}
@ -266,7 +287,7 @@ function Targets ({ className = '', isInElection, ownStashes, targets: { avgStak
/>
</Filtering>
</div>
), [nameFilter, _setNameFilter, t, withElected, withGroup, withIdentity, withoutComm, withoutOver]);
), [api, nameFilter, _setNameFilter, t, withElected, withGroup, withIdentity, withPayout, withoutComm, withoutOver]);
const displayList = isQueryFiltered
? validators

View File

@ -194,7 +194,9 @@ export default React.memo(styled(StakingApp)(({ theme }: ThemeProps) => `
}
.staking--optionsBar {
text-align: right;
margin: 0.5rem 0 1rem;
text-align: center;
white-space: normal;
.staking--buttonToggle {
display: inline-block;

View File

@ -8,6 +8,7 @@ export { useAddresses } from './useAddresses';
export { useApi } from './useApi';
export { useAvailableSlashes } from './useAvailableSlashes';
export { useBlockTime } from './useBlockTime';
export { useBlocksPerDays } from './useBlocksPerDays';
export { useCacheKey } from './useCacheKey';
export { useCall } from './useCall';
export { useContracts } from './useContracts';

View File

@ -0,0 +1,23 @@
// Copyright 2017-2020 @polkadot/app-democracy authors & contributors
// SPDX-License-Identifier: Apache-2.0
import BN from 'bn.js';
import { useMemo } from 'react';
import { useApi } from '@polkadot/react-hooks';
const DEFAULT_TIME = new BN(6000);
const A_DAY = new BN(24 * 60 * 60 * 1000);
export function useBlocksPerDays (days = 1): BN {
const { api } = useApi();
return useMemo(
() => A_DAY.muln(days).div(
api.consts.babe?.expectedBlockTime ||
api.consts.difficulty?.targetBlockTime ||
api.consts.timestamp?.minimumPeriod.muln(2) ||
DEFAULT_TIME
),
[api, days]
);
}