Add summaries for new pages (#7949)

* Add summaries for new pages

* Detect voting type

* Add member summaries

* linting

* Rebuild i18n
This commit is contained in:
Jaco 2022-08-01 09:52:23 +02:00 committed by GitHub
parent b131b8fd4c
commit 5b14f26452
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 274 additions and 94 deletions

View File

@ -1,6 +1,5 @@
{
"Allowed to vote on motions": "Allowed to vote on motions",
"Announcements": "Announcements",
"Announcements ({{count}})": "Announcements ({{count}})",
"Current prime member, default voting": "Current prime member, default voting",
"Join": "Join",

View File

@ -60,11 +60,9 @@
"recv": "recv",
"refresh in": "refresh in",
"requests": "requests",
"requests & subscriptions": "requests & subscriptions",
"role": "role",
"sent": "sent",
"session": "session",
"signer": "signer",
"state": "state",
"std dev": "std dev",
"subscriptions": "subscriptions",

View File

@ -6,7 +6,6 @@
"Submit Unsigned": "Submit Unsigned",
"decoded call": "decoded call",
"encoded call data": "encoded call data",
"encoded call details": "encoded call details",
"encoded call hash": "encoded call hash",
"encoding details": "encoding details",
"free balance": "free balance",

View File

@ -11,6 +11,7 @@
"This account will pay the fees for the preimage, based on the size thereof.": "This account will pay the fees for the preimage, based on the size thereof.",
"When submitting a proposal the hash needs to be known. Proposals can be submitted with hash-only, but upon dispatch the preimage needs to be available.": "When submitting a proposal the hash needs to be known. Proposals can be submitted with hash-only, but upon dispatch the preimage needs to be available.",
"calculated storage fee": "calculated storage fee",
"count": "count",
"preimage hash": "preimage hash",
"preimages": "preimages",
"proposal": "proposal",

View File

@ -1,8 +1,8 @@
{
"No members found": "No members found",
"Overview": "Overview",
"Referenda": "Referenda",
"Referenda ({{count}})": "Referenda ({{count}})",
"members": "members",
"rank": "rank"
"rank": "rank",
"total": "total"
}

View File

@ -1,6 +1,10 @@
{
"Aye": "Aye",
"Aye {{count}}": "Aye {{count}}",
"Conviction locks do overlap and are not additive, meaning that funds locked during a previous vote can be locked again.": "Conviction locks do overlap and are not additive, meaning that funds locked during a previous vote can be locked again.",
"If this proposal is passed, the changes will be applied via dispatch and the deposit returned.": "If this proposal is passed, the changes will be applied via dispatch and the deposit returned.",
"Nay": "Nay",
"Nay {{count}}": "Nay {{count}}",
"No referendums found": "No referendums found",
"Overview": "Overview",
"The balance associated with the vote will be locked as per the conviction specified and will not be available for transfer during this period.": "The balance associated with the vote will be locked as per the conviction specified and will not be available for transfer during this period.",
@ -13,5 +17,6 @@
"conviction": "conviction",
"preimage": "preimage",
"preimage {{shortHash}}": "preimage {{shortHash}}",
"referenda": "referenda"
"referenda": "referenda",
"total": "total"
}

View File

@ -2,14 +2,11 @@
"Crypto not detected": "Crypto not detected",
"Cryptography used to create this signature. It is auto-detected on valid signatures.": "Cryptography used to create this signature. It is auto-detected on valid signatures.",
"Detection on the input string to determine if it is hex or non-hex.": "Detection on the input string to determine if it is hex or non-hex.",
"Hash data": "Hash data",
"No": "No",
"Sign message": "Sign message",
"The account that signed the input": "The account that signed the input",
"The account's password specified at the creation of this account.": "The account's password specified at the creation of this account.",
"The blake2b 256-bit hash of the actual input data.": "The blake2b 256-bit hash of the actual input data.",
"The data that was signed. This is used in combination with the signature for the verification. It can either be hex or a string.": "The data that was signed. This is used in combination with the signature for the verification. It can either be hex or a string.",
"The input data to hash. This can be either specified as a hex value (0x-prefix) or as a string.": "The input data to hash. This can be either specified as a hex value (0x-prefix) or as a string.",
"The input data to sign. This can be either specified as a hex value (0x-prefix) or as a string.": "The input data to sign. This can be either specified as a hex value (0x-prefix) or as a string.",
"The resulting signature of the input data, as done with the crypto algorithm from the account. (This could be non-deterministic for some types such as sr25519).": "The resulting signature of the input data, as done with the crypto algorithm from the account. (This could be non-deterministic for some types such as sr25519).",
"The selected account to be unlocked.": "The selected account to be unlocked.",
@ -24,14 +21,12 @@
"Yes": "Yes",
"You need to unlock this account to be able to sign data.": "You need to unlock this account to be able to sign data.",
"account": "account",
"from the following data": "from the following data",
"hex input data": "hex input data",
"password": "password",
"select the account you wish to sign data with": "select the account you wish to sign data with",
"sign the following data": "sign the following data",
"signature crypto type": "signature crypto type",
"signature of supplied data": "signature of supplied data",
"the resulting hash is": "the resulting hash is",
"the supplied signature": "the supplied signature",
"using the following data": "using the following data",
"verify using address": "verify using address"

View File

@ -239,8 +239,6 @@
"capacity < {{maxCap}}%": "capacity < {{maxCap}}%",
"claimable": "claimable",
"comm.": "comm.",
"comm. < median": "comm. < median",
"comm. < {{maxComm}}%": "comm. < {{maxComm}}%",
"comm. <= median": "comm. <= median",
"comm. <= {{maxComm}}%": "comm. <= {{maxComm}}%",
"commission": "commission",
@ -276,7 +274,6 @@
"max. members": "max. members",
"max. members / pool": "max. members / pool",
"member account": "member account",
"members": "members",
"min": "min",
"min nominated": "min nominated",
"min nominated / threshold": "min nominated / threshold",

View File

@ -11,7 +11,6 @@
"No approved proposals": "No approved proposals",
"No open tips": "No open tips",
"No pending proposals": "No pending proposals",
"Of the beneficiary amount, at least {{bondPercentage}} would need to be put up as collateral. The maximum of this and the minimum bond will be used to secure the proposal, refundable if it passes.": "Of the beneficiary amount, at least {{bondPercentage}} would need to be put up as collateral. The maximum of this and the minimum bond will be used to secure the proposal, refundable if it passes.",
"Of the beneficiary amount, no less than the minimum bond amount and no more than maximum on-chain bond would need to be put up as collateral. This is calculated from {{bondPercentage}} of the requested amount.": "Of the beneficiary amount, no less than the minimum bond amount and no more than maximum on-chain bond would need to be put up as collateral. This is calculated from {{bondPercentage}} of the requested amount.",
"Of the beneficiary amount, no less than the minimum bond amount would need to be put up as collateral. This is calculated from {{bondPercentage}} of the requested amount.": "Of the beneficiary amount, no less than the minimum bond amount would need to be put up as collateral. This is calculated from {{bondPercentage}} of the requested amount.",
"Overview": "Overview",

View File

@ -358,7 +358,6 @@
"scheduled": "",
"secret": "",
"sending from my account": "",
"signer": "",
"size": "",
"somebody@example.com": "",
"stash": "",

View File

@ -36,13 +36,13 @@ function Summary ({ className, members, rule }: Props): React.ReactElement<Props
)
: t<string>('yes')
: t<string>('no')
: <Spinner />
: <Spinner noLabel />
}
</CardSummary>
<CardSummary label={t<string>('members')}>
{members
? formatNumber(members.length)
: <Spinner />
: <Spinner noLabel />
}
</CardSummary>
</SummaryBox>

