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:
parent
b131b8fd4c
commit
5b14f26452
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
{}
|
||||
@ -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"
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -358,7 +358,6 @@
|
||||
"scheduled": "",
|
||||
"secret": "",
|
||||
"sending from my account": "",
|
||||
"signer": "",
|
||||
"size": "",
|
||||
"somebody@example.com": "",
|
||||
"stash": "",
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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;
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
@ -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 (
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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';
|
||||
|
||||
33
packages/page-ranked/src/Members/Summary.tsx
Normal file
33
packages/page-ranked/src/Members/Summary.tsx
Normal 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);
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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}
|
||||
@ -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>
|
||||
@ -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()
|
||||
)}
|
||||
@ -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';
|
||||
|
||||
33
packages/page-referenda/src/Referenda/Summary.tsx
Normal file
33
packages/page-referenda/src/Referenda/Summary.tsx
Normal 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);
|
||||
@ -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}
|
||||
/>
|
||||
64
packages/page-referenda/src/Referenda/Votes.tsx
Normal file
64
packages/page-referenda/src/Referenda/Votes.tsx
Normal 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);
|
||||
@ -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}
|
||||
@ -31,7 +31,6 @@ function App ({ basePath, className }: Props): React.ReactElement<Props> {
|
||||
items={tabsRef.current}
|
||||
/>
|
||||
<Referenda
|
||||
isVoteBasic={false}
|
||||
palletReferenda='referenda'
|
||||
palletVote='convictionVoting'
|
||||
/>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) =>
|
||||
|
||||
22
packages/page-referenda/src/useSummary.ts
Normal file
22
packages/page-referenda/src/useSummary.ts
Normal 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);
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user