Make active/waiting click "snappy" (#7361)
This commit is contained in:
parent
ec02457b8f
commit
a983a07261
@ -15,8 +15,8 @@ interface Props {
|
||||
className?: string;
|
||||
nameFilter: string;
|
||||
setNameFilter: (value: string, isQuery: boolean) => void;
|
||||
setWithIdentity: (value: boolean) => void;
|
||||
withIdentity: boolean;
|
||||
setWithIdentity?: (value: boolean) => void;
|
||||
withIdentity?: boolean;
|
||||
}
|
||||
|
||||
function Filtering ({ children, className, nameFilter, setNameFilter, setWithIdentity, withIdentity }: Props): React.ReactElement<Props> | null {
|
||||
@ -47,17 +47,19 @@ function Filtering ({ children, className, nameFilter, setNameFilter, setWithIde
|
||||
onChange={_setNameFilter}
|
||||
value={nameFilter}
|
||||
/>
|
||||
<div className='staking--optionsBar'>
|
||||
{children}
|
||||
{api.query.identity && (
|
||||
<Toggle
|
||||
className='staking--buttonToggle'
|
||||
label={t<string>('with an identity')}
|
||||
onChange={setWithIdentity}
|
||||
value={withIdentity}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{(children || setWithIdentity) && (
|
||||
<div className='staking--optionsBar'>
|
||||
{children}
|
||||
{setWithIdentity && api.query.identity && (
|
||||
<Toggle
|
||||
className='staking--buttonToggle'
|
||||
label={t<string>('with an identity')}
|
||||
onChange={setWithIdentity}
|
||||
value={withIdentity}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ interface Props {
|
||||
recentlyOnline?: DeriveHeartbeatAuthor;
|
||||
toggleFavorite: (accountId: string) => void;
|
||||
validatorInfo?: ValidatorInfo;
|
||||
withIdentity: boolean;
|
||||
withIdentity?: boolean;
|
||||
}
|
||||
|
||||
interface StakingState {
|
||||
|
||||
@ -10,7 +10,7 @@ import type { NominatedByMap, SortedTargets, ValidatorInfo } from '../types';
|
||||
import React, { useContext, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Table } from '@polkadot/react-components';
|
||||
import { useApi, useCall, useLoadingDelay, useSavedFlags } from '@polkadot/react-hooks';
|
||||
import { useApi, useLoadingDelay } from '@polkadot/react-hooks';
|
||||
import { BlockAuthorsContext } from '@polkadot/react-query';
|
||||
|
||||
import Filtering from '../Filtering';
|
||||
@ -29,6 +29,7 @@ interface Props {
|
||||
nominatedBy?: NominatedByMap;
|
||||
ownStashIds?: string[];
|
||||
paraValidators?: Record<string, boolean>;
|
||||
recentlyOnline?: DeriveHeartbeats;
|
||||
setNominators?: (nominators: string[]) => void;
|
||||
stakingOverview?: DeriveStakingOverview;
|
||||
targets: SortedTargets;
|
||||
@ -73,7 +74,11 @@ function accountsToString (accounts: AccountId[]): string[] {
|
||||
return accounts.map((a) => a.toString());
|
||||
}
|
||||
|
||||
function getFiltered (isOwn: boolean, stakingOverview: DeriveStakingOverview, favorites: string[], next?: string[], ownStashIds?: string[]): Filtered {
|
||||
function getFiltered (isOwn: boolean, stakingOverview: DeriveStakingOverview | undefined, favorites: string[], next?: string[], ownStashIds?: string[]): Filtered {
|
||||
if (!stakingOverview) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const allElected = accountsToString(stakingOverview.nextElected);
|
||||
const validatorIds = accountsToString(stakingOverview.validators);
|
||||
|
||||
@ -87,24 +92,31 @@ function getFiltered (isOwn: boolean, stakingOverview: DeriveStakingOverview, fa
|
||||
|
||||
const DEFAULT_PARAS = {};
|
||||
|
||||
function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, minCommission, nominatedBy, ownStashIds, paraValidators = DEFAULT_PARAS, stakingOverview, targets, toggleFavorite }: Props): React.ReactElement<Props> | null {
|
||||
function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, minCommission, nominatedBy, ownStashIds, paraValidators = DEFAULT_PARAS, recentlyOnline, stakingOverview, targets, toggleFavorite }: Props): React.ReactElement<Props> | null {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { byAuthor, eraPoints } = useContext(isIntentions ? EmptyAuthorsContext : BlockAuthorsContext);
|
||||
const recentlyOnline = useCall<DeriveHeartbeats>(!isIntentions && api.derive.imOnline?.receivedHeartbeats);
|
||||
const [nameFilter, setNameFilter] = useState<string>('');
|
||||
const [toggles, setToggle] = useSavedFlags('staking:overview', { withIdentity: false });
|
||||
|
||||
// we have a very large list, so we use a loading delay
|
||||
const isLoading = useLoadingDelay();
|
||||
|
||||
const { validators, waiting } = useMemo(
|
||||
() => stakingOverview ? getFiltered(isOwn, stakingOverview, favorites, targets.waitingIds, ownStashIds) : {},
|
||||
() => getFiltered(isOwn, stakingOverview, favorites, targets.waitingIds, ownStashIds),
|
||||
[favorites, isOwn, ownStashIds, stakingOverview, targets]
|
||||
);
|
||||
|
||||
const list = useMemo(
|
||||
() => isLoading
|
||||
? undefined
|
||||
: isIntentions
|
||||
? nominatedBy && waiting
|
||||
: validators,
|
||||
[isIntentions, isLoading, nominatedBy, validators, waiting]
|
||||
);
|
||||
|
||||
const infoMap = useMemo(
|
||||
() => targets.validators?.reduce<Record<string, ValidatorInfo>>((result, info) => {
|
||||
() => targets.validators && targets.validators.reduce<Record<string, ValidatorInfo>>((result, info) => {
|
||||
result[info.key] = info;
|
||||
|
||||
return result;
|
||||
@ -137,11 +149,9 @@ function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, m
|
||||
<Table
|
||||
className={className}
|
||||
empty={
|
||||
!isLoading && (
|
||||
isIntentions
|
||||
? waiting && nominatedBy && t<string>('No waiting validators found')
|
||||
: recentlyOnline && validators && infoMap && t<string>('No active validators found')
|
||||
)
|
||||
isIntentions
|
||||
? list && t<string>('No waiting validators found')
|
||||
: list && recentlyOnline && infoMap && t<string>('No active validators found')
|
||||
}
|
||||
emptySpinner={
|
||||
<>
|
||||
@ -151,14 +161,13 @@ function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, m
|
||||
? !nominatedBy && <div>{t<string>('Retrieving nominators')}</div>
|
||||
: !recentlyOnline && <div>{t<string>('Retrieving online status')}</div>
|
||||
}
|
||||
{!list && <div>{t<string>('Preparing validator list')}</div>}
|
||||
</>
|
||||
}
|
||||
filter={
|
||||
<Filtering
|
||||
nameFilter={nameFilter}
|
||||
setNameFilter={setNameFilter}
|
||||
setWithIdentity={setToggle.withIdentity}
|
||||
withIdentity={toggles.withIdentity}
|
||||
/>
|
||||
}
|
||||
header={headerRef.current}
|
||||
@ -169,12 +178,7 @@ function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, m
|
||||
/>
|
||||
}
|
||||
>
|
||||
{!isLoading && (
|
||||
(isIntentions
|
||||
? nominatedBy && waiting
|
||||
: validators
|
||||
) || []
|
||||
).map(([address, isElected, isFavorite]): React.ReactNode => (
|
||||
{list && list.map(([address, isElected, isFavorite]): React.ReactNode => (
|
||||
<Address
|
||||
address={address}
|
||||
filterName={nameFilter}
|
||||
@ -191,7 +195,6 @@ function CurrentList ({ className, favorites, hasQueries, isIntentions, isOwn, m
|
||||
recentlyOnline={recentlyOnline?.[address]}
|
||||
toggleFavorite={toggleFavorite}
|
||||
validatorInfo={infoMap?.[address]}
|
||||
withIdentity={toggles.withIdentity}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright 2017-2022 @polkadot/app-staking authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { DeriveStakingOverview } from '@polkadot/api-derive/types';
|
||||
import type { DeriveHeartbeats, DeriveStakingOverview } from '@polkadot/api-derive/types';
|
||||
import type { StakerState } from '@polkadot/react-hooks/types';
|
||||
import type { BN } from '@polkadot/util';
|
||||
import type { NominatedByMap, SortedTargets } from '../types';
|
||||
@ -9,6 +9,7 @@ import type { NominatedByMap, SortedTargets } from '../types';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { Button, ToggleGroup } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import CurrentList from './CurrentList';
|
||||
@ -30,8 +31,10 @@ interface Props {
|
||||
|
||||
function Overview ({ className = '', favorites, hasQueries, minCommission, nominatedBy, ownStashes, paraValidators, stakingOverview, targets, toggleFavorite, toggleLedger, toggleNominatedBy }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [intentIndex, _setIntentIndex] = useState(0);
|
||||
const [typeIndex, setTypeIndex] = useState(1);
|
||||
const recentlyOnline = useCall<DeriveHeartbeats>(api.derive.imOnline?.receivedHeartbeats);
|
||||
|
||||
const setIntentIndex = useCallback(
|
||||
(index: number): void => {
|
||||
@ -77,32 +80,20 @@ function Overview ({ className = '', favorites, hasQueries, minCommission, nomin
|
||||
/>
|
||||
</Button.Group>
|
||||
<CurrentList
|
||||
className={intentIndex === 0 ? '' : '--hidden'}
|
||||
favorites={favorites}
|
||||
hasQueries={hasQueries}
|
||||
isIntentions={intentIndex === 1}
|
||||
isOwn={isOwn}
|
||||
minCommission={minCommission}
|
||||
key={intentIndex}
|
||||
minCommission={intentIndex === 0 ? minCommission : undefined}
|
||||
nominatedBy={intentIndex === 1 ? nominatedBy : undefined}
|
||||
ownStashIds={ownStashIds}
|
||||
paraValidators={paraValidators}
|
||||
recentlyOnline={intentIndex === 0 ? recentlyOnline : undefined}
|
||||
stakingOverview={stakingOverview}
|
||||
targets={targets}
|
||||
toggleFavorite={toggleFavorite}
|
||||
/>
|
||||
{intentIndex === 1 && (
|
||||
<CurrentList
|
||||
className={intentIndex === 1 ? '' : '--hidden'}
|
||||
favorites={favorites}
|
||||
hasQueries={hasQueries}
|
||||
isIntentions
|
||||
isOwn={isOwn}
|
||||
nominatedBy={nominatedBy}
|
||||
ownStashIds={ownStashIds}
|
||||
paraValidators={paraValidators}
|
||||
stakingOverview={stakingOverview}
|
||||
targets={targets}
|
||||
toggleFavorite={toggleFavorite}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -391,13 +391,14 @@ function Targets ({ className = '', isInElection, nominatedBy, ownStashes, targe
|
||||
<>
|
||||
{!(validators && allIdentity) && <div>{t('Retrieving validators')}</div>}
|
||||
{!nominatedBy && <div>{t('Retrieving nominators')}</div>}
|
||||
{!displayList && <div>{t('Preparing target display')}</div>}
|
||||
</>
|
||||
}
|
||||
filter={filter}
|
||||
header={header}
|
||||
legend={<Legend />}
|
||||
>
|
||||
{displayList?.map((info): React.ReactNode =>
|
||||
{displayList && displayList.map((info): React.ReactNode =>
|
||||
<Validator
|
||||
allSlashes={allSlashes}
|
||||
canSelect={selected.length < maxNominations}
|
||||
|
||||
@ -6,7 +6,7 @@ import { useEffect, useState } from 'react';
|
||||
import { createNamedHook } from './createNamedHook';
|
||||
import { useIsMountedRef } from './useIsMountedRef';
|
||||
|
||||
function useLoadingDelayImpl (delay = 100): boolean {
|
||||
function useLoadingDelayImpl (delay = 0): boolean {
|
||||
const mountedRef = useIsMountedRef();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user