diff --git a/packages/page-explorer/src/BlockInfo/Extrinsic.tsx b/packages/page-explorer/src/BlockInfo/Extrinsic.tsx
index dbba94334b..a196e1e094 100644
--- a/packages/page-explorer/src/BlockInfo/Extrinsic.tsx
+++ b/packages/page-explorer/src/BlockInfo/Extrinsic.tsx
@@ -112,6 +112,8 @@ function ExtrinsicDisplay ({ blockNumber, className = '', events, index, maxBloc
[index, events, maxBlockWeight]
);
+ const callName = `${section}.${method}`;
+
return (
{
+ const eventName = `${event.section}.${event.method}`;
+
return (
{event.data.length
? (
)
diff --git a/packages/page-referenda/package.json b/packages/page-referenda/package.json
index 8ab8151d2e..3b36dc98b6 100644
--- a/packages/page-referenda/package.json
+++ b/packages/page-referenda/package.json
@@ -14,5 +14,8 @@
"version": "0.122.3-132-x",
"dependencies": {
"@babel/runtime": "^7.20.6"
+ },
+ "devDependencies": {
+ "chart.js": "^3.9.1"
}
}
diff --git a/packages/page-referenda/src/Referenda/Group.tsx b/packages/page-referenda/src/Referenda/Group.tsx
index 975c698aa6..a4bf636e96 100644
--- a/packages/page-referenda/src/Referenda/Group.tsx
+++ b/packages/page-referenda/src/Referenda/Group.tsx
@@ -7,8 +7,8 @@ import type { PalletReferenda, PalletVote, ReferendaGroup, TrackDescription } fr
import React, { useMemo } from 'react';
import styled from 'styled-components';
-import { Table } from '@polkadot/react-components';
-import { useApi } from '@polkadot/react-hooks';
+import { ExpandButton, Table } from '@polkadot/react-components';
+import { useApi, useToggle } from '@polkadot/react-hooks';
import { useTranslation } from '../translate';
import { getTrackInfo } from '../util';
@@ -28,25 +28,51 @@ interface Props extends ReferendaGroup {
function Group ({ activeIssuance, className, isMember, members, palletReferenda, palletVote, ranks, referenda, trackId, trackName, tracks }: Props): React.ReactElement {
const { t } = useTranslation();
const { api, specName } = useApi();
+ const [isExpanded, toggleExpanded] = useToggle();
const trackInfo = useMemo(
() => getTrackInfo(api, specName, palletReferenda, tracks, trackId?.toNumber()),
[api, specName, palletReferenda, tracks, trackId]
);
+ const [headerButton, headerChildren] = useMemo(
+ () => [
+ false && trackInfo && (
+
+ ),
+ isExpanded && trackInfo && (
+
+ | Hello expanded |
+
+ )
+ ],
+ [isExpanded, toggleExpanded, trackInfo]
+ );
+
+ const [header, key] = useMemo(
+ () => [
+ [
+ [trackName ? <>{trackName}{trackInfo?.text}
> : t('referenda'), 'start', 5],
+ [undefined, 'number', 3],
+ [headerButton]
+ ],
+ trackName
+ ? `track:${trackName}`
+ : 'untracked'
+ ],
+ [headerButton, t, trackInfo, trackName]
+ );
+
return (
('No active referenda')}
- header={[
- [trackName ? <>{trackName}{trackInfo?.text}
> : t('referenda'), 'start', 7],
- [undefined, undefined, 3]
- ]}
- key={
- trackName
- ? `track:${trackName}`
- : 'untracked'
- }
+ header={header}
+ headerChildren={headerChildren}
+ key={key}
withCollapsibleRows
>
{referenda && referenda.map((r) => (
@@ -73,4 +99,9 @@ export default React.memo(styled(Group)`
padding-left: 1.5rem;
text-overflow: ellipsis;
}
+
+ th.number h1 {
+ display: inline-block;
+ opacity: 0.75;
+ }
`);
diff --git a/packages/page-referenda/src/Referenda/RefTuple.tsx b/packages/page-referenda/src/Referenda/RefTuple.tsx
index 2b15170ac8..189a9944e7 100644
--- a/packages/page-referenda/src/Referenda/RefTuple.tsx
+++ b/packages/page-referenda/src/Referenda/RefTuple.tsx
@@ -49,7 +49,10 @@ function Tuple ({ palletReferenda, value: { id, info, track } }: Props): React.R
return (
<>
- |
+ |
- |
>
);
}
diff --git a/packages/page-referenda/src/Referenda/Referendum.tsx b/packages/page-referenda/src/Referenda/Referendum.tsx
index 7a38200038..344f42726b 100644
--- a/packages/page-referenda/src/Referenda/Referendum.tsx
+++ b/packages/page-referenda/src/Referenda/Referendum.tsx
@@ -1,6 +1,7 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
+import type { ChartOptions } from 'chart.js';
import type { PalletConvictionVotingTally, PalletRankedCollectiveTally, PalletReferendaReferendumInfoConvictionVotingTally, PalletReferendaReferendumInfoRankedCollectiveTally } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { BaseReferendumProps as Props, CurveGraph, ReferendumProps } from '../types';
@@ -22,17 +23,27 @@ const COMPONENTS: Record> = {
Ongoing
};
-const VAL_COLORS = ['rgba(140, 140, 140, 0.65)', '#9c3333', '#339c33'];
+const VAL_COLORS = ['#ff8c00', '#9c3333', '#339c33'];
const BOX_COLORS = ['rgba(140, 140, 140, 0.2)', 'rgba(140, 0, 0, 0.2)', 'rgba(0, 140, 0, 0.2)'];
const PT_CUR = 0;
const PT_NEG = 1;
const PT_POS = 2;
-const OPTIONS = {
+const OPTIONS: ChartOptions = {
animation: {
duration: 0
},
aspectRatio: 2.25,
+ elements: {
+ point: {
+ hoverRadius: 6,
+ radius: 0
+ }
+ },
+ interaction: {
+ intersect: false,
+ mode: 'index'
+ },
maintainAspectRatio: true,
scales: {
y: {
@@ -115,12 +126,13 @@ function getChartResult (totalEligible: BN, isConvictionVote: boolean, info: Pal
function getChartProps (bestNumber: BN, chartProps: ChartResultExt[]): ChartProps[] {
return chartProps.map(({ changeX, currentY, labels, progress, since, trackGraph: { x }, values }, index): ChartProps => {
- const currentX = 100 * (
+ const maxX = labels.length;
+ const currentX = maxX * (
bestNumber.sub(since.add(x[0])).toNumber() / x[x.length - 1].sub(x[0]).toNumber()
);
const swapX = changeX === -1
? -1
- : 100 * (changeX / x.length);
+ : maxX * (changeX / x.length);
return {
colors: VAL_COLORS,
@@ -135,7 +147,7 @@ function getChartProps (bestNumber: BN, chartProps: ChartResultExt[]): ChartProp
borderWidth: 0,
type: 'box',
xMax: swapX === -1
- ? 100
+ ? maxX
: swapX,
xMin: 0,
yMax: currentY,
@@ -159,7 +171,7 @@ function getChartProps (bestNumber: BN, chartProps: ChartResultExt[]): ChartProp
backgroundColor: BOX_COLORS[2],
borderWidth: 0,
type: 'box',
- xMax: 100,
+ xMax: maxX,
xMin: swapX,
yMax: currentY,
yMin: 0
diff --git a/packages/page-referenda/src/Referenda/util.ts b/packages/page-referenda/src/Referenda/util.ts
index f4806efc59..1da935ed96 100644
--- a/packages/page-referenda/src/Referenda/util.ts
+++ b/packages/page-referenda/src/Referenda/util.ts
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { PalletReferendaDeposit } from '@polkadot/types/lookup';
+import type { Referendum } from '../types';
import { Option } from '@polkadot/types';
@@ -10,3 +11,14 @@ export function unwrapDeposit (value: PalletReferendaDeposit | Option
+ info.isOngoing &&
+ info.asOngoing.deciding.isSome
+ ).length;
+}
diff --git a/packages/page-referenda/src/types.ts b/packages/page-referenda/src/types.ts
index 5424a74d15..67a89d6791 100644
--- a/packages/page-referenda/src/types.ts
+++ b/packages/page-referenda/src/types.ts
@@ -74,6 +74,10 @@ export interface TrackInfo {
text?: string;
}
+export interface TrackInfoExt extends TrackInfo {
+ track: TrackDescription;
+}
+
export interface Lock {
classId: BN;
endBlock: BN;
diff --git a/packages/page-referenda/src/util.ts b/packages/page-referenda/src/util.ts
index 5e85e0ed96..69bf945aee 100644
--- a/packages/page-referenda/src/util.ts
+++ b/packages/page-referenda/src/util.ts
@@ -3,12 +3,12 @@
import type { ApiPromise } from '@polkadot/api';
import type { PalletConvictionVotingTally, PalletRankedCollectiveTally, PalletReferendaCurve, PalletReferendaReferendumInfoConvictionVotingTally, PalletReferendaReferendumInfoRankedCollectiveTally, PalletReferendaTrackInfo } from '@polkadot/types/lookup';
-import type { CurveGraph, TrackDescription, TrackInfo } from './types';
+import type { CurveGraph, TrackDescription, TrackInfoExt } from './types';
import { getGovernanceTracks } from '@polkadot/apps-config';
-import { BN, BN_BILLION, BN_ONE, BN_ZERO, bnMax, bnMin, formatNumber, stringPascalCase } from '@polkadot/util';
+import { BN, BN_BILLION, BN_ONE, BN_ZERO, bnMax, bnMin, formatNumber, objectSpread, stringPascalCase } from '@polkadot/util';
-const CALC_CURVE_LENGTH = 100;
+const CURVE_LENGTH = 500;
export function getTrackName (trackId: BN, { name }: PalletReferendaTrackInfo): string {
return `${
@@ -22,20 +22,23 @@ export function getTrackName (trackId: BN, { name }: PalletReferendaTrackInfo):
}`;
}
-export function getTrackInfo (api: ApiPromise, specName: string, palletReferenda: string, tracks?: TrackDescription[], trackId?: number): TrackInfo | undefined {
- let info: TrackInfo | undefined;
+export function getTrackInfo (api: ApiPromise, specName: string, palletReferenda: string, tracks?: TrackDescription[], trackId?: number): TrackInfoExt | undefined {
+ let info: TrackInfoExt | undefined;
if (tracks && trackId !== undefined) {
const originMap = getGovernanceTracks(api, specName, palletReferenda);
- const trackInfo = tracks.find(({ id }) => id.eqn(trackId));
+ const track = tracks.find(({ id }) => id.eqn(trackId));
- if (trackInfo && originMap) {
- const trackName = trackInfo.info.name.toString();
-
- info = originMap.find(({ id, name }) =>
+ if (track && originMap) {
+ const trackName = track.info.name.toString();
+ const base = originMap.find(({ id, name }) =>
id === trackId &&
name === trackName
);
+
+ if (base) {
+ info = objectSpread({ track }, base);
+ }
}
}
@@ -202,11 +205,11 @@ export function calcDecidingEnd (totalEligible: BN, tally: PalletRankedCollectiv
}
export function calcCurves ({ decisionPeriod, minApproval, minSupport }: PalletReferendaTrackInfo): CurveGraph {
- const approval = new Array(100);
- const support = new Array(100);
- const x = new Array(100);
- const step = decisionPeriod.divn(CALC_CURVE_LENGTH);
- const last = CALC_CURVE_LENGTH - 1;
+ const approval = new Array(CURVE_LENGTH);
+ const support = new Array(CURVE_LENGTH);
+ const x = new Array(CURVE_LENGTH);
+ const step = decisionPeriod.divn(CURVE_LENGTH);
+ const last = CURVE_LENGTH - 1;
let current = new BN(0);
for (let i = 0; i < last; i++) {
diff --git a/packages/react-components/src/Call.tsx b/packages/react-components/src/Call.tsx
index da40be19c4..0163542676 100644
--- a/packages/react-components/src/Call.tsx
+++ b/packages/react-components/src/Call.tsx
@@ -1,6 +1,7 @@
// Copyright 2017-2022 @polkadot/react-components authors & contributors
// SPDX-License-Identifier: Apache-2.0
+import type { ComponentMap } from '@polkadot/react-params/types';
import type { ExtrinsicSignature } from '@polkadot/types/interfaces';
import type { Codec, IExtrinsic, IMethod, TypeDef } from '@polkadot/types/types';
import type { BN } from '@polkadot/util';
@@ -9,6 +10,7 @@ import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import Params from '@polkadot/react-params';
+import BalanceParam from '@polkadot/react-params/Param/Balance';
import { FormatBalance } from '@polkadot/react-query';
import { Enum, getTypeDef } from '@polkadot/types';
@@ -16,6 +18,7 @@ import Static from './Static';
import { useTranslation } from './translate';
export interface Props {
+ callName?: string;
children?: React.ReactNode;
className?: string;
labelHash?: React.ReactNode;
@@ -42,12 +45,27 @@ interface Value {
interface Extracted {
hash: string | null;
+ overrides?: ComponentMap;
params: Param[];
signature: string | null;
signatureType: string | null;
values: Value[];
}
+const BALANCE_CALLS = [
+ 'balances.forceTransfer', 'balances.forceUnreserve', 'balances.setBalance', 'balances.transfer', 'balances.transferKeepAlive',
+ 'crowdloan.contribute', 'crowdloan.create', 'crowdloan.edit',
+ 'democracy.delegate', 'democracy.propose',
+ 'nominationPools.bondExtra', 'nominationPools.join', 'nominationPools.unbond',
+ 'staking.bond', 'staking.bondExtra', 'staking.rebond', 'staking.unbond',
+ 'treasury.proposeSpend', 'treasury.spend',
+ 'vesting.forceVestedTransfer', 'vesting.vestedTransfer'
+];
+
+const BALANCE_OVERRIDE: ComponentMap = {
+ 'Compact': BalanceParam
+};
+
function isExtrinsic (value: IExtrinsic | IMethod): value is IExtrinsic {
return !!(value as IExtrinsic).signature;
}
@@ -58,7 +76,10 @@ function getRawSignature (value: IExtrinsic): ExtrinsicSignature | undefined {
return (value as any)._raw?.signature?.multiSignature as ExtrinsicSignature;
}
-function extractState (value: IExtrinsic | IMethod, withHash?: boolean, withSignature?: boolean): Extracted {
+function extractState (value: IExtrinsic | IMethod, withHash?: boolean, withSignature?: boolean, callName?: string): Extracted {
+ const overrides = callName && BALANCE_CALLS.includes(callName)
+ ? BALANCE_OVERRIDE
+ : undefined;
const params = value.meta.args.map(({ name, type }): Param => ({
name: name.toString(),
type: getTypeDef(type.toString())
@@ -82,22 +103,23 @@ function extractState (value: IExtrinsic | IMethod, withHash?: boolean, withSign
: null;
}
- return { hash, params, signature, signatureType, values };
+ return { hash, overrides, params, signature, signatureType, values };
}
-function Call ({ children, className = '', labelHash, labelSignature, mortality, noIndent, onError, tip, value, withBorder, withHash, withSignature }: Props): React.ReactElement {
+function Call ({ callName, children, className = '', labelHash, labelSignature, mortality, noIndent, onError, tip, value, withBorder, withHash, withSignature }: Props): React.ReactElement {
const { t } = useTranslation();
- const [{ hash, params, signature, signatureType, values }, setExtracted] = useState({ hash: null, params: [], signature: null, signatureType: null, values: [] });
+ const [{ hash, overrides, params, signature, signatureType, values }, setExtracted] = useState({ hash: null, params: [], signature: null, signatureType: null, values: [] });
useEffect((): void => {
- setExtracted(extractState(value, withHash, withSignature));
- }, [value, withHash, withSignature]);
+ setExtracted(extractState(value, withHash, withSignature, callName));
+ }, [callName, value, withHash, withSignature]);
return (
}
+ summaryHead={{callName}
}
summaryMeta={meta}
>
{
+const BALANCE_EVENTS = [
+ 'balances.Deposit', 'balances.Endowed', 'balances.Transfer', 'balances.Withdraw',
+ 'staking.Bonded', 'staking.Rewarded', 'staking.Unbonded', 'staking.Withdrawn',
+ 'transactionPayment.TransactionFeePaid',
+ 'treasury.Deposit'
+];
+
+const BALANCE_OVERRIDE: ComponentMap = {
+ 'Compact': BalanceParam,
+ u128: BalanceParam
+};
+
+function EventDisplay ({ children, className = '', eventName, value }: Props): React.ReactElement {
const { t } = useTranslation();
const names = value.data.names;
const params = value.typeDef.map((type, i) => ({
@@ -38,6 +53,13 @@ function EventDisplay ({ children, className = '', value }: Props): React.ReactE
}));
const values = value.data.map((value) => ({ isValid: true, value }));
+ const overrides = useMemo(
+ () => eventName && BALANCE_EVENTS.includes(eventName)
+ ? BALANCE_OVERRIDE
+ : undefined,
+ [eventName]
+ );
+
const abiEvent = useMemo(
(): AbiEvent | null => {
// for contracts, we decode the actual event
@@ -72,6 +94,7 @@ function EventDisplay ({ children, className = '', value }: Props): React.ReactE
{children}
diff --git a/packages/react-components/src/InputBalance.tsx b/packages/react-components/src/InputBalance.tsx
index 5a801a80f4..888b9edbf5 100644
--- a/packages/react-components/src/InputBalance.tsx
+++ b/packages/react-components/src/InputBalance.tsx
@@ -8,7 +8,7 @@ import React, { useMemo } from 'react';
import styled from 'styled-components';
import { BitLengthOption } from '@polkadot/react-components/constants';
-import { BN, formatBalance, isUndefined } from '@polkadot/util';
+import { BN, BN_TEN, formatBalance, isString, isUndefined } from '@polkadot/util';
import InputNumber from './InputNumber';
@@ -40,26 +40,34 @@ interface Props {
const DEFAULT_BITLENGTH = BitLengthOption.CHAIN_SPEC as BitLength;
-function reformat (value?: string | BN, isDisabled?: boolean, siDecimals?: number): [string?, SiDef?] {
+function reformat (value?: string | BN, isDisabled?: boolean, siDecimals?: number): { defaultValue?: string; siDefault?: SiDef } {
if (!value) {
- return [];
+ return {};
}
const decimals = isUndefined(siDecimals)
? formatBalance.getDefaults().decimals
: siDecimals;
- const si = isDisabled
+ const maxDisabled = BN_TEN.pow(new BN(decimals - 1)).toString(10);
+ const siDefault = isDisabled && isString(value) && (value.length < maxDisabled.length) && value !== '0'
? formatBalance.calcSi(value.toString(), decimals)
: formatBalance.findSi('-');
+ const defaultValue = formatBalance(value, {
+ decimals,
+ forceUnit: siDefault.value,
+ withSi: false
+ });
- return [
- formatBalance(value, { decimals, forceUnit: si.value, withSi: false }).replace(/,/g, isDisabled ? ',' : ''),
- si
- ];
+ return {
+ defaultValue: isDisabled
+ ? defaultValue
+ : defaultValue.replace(/,/g, isDisabled ? ',' : ''),
+ siDefault
+ };
}
function InputBalance ({ autoFocus, children, className = '', defaultValue: inDefault, help, isDisabled, isError, isFull, isWarning, isZeroable, label, labelExtra, maxValue, onChange, onEnter, onEscape, placeholder, siDecimals, siSymbol, value, withEllipsis, withLabel, withMax }: Props): React.ReactElement {
- const [defaultValue, siDefault] = useMemo(
+ const { defaultValue, siDefault } = useMemo(
() => reformat(inDefault, isDisabled, siDecimals),
[inDefault, isDisabled, siDecimals]
);
diff --git a/packages/react-components/src/Table/Head.tsx b/packages/react-components/src/Table/Head.tsx
index a8293f0387..ffa8cdb803 100644
--- a/packages/react-components/src/Table/Head.tsx
+++ b/packages/react-components/src/Table/Head.tsx
@@ -9,13 +9,14 @@ import Icon from '../Icon';
type HeaderDef = [React.ReactNode?, string?, number?, (() => void)?];
interface Props {
+ children?: React.ReactNode;
className?: string;
filter?: React.ReactNode;
header?: (null | undefined | HeaderDef)[];
isEmpty: boolean;
}
-function Head ({ className = '', filter, header, isEmpty }: Props): React.ReactElement | null {
+function Head ({ children, className = '', filter, header, isEmpty }: Props): React.ReactElement | null {
if (!header?.length) {
return null;
}
@@ -52,6 +53,7 @@ function Head ({ className = '', filter, header, isEmpty }: Props): React.ReactE
)}
+ {children}
);
}
@@ -100,7 +102,8 @@ export default React.memo(styled(Head)`
padding: 0;
}
- &.expand {
+ &.expand,
+ &.number {
text-align: right;
}
diff --git a/packages/react-components/src/Table/index.tsx b/packages/react-components/src/Table/index.tsx
index a3b083ad53..9372bef3c5 100644
--- a/packages/react-components/src/Table/index.tsx
+++ b/packages/react-components/src/Table/index.tsx
@@ -16,6 +16,7 @@ interface TableProps {
filter?: React.ReactNode;
footer?: React.ReactNode;
header?: [React.ReactNode?, string?, number?, (() => void)?][];
+ headerChildren?: React.ReactNode;
isFixed?: boolean;
isInline?: boolean;
legend?: React.ReactNode;
@@ -34,7 +35,7 @@ function extractBodyChildren (children: React.ReactNode): [boolean, React.ReactN
return [isEmpty, isEmpty ? null : kids];
}
-function Table ({ children, className = '', empty, emptySpinner, filter, footer, header, isFixed, isInline, legend, noBodyTag, withCollapsibleRows = false }: TableProps): React.ReactElement {
+function Table ({ children, className = '', empty, emptySpinner, filter, footer, header, headerChildren, isFixed, isInline, legend, noBodyTag, withCollapsibleRows = false }: TableProps): React.ReactElement {
const [isEmpty, bodyChildren] = extractBodyChildren(children);
return (
@@ -45,7 +46,9 @@ function Table ({ children, className = '', empty, emptySpinner, filter, footer,
filter={filter}
header={header}
isEmpty={isEmpty}
- />
+ >
+ {headerChildren}
+
{
const call = value as Extrinsic;
const { method, section } = call.registry.findMetaCall(call.callIndex);
+ const callName = `${section}.${method}`;
return (
@@ -32,9 +33,10 @@ function CallDisplay (props: Props): React.ReactElement {
label={label}
withLabel={withLabel}
>
- {section}.{method}
+ {callName}
('call hash / {{section}}.{{method}}', { replace: { method, section } })}
noIndent
value={call}
diff --git a/packages/react-params/src/Param/findComponent.ts b/packages/react-params/src/Param/findComponent.ts
index c64c98b825..b4af99ef2c 100644
--- a/packages/react-params/src/Param/findComponent.ts
+++ b/packages/react-params/src/Param/findComponent.ts
@@ -148,7 +148,7 @@ export default function findComponent (registry: Registry, def: TypeDef, overrid
: null;
const type = fromDef(def);
- let Component = findOne(def.lookupName) || findOne(type);
+ let Component = findOne(def.lookupName) || findOne(def.type) || findOne(type);
if (!Component) {
try {
diff --git a/packages/react-params/src/index.tsx b/packages/react-params/src/index.tsx
index a2a8f31b27..56dc86f2da 100644
--- a/packages/react-params/src/index.tsx
+++ b/packages/react-params/src/index.tsx
@@ -88,6 +88,8 @@ class Params extends React.PureComponent {
return null;
}
+ overrides && console.log(overrides);
+
return (