View File

@ -11,7 +11,7 @@ import { Available } from '@polkadot/react-query';
import { BN, BN_ZERO } from '@polkadot/util';
import { blake2AsHex } from '@polkadot/util-crypto';
import { useTranslation } from './translate';
import { useTranslation } from '../translate';
interface Props {
className?: string;

View File

@ -8,8 +8,8 @@ import React from 'react';
import { CallExpander } from '@polkadot/react-components';
import { formatNumber } from '@polkadot/util';
import { useTranslation } from './translate';
import usePreimage from './usePreimage';
import { useTranslation } from '../translate';
import usePreimage from '../usePreimage';
interface Props {
className?: string;
@ -22,9 +22,7 @@ function Preimage ({ className, value }: Props): React.ReactElement<Props> {
return (
<tr className={ className }>
<td>
{value}
</td>
<td>{value}</td>
<td className='all'>
{info && info.proposal && (
<CallExpander
@ -39,6 +37,9 @@ function Preimage ({ className, value }: Props): React.ReactElement<Props> {
<td className='number'>
{info && info.status && info.status.type}
</td>
<td className='number'>
{info && info.count !== 0 && formatNumber(info.count)}
</td>
</tr>
);
}

View File

@ -7,10 +7,10 @@ import React, { useRef } from 'react';
import { Button, Table } from '@polkadot/react-components';
import { useTranslation } from '../translate';
import usePreimages from '../usePreimages';
import Add from './Add';
import Preimage from './Preimage';
import { useTranslation } from './translate';
import usePreimages from './usePreimages';
interface Props {
className?: string;
@ -25,7 +25,8 @@ function Hashes ({ className }: Props): React.ReactElement<Props> {
const headerRef = useRef([
[t('preimages'), 'start', 2],
[t('size')],
[t('status')]
[t('status')],
[t('count')]
]);
return (

View File

@ -6,6 +6,7 @@ import type { Call } from '@polkadot/types/interfaces';
import type { PalletPreimageRequestStatus } from '@polkadot/types/lookup';
export interface Preimage {
count: number;
bytes: Bytes | null;
proposal: Call | null;
status: PalletPreimageRequestStatus | null;

View File

@ -12,8 +12,10 @@ import { useMemo } from 'react';
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
function createResult (api: ApiPromise, preimage: Option<Bytes>, status: Option<PalletPreimageRequestStatus>): Preimage {
function createResult (api: ApiPromise, preimage: Option<Bytes>, optStatus: Option<PalletPreimageRequestStatus>): Preimage {
const bytes = preimage.unwrapOr(null);
const status = optStatus.unwrapOr(null);
let count = 0;
let proposal: Call | null = null;
if (bytes) {
@ -24,10 +26,15 @@ function createResult (api: ApiPromise, preimage: Option<Bytes>, status: Option<
}
}
if (status && status.isRequested) {
count = status.asRequested.toNumber();
}
return {
bytes,
count,
proposal,
status: status.unwrapOr(null)
status
};
}

View File

@ -50,7 +50,6 @@ function App ({ basePath, className, palletColl, palletPoll }: Props): React.Rea
<Switch>
<Route path={`${basePath}/referenda`}>
<Referenda
isVoteBasic
members={members && members.memberIds}
palletReferenda={palletPoll}
palletVote={palletColl}

View File

@ -1,7 +1,7 @@
// Copyright 2017-2022 @polkadot/app-ranked authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Member as MemberType } from './types';
import type { Member as MemberType } from '../types';
import React from 'react';

View File

@ -0,0 +1,33 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Member as MemberType } from '../types';
import React from 'react';
import { CardSummary, Spinner, SummaryBox } from '@polkadot/react-components';
import { formatNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
interface Props {
className?: string;
members?: MemberType[];
}
function Summary ({ className, members }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
return (
<SummaryBox className={className}>
<CardSummary label={t<string>('total')}>
{members === undefined
? <Spinner noLabel />
: formatNumber(members.length)
}
</CardSummary>
</SummaryBox>
);
}
export default React.memo(Summary);

View File

@ -1,14 +1,15 @@
// Copyright 2017-2022 @polkadot/app-ranked authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Member as MemberType } from './types';
import type { Member as MemberType } from '../types';
import React, { useRef } from 'react';
import { Table } from '@polkadot/react-components';
import { useTranslation } from '../translate';
import Member from './Member';
import { useTranslation } from './translate';
import Summary from './Summary';
interface Props {
className?: string;
@ -23,18 +24,21 @@ function Members ({ className, members }: Props): React.ReactElement<Props> {
]);
return (
<Table
className={className}
empty={members && t<string>('No members found')}
header={headerRef.current}
>
{members && members.map((a): React.ReactNode => (
<Member
key={a.accountId}
value={a}
/>
))}
</Table>
<div className={className}>
<Summary members={members} />
<Table
className={className}
empty={members && t<string>('No members found')}
header={headerRef.current}
>
{members && members.map((a): React.ReactNode => (
<Member
key={a.accountId}
value={a}
/>
))}
</Table>
</div>
);
}

View File

@ -2,16 +2,17 @@
// SPDX-License-Identifier: Apache-2.0
import type { BN } from '@polkadot/util';
import type { Referendum, ReferendumProps as Props } from './types';
import type { Referendum, ReferendumProps as Props } from '../types';
import React, { useMemo } from 'react';
import usePreimage from '@polkadot/app-preimages/usePreimage';
import { CallExpander, Progress } from '@polkadot/react-components';
import { useTranslation } from '../translate';
import Deposit from './Deposit';
import { useTranslation } from './translate';
import Vote from './Vote';
import Votes from './Votes';
interface Expanded {
ongoing: Referendum['info']['asOngoing'];
@ -30,7 +31,7 @@ function expandOngoing (info: Referendum['info']): Expanded {
};
}
function Ongoing ({ isMember, isVoteBasic, members, palletVote, value: { id, info } }: Props): React.ReactElement<Props> {
function Ongoing ({ isMember, members, palletVote, value: { id, info, isConvictionVote } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { ongoing: { decisionDeposit, proposalHash, submissionDeposit, tally }, shortHash, tallyTotal } = useMemo(
() => expandOngoing(info),
@ -56,6 +57,12 @@ function Ongoing ({ isMember, isVoteBasic, members, palletVote, value: { id, inf
decision={decisionDeposit}
submit={submissionDeposit}
/>
<Votes
id={id}
isConvictionVote={isConvictionVote}
palletVote={palletVote}
tally={tally}
/>
<td className='middle chart'>
<Progress
total={tallyTotal}
@ -66,8 +73,8 @@ function Ongoing ({ isMember, isVoteBasic, members, palletVote, value: { id, inf
{preimage && (
<Vote
id={id}
isConvictionVote={isConvictionVote}
isMember={isMember}
isVoteBasic={isVoteBasic}
members={members}
palletVote={palletVote}
preimage={preimage}

View File

@ -1,7 +1,7 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ReferendumProps as Props } from './types';
import type { ReferendumProps as Props } from '../types';
import React from 'react';
@ -9,7 +9,7 @@ function RefOther ({ value: { info: { type } } }: Props): React.ReactElement<Pro
return (
<td
className='number'
colSpan={3}
colSpan={5}
>
{type}
</td>

View File

@ -3,7 +3,7 @@
import type { Option } from '@polkadot/types';
import type { PalletReferendaDeposit } from '@polkadot/types/lookup';
import type { Referendum, ReferendumProps as Props } from './types';
import type { Referendum, ReferendumProps as Props } from '../types';
import React, { useMemo } from 'react';
@ -54,7 +54,10 @@ function Tuple ({ value: { info } }: Props): React.ReactElement<Props> {
decision={decision}
submit={submit}
/>
<td className='number'>
<td
className='number'
colSpan={2}
>
{when && (
when.toUTCString()
)}

View File

@ -1,7 +1,7 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ReferendumProps as Props } from './types';
import type { ReferendumProps as Props } from '../types';
import React, { useMemo } from 'react';

View File

@ -0,0 +1,33 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Summary as SummaryType } from '../types';
import React from 'react';
import { CardSummary, Spinner, SummaryBox } from '@polkadot/react-components';
import { formatNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
interface Props {
className?: string;
summary: SummaryType;
}
function Summary ({ className, summary: { refCount } }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
return (
<SummaryBox className={className}>
<CardSummary label={t<string>('total')}>
{refCount === undefined
? <Spinner noLabel />
: formatNumber(refCount)
}
</CardSummary>
</SummaryBox>
);
}
export default React.memo(Summary);

View File

@ -3,25 +3,25 @@
import type { Preimage } from '@polkadot/app-preimages/types';
import type { BN } from '@polkadot/util';
import type { PalletVote } from './types';
import type { PalletVote } from '../types';
import React, { useState } from 'react';
import { Button, ConvictionDropdown, Modal, ProposedAction, TxButton, VoteAccount, VoteValue } from '@polkadot/react-components';
import { useAccounts, useApi, useToggle } from '@polkadot/react-hooks';
import { useTranslation } from './translate';
import { useTranslation } from '../translate';
interface Props {
id: BN;
isConvictionVote: boolean;
isMember: boolean;
isVoteBasic: boolean;
members?: string[];
palletVote: PalletVote;
preimage: Preimage;
}
function Voting ({ id, isMember, isVoteBasic, members, palletVote, preimage: { proposal } }: Props): React.ReactElement<Props> | null {
function Voting ({ id, isConvictionVote, isMember, members, palletVote, preimage: { proposal } }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const { hasAccounts } = useAccounts();
@ -55,7 +55,7 @@ function Voting ({ id, isMember, isVoteBasic, members, palletVote, preimage: { p
onChange={setAccountId}
/>
</Modal.Columns>
{!isVoteBasic && (
{isConvictionVote && (
<Modal.Columns
hint={
<>
@ -86,9 +86,9 @@ function Voting ({ id, isMember, isVoteBasic, members, palletVote, preimage: { p
label={t<string>('Vote Nay')}
onStart={toggleVoting}
params={
isVoteBasic
? [id, false]
: [id, { Standard: { balance, vote: { aye: false, conviction } } }]
isConvictionVote
? [id, { Standard: { balance, vote: { aye: false, conviction } } }]
: [id, false]
}
tx={api.tx[palletVote].vote}
/>
@ -99,9 +99,9 @@ function Voting ({ id, isMember, isVoteBasic, members, palletVote, preimage: { p
label={t<string>('Vote Aye')}
onStart={toggleVoting}
params={
isVoteBasic
? [id, true]
: [id, { Standard: { balance, vote: { aye: true, conviction } } }]
isConvictionVote
? [id, { Standard: { balance, vote: { aye: true, conviction } } }]
: [id, true]
}
tx={api.tx[palletVote].vote}
/>

View File

@ -0,0 +1,64 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { PalletConvictionVotingTally, PalletRankedCollectiveTally } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { PalletVote } from '../types';
import React from 'react';
import { Expander } from '@polkadot/react-components';
import { FormatBalance } from '@polkadot/react-query';
import { useTranslation } from '../translate';
interface Props {
className?: string;
id: BN;
isConvictionVote: boolean;
palletVote: PalletVote;
tally: PalletConvictionVotingTally | PalletRankedCollectiveTally;
}
function Votes ({ className = '', isConvictionVote, tally }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
return (
<td className={`${className} expand`}>
{isConvictionVote
? (
<>
<Expander
summary={
<>
{t<string>('Aye')}
<div><FormatBalance value={tally.ayes} /></div>
</>
}
/>
<Expander
summary={
<>
{t<string>('Nay')}
<div><FormatBalance value={tally.ayes} /></div>
</>
}
/>
</>
)
: (
<>
<Expander
summary={t<string>('Aye {{count}}', { replace: { count: tally.ayes.toNumber() } })}
/>
<Expander
summary={t<string>('Nay {{count}}', { replace: { count: tally.nays.toNumber() } })}
/>
</>
)
}
</td>
);
}
export default React.memo(Votes);

View File

@ -1,29 +1,31 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { PalletReferenda, PalletVote } from './types';
import type { PalletReferenda, PalletVote } from '../types';
import React, { useMemo, useRef } from 'react';
import { Table } from '@polkadot/react-components';
import { useAccounts } from '@polkadot/react-hooks';
import { useTranslation } from '../translate';
import useReferenda from '../useReferenda';
import useSummary from '../useSummary';
import Referendum from './Referendum';
import { useTranslation } from './translate';
import useReferenda from './useReferenda';
import Summary from './Summary';
interface Props {
className?: string;
isVoteBasic: boolean;
members?: string[];
palletReferenda: PalletReferenda;
palletVote: PalletVote;
}
function Referenda ({ className, isVoteBasic, members, palletReferenda, palletVote }: Props): React.ReactElement<Props> {
function Referenda ({ className, members, palletReferenda, palletVote }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { allAccounts } = useAccounts();
const referenda = useReferenda(palletReferenda);
const summary = useSummary(palletReferenda);
const isMember = useMemo(
() => !members || allAccounts.some((a) => members.includes(a)),
@ -37,6 +39,7 @@ function Referenda ({ className, isVoteBasic, members, palletReferenda, palletVo
return (
<div className={className}>
<Summary summary={summary} />
<Table
className={className}
empty={referenda && t<string>('No referendums found')}
@ -45,7 +48,6 @@ function Referenda ({ className, isVoteBasic, members, palletReferenda, palletVo
{referenda && referenda.map((r) => (
<Referendum
isMember={isMember}
isVoteBasic={isVoteBasic}
key={r.key}
members={members}
palletVote={palletVote}

View File

@ -31,7 +31,6 @@ function App ({ basePath, className }: Props): React.ReactElement<Props> {
items={tabsRef.current}
/>
<Referenda
isVoteBasic={false}
palletReferenda='referenda'
palletVote='convictionVoting'
/>

View File

@ -1,24 +1,29 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { PalletReferendaReferendumInfoConvictionVotingTally } from '@polkadot/types/lookup';
import type { PalletReferendaReferendumInfoConvictionVotingTally, PalletReferendaReferendumInfoRankedCollectiveTally } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
export type PalletReferenda = 'referenda' | 'rankedPolls' | 'fellowshipReferenda';
export type PalletVote = 'convictionVoting' | 'rankedCollective' | 'fellowshipCollective';
export interface Referendum {
id: BN;
info: PalletReferendaReferendumInfoConvictionVotingTally;
info: PalletReferendaReferendumInfoConvictionVotingTally | PalletReferendaReferendumInfoRankedCollectiveTally;
isConvictionVote: boolean;
key: string;
}
export interface ReferendumProps {
className?: string;
isMember: boolean;
isVoteBasic: boolean;
members?: string[];
palletVote: PalletVote;
value: Referendum;
}
export type PalletReferenda = 'referenda' | 'rankedPolls' | 'fellowshipReferenda';
export type PalletVote = 'convictionVoting' | 'rankedCollective' | 'fellowshipCollective';
export interface Summary {
deciding?: BN;
refCount?: BN;
}

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { Option } from '@polkadot/types';
import type { PalletReferendaReferendumInfoConvictionVotingTally } from '@polkadot/types/lookup';
import type { PalletReferendaReferendumInfoConvictionVotingTally, PalletReferendaReferendumInfoRankedCollectiveTally } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { PalletReferenda, Referendum } from './types';
@ -14,11 +14,12 @@ import useReferendaIds from './useReferendaIds';
const ORDER = <const> ['Ongoing', 'Approved', 'Rejected', 'Cancelled', 'Killed', 'TimedOut'];
function sortOngoing (a: Referendum, b: Referendum): number {
const ona = a.info.asOngoing;
const onb = b.info.asOngoing;
function isConvictionVote (info: Referendum['info']): info is PalletReferendaReferendumInfoConvictionVotingTally {
return info.isOngoing && !(info as PalletReferendaReferendumInfoRankedCollectiveTally).asOngoing.tally.bareAyes && !!(info as PalletReferendaReferendumInfoConvictionVotingTally).asOngoing.tally.support;
}
return ona.track.cmp(onb.track) || a.id.cmp(b.id);
function sortOngoing (a: Referendum, b: Referendum): number {
return a.info.asOngoing.track.cmp(b.info.asOngoing.track) || a.id.cmp(b.id);
}
function sortOther (a: Referendum, b: Referendum): number {
@ -37,17 +38,18 @@ function sortOther (a: Referendum, b: Referendum): number {
}
const OPT_MULTI = {
transform: ([[ids], all]: [[BN[]], Option<PalletReferendaReferendumInfoConvictionVotingTally>[]]) =>
transform: ([[ids], all]: [[BN[]], Option<Referendum['info']>[]]) =>
all
.map((o, i) =>
o.isSome
? [ids[i], o.unwrap()]
: null
)
.filter((r): r is [BN, PalletReferendaReferendumInfoConvictionVotingTally] => !!r)
.filter((r): r is [BN, Referendum['info']] => !!r)
.map(([id, info]): Referendum => ({
id,
info,
isConvictionVote: isConvictionVote(info),
key: id.toString()
}))
.sort((a, b) =>

View File

@ -0,0 +1,22 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { u32 } from '@polkadot/types';
import type { PalletReferenda, Summary } from './types';
import { useMemo } from 'react';
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
// TODO keep track of all tracks to get the number of deciding
function useSummaryImpl (palletReferenda: PalletReferenda): Summary {
const { api } = useApi();
const refCount = useCall<u32>(api.query[palletReferenda].referendumCount);
return useMemo(
() => ({ refCount }),
[refCount]
);
}
export default createNamedHook('useSummary', useSummaryImpl);

View File

@ -18,7 +18,7 @@ interface Props {
const MAX_REASON_LEN = 256;
const MIN_REASON_LEN = 5;
function TipCreate ({ members }: Props): React.ReactElement<Props> {
function TipCreate ({ members }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const { api } = useApi();
const [isOpen, toggleOpen] = useToggle();
@ -40,6 +40,10 @@ function TipCreate ({ members }: Props): React.ReactElement<Props> {
const hasValue = !!value && value.gt(BN_ZERO);
const hasReason = !!reason && (reason.length >= MIN_REASON_LEN) && (reason.length <= maxReasonLen);
if (!(api.tx.tips.tipNew || api.tx.treasury.tipNew)) {
return null;
}
return (
<>
<Button

View File

@ -7,9 +7,9 @@ import React, { useRef } from 'react';
import { Table } from '@polkadot/react-components';
import { useTranslation } from '../translate';
import useHashes from '../useHashes';
import Hash from './Hash';
import { useTranslation } from './translate';
import useHashes from './useHashes';
interface Props {
className?: string;

View File

@ -1,6 +1,7 @@
// Copyright 2017-2022 @polkadot/react-hooks authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { ApiPromise } from '@polkadot/api';
import type { EventRecord } from '@polkadot/types/interfaces';
import type { Codec } from '@polkadot/types/types';
import type { BN } from '@polkadot/util';
@ -10,6 +11,7 @@ import { useEffect, useState } from 'react';
import { isFunction } from '@polkadot/util';
import { useApi } from './useApi';
import { useEventTrigger } from './useEventTrigger';
export interface Changes<T extends Codec> {
@ -45,7 +47,8 @@ function interleave <T extends Codec> (existing: T[] = [], { added = [], removed
.map(([, v]) => v);
}
export function useEventChanges <T extends Codec> (checks: EventCheck[], filter: (records: EventRecord[]) => Changes<T>, startValue?: T[]): T[] | undefined {
export function useEventChanges <T extends Codec> (checks: EventCheck[], filter: (records: EventRecord[], api: ApiPromise) => Changes<T>, startValue?: T[]): T[] | undefined {
const { api } = useApi();
const [state, setState] = useState<T[] | undefined>();
const { blockHash, events } = useEventTrigger(checks);
@ -56,8 +59,8 @@ export function useEventChanges <T extends Codec> (checks: EventCheck[], filter:
// add/remove any additional items detected (only when actual events occur)
useEffect((): void => {
blockHash && setState((prev) => interleave(prev, filter(events)));
}, [blockHash, events, filter]);
blockHash && setState((prev) => interleave(prev, filter(events, api)));
}, [api, blockHash, events, filter]);
return state;
}