diff --git a/packages/page-staking/src/Legend.tsx b/packages/page-staking/src/Legend.tsx index ce727f6b77..f9ab96dba7 100644 --- a/packages/page-staking/src/Legend.tsx +++ b/packages/page-staking/src/Legend.tsx @@ -24,6 +24,13 @@ function Legend ({ className }: Props): React.ReactElement { /> {t('Next session')} + + + {t('Para validator')} + { +const NO_NOMS: { nominatorId: string }[] = []; + +function Status ({ isElected, isMain, isPara, nominators = NO_NOMS, onlineCount, onlineMessage }: Props): React.ReactElement { const { allAccounts } = useAccounts(); const blockCount = onlineCount && onlineCount.toNumber(); @@ -37,6 +40,15 @@ function Status ({ isElected, isMain, nominators = [], onlineCount, onlineMessag ) : } + {isPara + ? ( + + ) + : + } {isElected ? ( | null { +function Address ({ address, className = '', filterName, hasQueries, isElected, isFavorite, isMain, isPara, lastBlock, nominatedBy, points, recentlyOnline, toggleFavorite, validatorInfo, withIdentity }: Props): React.ReactElement | null { const { api } = useApi(); const { accountInfo, slashingSpans } = useAddressCalls(api, address, isMain); @@ -121,6 +122,7 @@ function Address ({ address, className = '', filterName, hasQueries, isElected, ; setNominators?: (nominators: string[]) => void; stakingOverview?: DeriveStakingOverview; targets: SortedTargets; @@ -71,7 +72,9 @@ function getFiltered (stakingOverview: DeriveStakingOverview, favorites: string[ }; } -function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, targets, toggleFavorite }: Props): React.ReactElement | null { +const DEFAULT_PARAS = {}; + +function CurrentList ({ favorites, hasQueries, isIntentions, paraValidators = DEFAULT_PARAS, stakingOverview, targets, toggleFavorite }: Props): React.ReactElement | null { const { t } = useTranslation(); const { api } = useApi(); const { byAuthor, eraPoints } = useContext(isIntentions ? EmptyAuthorsContext : BlockAuthorsContext); @@ -126,6 +129,7 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta isElected={isElected} isFavorite={isFavorite} isMain={isMain} + isPara={paraValidators[address]} key={address} lastBlock={byAuthor[address]} nominatedBy={nominatedBy ? (nominatedBy[address] || []) : undefined} @@ -136,7 +140,7 @@ function CurrentList ({ favorites, hasQueries, isIntentions, stakingOverview, ta withIdentity={toggles.withIdentity} /> )), - [byAuthor, eraPoints, hasQueries, infoMap, nameFilter, nominatedBy, recentlyOnline, toggleFavorite, toggles] + [byAuthor, eraPoints, hasQueries, infoMap, nameFilter, nominatedBy, paraValidators, recentlyOnline, toggleFavorite, toggles] ); return isIntentions diff --git a/packages/page-staking/src/Overview/index.tsx b/packages/page-staking/src/Overview/index.tsx index 0273a715e0..988f81eb87 100644 --- a/packages/page-staking/src/Overview/index.tsx +++ b/packages/page-staking/src/Overview/index.tsx @@ -13,13 +13,14 @@ interface Props { favorites: string[]; hasQueries: boolean; isIntentions?: boolean; + paraValidators?: Record; stakingOverview?: DeriveStakingOverview; targets: SortedTargets; toggleFavorite: (address: string) => void; toggleLedger?: () => void; } -function Overview ({ className = '', favorites, hasQueries, isIntentions, stakingOverview, targets, toggleFavorite, toggleLedger }: Props): React.ReactElement { +function Overview ({ className = '', favorites, hasQueries, isIntentions, paraValidators, stakingOverview, targets, toggleFavorite, toggleLedger }: Props): React.ReactElement { useEffect((): void => { toggleLedger && toggleLedger(); }, [toggleLedger]); @@ -30,6 +31,7 @@ function Overview ({ className = '', favorites, hasQueries, isIntentions, stakin favorites={favorites} hasQueries={hasQueries} isIntentions={isIntentions} + paraValidators={paraValidators} stakingOverview={stakingOverview} targets={targets} toggleFavorite={toggleFavorite} diff --git a/packages/page-staking/src/index.tsx b/packages/page-staking/src/index.tsx index 03a047be78..0036ddee16 100644 --- a/packages/page-staking/src/index.tsx +++ b/packages/page-staking/src/index.tsx @@ -3,7 +3,7 @@ import type { DeriveStakingOverview } from '@polkadot/api-derive/types'; import type { AppProps as Props, ThemeProps } from '@polkadot/react-components/types'; -import type { ElectionStatus } from '@polkadot/types/interfaces'; +import type { ElectionStatus, ParaValidatorIndex, ValidatorId } from '@polkadot/types/interfaces'; import React, { useCallback, useMemo, useState } from 'react'; import { Route, Switch } from 'react-router'; @@ -12,7 +12,7 @@ import styled from 'styled-components'; import { HelpOverlay } from '@polkadot/react-components'; import Tabs from '@polkadot/react-components/Tabs'; -import { useAccounts, useApi, useAvailableSlashes, useCall, useFavorites, useOwnStashInfos } from '@polkadot/react-hooks'; +import { useAccounts, useApi, useAvailableSlashes, useCall, useCallMulti, useFavorites, useOwnStashInfos } from '@polkadot/react-hooks'; import { isFunction } from '@polkadot/util'; import basicMd from './md/basic.md'; @@ -30,8 +30,14 @@ import useSortedTargets from './useSortedTargets'; const HIDDEN_ACC = ['actions', 'payout']; -const transformElection = { - transform: (status: ElectionStatus) => status.isOpen +const optionsParaValidators = { + defaultValue: [false, {}] as [boolean, Record], + transform: ([eraElectionStatus, validators, activeValidatorIndices]: [ElectionStatus | null, ValidatorId[] | null, ParaValidatorIndex[] | null]): [boolean, Record] => [ + !!eraElectionStatus && eraElectionStatus.isOpen, + validators && activeValidatorIndices + ? activeValidatorIndices.reduce((all, index) => ({ ...all, [validators[index.toNumber()].toString()]: true }), {}) + : {} + ] }; function StakingApp ({ basePath, className = '' }: Props): React.ReactElement { @@ -42,7 +48,11 @@ function StakingApp ({ basePath, className = '' }: Props): React.ReactElement(api.derive.staking.overview); - const isInElection = useCall(api.query.staking?.eraElectionStatus, undefined, transformElection); + const [isInElection, paraValidators] = useCallMulti<[boolean, Record]>([ + api.query.staking.eraElectionStatus, + api.query.session.validators, + (api.query.parasShared || api.query.shared)?.activeValidatorIndices + ], optionsParaValidators); const ownStashes = useOwnStashInfos(); const slashes = useAvailableSlashes(); const targets = useSortedTargets(favorites, withLedger); @@ -165,6 +175,7 @@ function StakingApp ({ basePath, className = '' }: Props): React.ReactElement