Basic democracy (Referendum) overview (#216)
* Basic democacry (Referendum) overview * Summary in-place * Fix package name * Proposals & Referendums are showing up * Some basic Extrinsic formatting. (WIP) * Basic referendum/proposal summary in place * Referendum outcome chart * Voting in place. It works. * Remove extra console.log/error * Only show balances as label
This commit is contained in:
parent
7768f51639
commit
4484883afc
@ -2,7 +2,7 @@ const config = require('@polkadot/dev-react/config/jest');
|
||||
|
||||
module.exports = Object.assign({}, config, {
|
||||
moduleNameMapper: {
|
||||
'@polkadot/app-(accounts|addresses|example|explorer|extrinsics|rpc|staking|storage|toolbox|vanitygen)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
|
||||
'@polkadot/app-(accounts|addresses|democracy|example|explorer|extrinsics|rpc|staking|storage|toolbox|vanitygen)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
|
||||
'@polkadot/ui-(app|identicon|keyring|react-rx|react|signer)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object',
|
||||
'\\.(css|less)$': 'empty/object'
|
||||
|
||||
15
packages/app-democracy/LICENSE
Normal file
15
packages/app-democracy/LICENSE
Normal file
@ -0,0 +1,15 @@
|
||||
ISC License (ISC)
|
||||
|
||||
Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
1
packages/app-democracy/README.md
Normal file
1
packages/app-democracy/README.md
Normal file
@ -0,0 +1 @@
|
||||
# @polkadot/app-democracy
|
||||
19
packages/app-democracy/package.json
Normal file
19
packages/app-democracy/package.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "@polkadot/app-democracy",
|
||||
"version": "0.19.30",
|
||||
"description": "A referendum & proposal app",
|
||||
"main": "index.js",
|
||||
"scripts": {},
|
||||
"author": "Jaco Greeff <jacogr@gmail.com>",
|
||||
"maintainers": [
|
||||
"Jaco Greeff <jacogr@gmail.com>"
|
||||
],
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/storage": "^0.28.11",
|
||||
"@polkadot/ui-react": "^0.19.30",
|
||||
"@polkadot/ui-react-rx": "^0.19.30",
|
||||
"@polkadot/util-keyring": "^0.28.1"
|
||||
}
|
||||
}
|
||||
45
packages/app-democracy/src/Extrinsic.tsx
Normal file
45
packages/app-democracy/src/Extrinsic.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2017-2018 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { ExtrinsicDecoded } from '@polkadot/params/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RawParam } from '@polkadot/ui-app/Params/types';
|
||||
|
||||
import React from 'react';
|
||||
import Params from '@polkadot/ui-app/Params';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
export type Props = I18nProps & {
|
||||
children?: React.ReactNode,
|
||||
value: ExtrinsicDecoded
|
||||
};
|
||||
|
||||
class Extrinsic extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { children, className, style, value: { extrinsic, params } } = this.props;
|
||||
const values: Array<RawParam> = extrinsic.params.map(({ type }, index) => ({
|
||||
isValid: true,
|
||||
value: params[index],
|
||||
type
|
||||
}));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('democracy--Extrinsic', className)}
|
||||
style={style}
|
||||
>
|
||||
{children}
|
||||
<Params
|
||||
isDisabled
|
||||
item={extrinsic}
|
||||
values={values}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Extrinsic);
|
||||
64
packages/app-democracy/src/Item.tsx
Normal file
64
packages/app-democracy/src/Item.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { ExtrinsicDecoded } from '@polkadot/params/types';
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import Card from '@polkadot/ui-app/Card';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
// TODO This would be nice as a shared component, move to ui-app as soon as
|
||||
// we have actual "more-than-one-use" apps
|
||||
import Extrinsic from './Extrinsic';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
children?: React.ReactNode,
|
||||
proposal: ExtrinsicDecoded,
|
||||
proposalExtra?: React.ReactNode,
|
||||
idNumber: BN
|
||||
};
|
||||
|
||||
class Item extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { children, className, idNumber, proposal, proposalExtra, style } = this.props;
|
||||
|
||||
return (
|
||||
<Card
|
||||
className={classes('democracy--Item', className)}
|
||||
style={style}
|
||||
>
|
||||
<div className='democracy--Item-header'>
|
||||
<div className='democracy--Item-header-info'>
|
||||
<div className='democracy--Item-header-name'>
|
||||
{proposal.extrinsic.section}.{proposal.extrinsic.name}
|
||||
</div>
|
||||
<div className='democracy--Item-header-description'>
|
||||
{proposal.extrinsic.description}
|
||||
</div>
|
||||
</div>
|
||||
<div className='democracy--Item-header-id'>
|
||||
#{numberFormat(idNumber)}
|
||||
</div>
|
||||
</div>
|
||||
<div className='democracy--Item-body'>
|
||||
<Extrinsic
|
||||
className='democracy--Item-extrinsic'
|
||||
value={proposal}
|
||||
>
|
||||
{proposalExtra}
|
||||
</Extrinsic>
|
||||
<div className='democracy--Item-children'>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Item);
|
||||
86
packages/app-democracy/src/Proposal.tsx
Normal file
86
packages/app-democracy/src/Proposal.tsx
Normal file
@ -0,0 +1,86 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RxProposal, RxProposalDeposits } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import AddressMini from '@polkadot/ui-app/AddressMini';
|
||||
import Labelled from '@polkadot/ui-app/Labelled';
|
||||
import Static from '@polkadot/ui-app/Static';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
import Item from './Item';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
democracyProposalDeposits?: RxProposalDeposits,
|
||||
idNumber: BN,
|
||||
value: RxProposal
|
||||
};
|
||||
|
||||
class Proposal extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, idNumber, style, value } = this.props;
|
||||
|
||||
return (
|
||||
<Item
|
||||
className={classes('democracy--Proposal', className)}
|
||||
idNumber={idNumber}
|
||||
proposal={value.proposal}
|
||||
proposalExtra={this.renderExtra()}
|
||||
style={style}
|
||||
>
|
||||
{this.renderVoting()}
|
||||
</Item>
|
||||
);
|
||||
}
|
||||
|
||||
private renderExtra () {
|
||||
const { democracyProposalDeposits, t } = this.props;
|
||||
|
||||
if (!democracyProposalDeposits) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { balance, addresses } = democracyProposalDeposits;
|
||||
|
||||
return (
|
||||
<div className='democracy--Proposal-info'>
|
||||
<Labelled label={t('proposal.depositsAddresses', {
|
||||
defaultValue: 'depositors'
|
||||
})}>
|
||||
<div>
|
||||
{addresses.map((address) => (
|
||||
<AddressMini
|
||||
isPadded={false}
|
||||
key={address}
|
||||
value={address}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Labelled>
|
||||
<Static label={t('proposal.depositsBalanceLabel', {
|
||||
defaultValue: 'balance'
|
||||
})}>
|
||||
{numberFormat(balance)}
|
||||
</Static>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderVoting () {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Proposal,
|
||||
translate,
|
||||
withObservable('democracyProposalDeposits', { paramProp: 'idNumber' })
|
||||
);
|
||||
64
packages/app-democracy/src/Proposals.tsx
Normal file
64
packages/app-democracy/src/Proposals.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RxProposal } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
|
||||
import Proposal from './Proposal';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
democracyProposals?: Array<RxProposal>
|
||||
};
|
||||
|
||||
class Proposals extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, style, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('democracy--Proposals', className)}
|
||||
style={style}
|
||||
>
|
||||
<h1>{t('proposals.header', {
|
||||
defaultValue: 'proposals'
|
||||
})}</h1>
|
||||
{this.renderProposals()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderProposals () {
|
||||
const { democracyProposals, t } = this.props;
|
||||
|
||||
if (!democracyProposals || !democracyProposals.length) {
|
||||
return (
|
||||
<div className='ui disabled'>
|
||||
{t('proposals.none', {
|
||||
defaultValue: 'no available proposals'
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return democracyProposals.map((proposal) => (
|
||||
<Proposal
|
||||
idNumber={proposal.id}
|
||||
key={proposal.id.toString()}
|
||||
value={proposal}
|
||||
/>
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Proposals,
|
||||
translate,
|
||||
withObservable('democracyProposals')
|
||||
);
|
||||
171
packages/app-democracy/src/Referendum.tsx
Normal file
171
packages/app-democracy/src/Referendum.tsx
Normal file
@ -0,0 +1,171 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RawParam } from '@polkadot/ui-app/Params/types';
|
||||
import { RxReferendum, RxReferendumVote } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import Static from '@polkadot/ui-app/Static';
|
||||
import Doughnut from '@polkadot/ui-app/Chart/Doughnut';
|
||||
import VoteThreshold from '@polkadot/ui-app/Params/Param/VoteThreshold';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
|
||||
import Item from './Item';
|
||||
import Voting from './Voting';
|
||||
import translate from './translate';
|
||||
|
||||
const COLORS_YAY = ['#4d4', '#4e4'];
|
||||
const COLORS_NAY = ['#d44', '#e44'];
|
||||
|
||||
type Props = I18nProps & {
|
||||
bestNumber?: BN,
|
||||
democracyReferendumVoters?: Array<RxReferendumVote>,
|
||||
idNumber: BN,
|
||||
value: RxReferendum
|
||||
};
|
||||
|
||||
type State = {
|
||||
voteCount: number,
|
||||
voteCountYay: number,
|
||||
voteCountNay: number,
|
||||
votedTotal: BN,
|
||||
votedNay: BN,
|
||||
votedYay: BN
|
||||
};
|
||||
|
||||
class Referendum extends React.PureComponent<Props, State> {
|
||||
state: State;
|
||||
|
||||
constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
voteCount: 0,
|
||||
voteCountYay: 0,
|
||||
voteCountNay: 0,
|
||||
votedTotal: new BN(0),
|
||||
votedYay: new BN(0),
|
||||
votedNay: new BN(0)
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps ({ democracyReferendumVoters }: Props, prevState: State): State | null {
|
||||
if (!democracyReferendumVoters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const newState: State = democracyReferendumVoters.reduce((state, { balance, vote }) => {
|
||||
if (vote) {
|
||||
state.voteCountYay++;
|
||||
state.votedYay = state.votedYay.add(balance);
|
||||
} else {
|
||||
state.voteCountNay++;
|
||||
state.votedNay = state.votedNay.add(balance);
|
||||
}
|
||||
|
||||
state.voteCount++;
|
||||
state.votedTotal = state.votedTotal.add(balance);
|
||||
|
||||
return state;
|
||||
}, {
|
||||
voteCount: 0,
|
||||
voteCountYay: 0,
|
||||
voteCountNay: 0,
|
||||
votedTotal: new BN(0),
|
||||
votedYay: new BN(0),
|
||||
votedNay: new BN(0)
|
||||
});
|
||||
|
||||
if (newState.votedYay.eq(prevState.votedNay) && newState.votedNay.eq(prevState.votedNay)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, idNumber, style, value } = this.props;
|
||||
|
||||
return (
|
||||
<Item
|
||||
className={classes('democracy--Referendum', className)}
|
||||
idNumber={idNumber}
|
||||
proposal={value.proposal}
|
||||
proposalExtra={this.renderExtra()}
|
||||
style={style}
|
||||
>
|
||||
<Voting referendumId={idNumber} />
|
||||
{this.renderResults()}
|
||||
</Item>
|
||||
);
|
||||
}
|
||||
|
||||
private renderExtra () {
|
||||
const { bestNumber, t, value: { blockNumber, voteThreshold } } = this.props;
|
||||
|
||||
if (!bestNumber) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='democracy--Referendum-info'>
|
||||
<Static label={t('referendum.endLabel', {
|
||||
defaultValue: 'remaining time'
|
||||
})}>
|
||||
{t('referendum.endInfo', {
|
||||
defaultValue: '{{remaining}} blocks remaining, ending at block #{{blockNumber}}',
|
||||
replace: {
|
||||
blockNumber: numberFormat(blockNumber),
|
||||
remaining: numberFormat(blockNumber.sub(bestNumber))
|
||||
}
|
||||
})}
|
||||
</Static>
|
||||
<VoteThreshold
|
||||
isDisabled
|
||||
defaultValue={{ value: voteThreshold } as RawParam}
|
||||
label={t('referendum.thresholdLabel', {
|
||||
defaultValue: 'vote threshold'
|
||||
})}
|
||||
name='voteThreshold'
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderResults () {
|
||||
const { voteCount, voteCountYay, voteCountNay, votedTotal, votedYay, votedNay } = this.state;
|
||||
|
||||
if (voteCount === 0 || votedTotal.eqn(0)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='democracy--Referendum-results chart'>
|
||||
<Doughnut values={[
|
||||
{
|
||||
colors: COLORS_YAY,
|
||||
label: `${numberFormat(votedYay)} (${numberFormat(voteCountYay)})`,
|
||||
value: votedYay.muln(10000).div(votedTotal).toNumber() / 100
|
||||
},
|
||||
{
|
||||
colors: COLORS_NAY,
|
||||
label: `${numberFormat(votedNay)} (${numberFormat(voteCountNay)})`,
|
||||
value: votedNay.muln(10000).div(votedTotal).toNumber() / 100
|
||||
}
|
||||
]} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
translate(Referendum),
|
||||
withObservable('bestNumber'),
|
||||
withObservable('democracyReferendumVoters', { paramProp: 'idNumber' })
|
||||
);
|
||||
64
packages/app-democracy/src/Referendums.tsx
Normal file
64
packages/app-democracy/src/Referendums.tsx
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RxReferendum } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
|
||||
import Referendum from './Referendum';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
democracyReferendums?: Array<RxReferendum>
|
||||
};
|
||||
|
||||
class Referendums extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, style, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('democracy--Referendums', className)}
|
||||
style={style}
|
||||
>
|
||||
<h1>{t('referendums.header', {
|
||||
defaultValue: 'referendums'
|
||||
})}</h1>
|
||||
{this.renderReferendums()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderReferendums () {
|
||||
const { democracyReferendums, t } = this.props;
|
||||
|
||||
if (!democracyReferendums || !democracyReferendums.length) {
|
||||
return (
|
||||
<div className='ui disabled'>
|
||||
{t('proposals.none', {
|
||||
defaultValue: 'no available referendums'
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return democracyReferendums.map((referendum) => (
|
||||
<Referendum
|
||||
idNumber={referendum.id}
|
||||
key={referendum.id.toString()}
|
||||
value={referendum}
|
||||
/>
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Referendums,
|
||||
translate,
|
||||
withObservable('democracyReferendums')
|
||||
);
|
||||
79
packages/app-democracy/src/Summary.tsx
Normal file
79
packages/app-democracy/src/Summary.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import CardSummary from '@polkadot/ui-app/CardSummary';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
democracyLaunchPeriod?: BN,
|
||||
democracyNextTally?: BN,
|
||||
democracyProposalCount?: BN,
|
||||
democracyReferendumCount?: BN,
|
||||
democracyVotingPeriod?: BN
|
||||
};
|
||||
|
||||
class Summary extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, democracyLaunchPeriod, democracyNextTally = new BN(0), democracyProposalCount, democracyReferendumCount = new BN(0), democracyVotingPeriod, style, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('democracy--Summary', className)}
|
||||
style={style}
|
||||
>
|
||||
<div className='democracy--Summary-column'>
|
||||
<CardSummary label={t('summary.proposalCount', {
|
||||
defaultValue: 'proposals'
|
||||
})}>
|
||||
{numberFormat(democracyProposalCount)}
|
||||
</CardSummary>
|
||||
<CardSummary label={t('summary.referendumCount', {
|
||||
defaultValue: 'referendums'
|
||||
})}>
|
||||
{numberFormat(democracyReferendumCount)}
|
||||
</CardSummary>
|
||||
<CardSummary label={t('summary.active', {
|
||||
defaultValue: 'active num'
|
||||
})}>
|
||||
{democracyNextTally && democracyReferendumCount
|
||||
? numberFormat(democracyReferendumCount.sub(democracyNextTally))
|
||||
: 0
|
||||
}
|
||||
</CardSummary>
|
||||
</div>
|
||||
<div className='democracy--Summary-column'>
|
||||
<CardSummary label={t('summary.votingPeriod', {
|
||||
defaultValue: 'voting period'
|
||||
})}>
|
||||
{numberFormat(democracyVotingPeriod)}
|
||||
</CardSummary>
|
||||
<CardSummary label={t('summary.launchPeriod', {
|
||||
defaultValue: 'launch period'
|
||||
})}>
|
||||
{numberFormat(democracyLaunchPeriod)}
|
||||
</CardSummary>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Summary,
|
||||
translate,
|
||||
withObservable('democracyLaunchPeriod'),
|
||||
withObservable('democracyReferendumCount'),
|
||||
withObservable('democracyNextTally'),
|
||||
withObservable('democracyProposalCount'),
|
||||
withObservable('democracyVotingPeriod')
|
||||
);
|
||||
72
packages/app-democracy/src/Voting.tsx
Normal file
72
packages/app-democracy/src/Voting.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { QueueProps } from '@polkadot/ui-signer/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import InputAddress from '@polkadot/ui-app/InputAddress';
|
||||
import { QueueConsumer } from '@polkadot/ui-signer/Context';
|
||||
|
||||
import VotingButtons from './VotingButtons';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
referendumId: BN
|
||||
};
|
||||
|
||||
type State = {
|
||||
publicKey?: Uint8Array
|
||||
};
|
||||
|
||||
class Voting extends React.PureComponent<Props, State> {
|
||||
state: State = {};
|
||||
|
||||
render () {
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<div className='democracy--Referendum-vote'>
|
||||
<InputAddress
|
||||
label={t('voting.account', {
|
||||
defaultValue: 'vote using my account'
|
||||
})}
|
||||
onChange={this.onChangeAccount}
|
||||
placeholder='0x...'
|
||||
type='account'
|
||||
withLabel
|
||||
/>
|
||||
{this.renderButtons()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderButtons () {
|
||||
const { referendumId } = this.props;
|
||||
const { publicKey } = this.state;
|
||||
|
||||
if (!publicKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QueueConsumer>
|
||||
{({ queueExtrinsic }: QueueProps) => (
|
||||
<VotingButtons
|
||||
publicKey={publicKey}
|
||||
queueExtrinsic={queueExtrinsic}
|
||||
referendumId={referendumId}
|
||||
/>
|
||||
)}
|
||||
</QueueConsumer>
|
||||
);
|
||||
}
|
||||
|
||||
private onChangeAccount = (publicKey?: Uint8Array) => {
|
||||
this.setState({ publicKey });
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Voting);
|
||||
78
packages/app-democracy/src/VotingButtons.tsx
Normal file
78
packages/app-democracy/src/VotingButtons.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-signer/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import extrinsics from '@polkadot/extrinsics';
|
||||
import Button from '@polkadot/ui-app/Button';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
publicKey?: Uint8Array,
|
||||
queueExtrinsic: QueueTx$ExtrinsicAdd,
|
||||
referendumId: BN,
|
||||
systemAccountIndexOf?: BN
|
||||
};
|
||||
|
||||
class VotingButton extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { publicKey, t } = this.props;
|
||||
|
||||
return (
|
||||
<Button.Group>
|
||||
<Button
|
||||
isDisabled={!publicKey}
|
||||
isPositive
|
||||
text={t('votebtn.yay', {
|
||||
defaultValue: 'yay'
|
||||
})}
|
||||
onClick={this.onClickYay}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
isDisabled={!publicKey}
|
||||
isNegative
|
||||
text={t('votebtn.nay', {
|
||||
defaultValue: 'nay'
|
||||
})}
|
||||
onClick={this.onClickNay}
|
||||
/>
|
||||
</Button.Group>
|
||||
);
|
||||
}
|
||||
|
||||
private doVote (vote: boolean) {
|
||||
const { publicKey, queueExtrinsic, referendumId, systemAccountIndexOf = new BN(0) } = this.props;
|
||||
|
||||
if (!publicKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
queueExtrinsic({
|
||||
extrinsic: extrinsics.democracy.public.vote,
|
||||
nonce: systemAccountIndexOf,
|
||||
publicKey,
|
||||
values: [referendumId, vote]
|
||||
});
|
||||
}
|
||||
|
||||
private onClickYay = () => {
|
||||
this.doVote(true);
|
||||
}
|
||||
|
||||
private onClickNay = () => {
|
||||
this.doVote(false);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
translate(VotingButton),
|
||||
withObservable('systemAccountIndexOf', { paramProp: 'publicKey' })
|
||||
);
|
||||
100
packages/app-democracy/src/index.css
Normal file
100
packages/app-democracy/src/index.css
Normal file
@ -0,0 +1,100 @@
|
||||
/* Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
/* This software may be modified and distributed under the terms
|
||||
/* of the ISC license. See the LICENSE file for details. */
|
||||
|
||||
.democracy--App {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* FIXME These are just copied as-is from staking/Summary - once happy and proven to be
|
||||
shareable, it needs to be moved into ui-app for consistency.
|
||||
*/
|
||||
.democracy--Summary {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.democracy--Summary-column {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.democracy--Summary-card {
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.democracy--Proposals,
|
||||
.democracy--Referendums {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.democracy--Item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.democracy--Item-header-info,
|
||||
.democracy--Item-header-id {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.democracy--Item-header-id {
|
||||
font-size: 2rem;
|
||||
line-height: 2rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.democracy--Item-header-description {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.democracy--Item-header-name {
|
||||
font-size: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
|
||||
.democracy--Item-body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
}
|
||||
|
||||
.democracy--Item-extrinsic,
|
||||
.democracy--Item-children {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
padding: 0 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.democracy--Item-extrinsic .ui--Params-Content {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.democracy--Extrinsic .ui--Labelled {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.democracy--Extrinsic .ui--Labelled .ui.label {
|
||||
display: block;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.democracy--Proposal-info,
|
||||
.democracy--Referendum-info {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.democracy--Referendum-results {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.democracy--Referendum-results.chart {
|
||||
text-align: center;
|
||||
}
|
||||
28
packages/app-democracy/src/index.tsx
Normal file
28
packages/app-democracy/src/index.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2017-2018 @polkadot/app-democracy authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { BareProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import './index.css';
|
||||
|
||||
import React from 'react';
|
||||
import Page from '@polkadot/ui-app/Page';
|
||||
|
||||
import Proposals from './Proposals';
|
||||
import Referendums from './Referendums';
|
||||
import Summary from './Summary';
|
||||
|
||||
type Props = BareProps & {};
|
||||
|
||||
export default class App extends React.PureComponent<Props> {
|
||||
render () {
|
||||
return (
|
||||
<Page className='democracy--App'>
|
||||
<Summary />
|
||||
<Referendums />
|
||||
<Proposals />
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
7
packages/app-democracy/src/translate.ts
Normal file
7
packages/app-democracy/src/translate.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { translate } from 'react-i18next';
|
||||
|
||||
export default translate(['democracy', 'ui']);
|
||||
@ -11,7 +11,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/storage": "^0.28.9",
|
||||
"@polkadot/storage": "^0.28.11",
|
||||
"@polkadot/ui-react": "^0.19.30",
|
||||
"@polkadot/ui-react-rx": "^0.19.30",
|
||||
"@polkadot/util-keyring": "^0.28.1"
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/primitives": "^0.28.9",
|
||||
"@polkadot/primitives": "^0.28.11",
|
||||
"@polkadot/ui-app": "^0.19.30",
|
||||
"@polkadot/util-crypto": "^0.28.1"
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/extrinsics": "^0.28.9",
|
||||
"@polkadot/extrinsics": "^0.28.11",
|
||||
"@polkadot/ui-app": "^0.19.30",
|
||||
"@polkadot/ui-signer": "^0.19.30",
|
||||
"react-dropzone": "^4.2.9"
|
||||
|
||||
@ -20,7 +20,7 @@ type Props = I18nProps & {
|
||||
isError?: boolean,
|
||||
isInput?: boolean,
|
||||
label: string,
|
||||
onChange: (publicKey: Uint8Array) => void,
|
||||
onChange?: (publicKey: Uint8Array) => void,
|
||||
type?: KeyringOption$Type,
|
||||
withLabel?: boolean
|
||||
};
|
||||
@ -94,7 +94,7 @@ class Account extends React.PureComponent<Props, State> {
|
||||
const { onChange } = this.props;
|
||||
|
||||
this.setState({ publicKey }, () =>
|
||||
onChange(publicKey)
|
||||
onChange && onChange(publicKey)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ export default class Account extends React.PureComponent<Props> {
|
||||
onChange = (publicKey?: Uint8Array): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: !!publicKey && publicKey.length === 32,
|
||||
value: publicKey
|
||||
});
|
||||
|
||||
@ -19,7 +19,7 @@ type Props = I18nProps & {
|
||||
isError?: boolean,
|
||||
isPrivate: boolean,
|
||||
label: string,
|
||||
onChange: RawParam$OnChange,
|
||||
onChange?: RawParam$OnChange,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
@ -56,7 +56,7 @@ class Extrinsic extends React.PureComponent<Props> {
|
||||
onChange = ({ isValid, values }: EncodedMessage): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid,
|
||||
value: (values[0] as Uint8Array)
|
||||
});
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/app-extrinsics": "^0.19.30",
|
||||
"@polkadot/storage": "^0.28.9",
|
||||
"@polkadot/storage": "^0.28.11",
|
||||
"@polkadot/ui-app": "^0.19.30",
|
||||
"@polkadot/ui-keyring": "^0.19.30",
|
||||
"@polkadot/ui-react": "^0.19.30",
|
||||
|
||||
@ -7,7 +7,7 @@ import { Extrinsics } from '@polkadot/extrinsics/types';
|
||||
import { SectionItem } from '@polkadot/params/types';
|
||||
import { RawParam$Value } from '@polkadot/ui-app/Params/types';
|
||||
import { QueueTx$ExtrinsicAdd } from '@polkadot/ui-signer/types';
|
||||
import { ExtendedBalanceMap } from '@polkadot/ui-react-rx/types';
|
||||
import { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
@ -29,7 +29,7 @@ import translate from './translate';
|
||||
type Props = I18nProps & {
|
||||
systemAccountIndexOf?: BN,
|
||||
address: string,
|
||||
balances: ExtendedBalanceMap,
|
||||
balances: RxBalanceMap,
|
||||
name: string,
|
||||
stakingNominating?: string,
|
||||
stakingNominatorsFor?: Array<string>,
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { QueueProps } from '@polkadot/ui-signer/types';
|
||||
import { ExtendedBalanceMap } from '@polkadot/ui-react-rx/types';
|
||||
import { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
@ -15,7 +15,7 @@ import Account from './Account';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
balances: ExtendedBalanceMap,
|
||||
balances: RxBalanceMap,
|
||||
intentions: Array<string>,
|
||||
validators: Array<string>
|
||||
};
|
||||
|
||||
@ -3,7 +3,8 @@
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { ApiProps, ExtendedBalance, ExtendedBalanceMap } from '@polkadot/ui-react-rx/types';
|
||||
import { RxBalance, RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
import { ApiProps } from '@polkadot/ui-react-rx/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
@ -15,7 +16,7 @@ import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
balances: ExtendedBalanceMap,
|
||||
balances: RxBalanceMap,
|
||||
bestNumber?: BN,
|
||||
intentions: Array<string>,
|
||||
lastLengthChange?: BN,
|
||||
@ -74,10 +75,10 @@ class Summary extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
|
||||
private calcIntentionsHigh (): ExtendedBalance | null {
|
||||
private calcIntentionsHigh (): RxBalance | null {
|
||||
const { balances, intentions, validators } = this.props;
|
||||
|
||||
return intentions.reduce((high: ExtendedBalance | null, addr) => {
|
||||
return intentions.reduce((high: RxBalance | null, addr) => {
|
||||
const balance = validators.includes(addr) || !balances[addr]
|
||||
? null
|
||||
: balances[addr];
|
||||
@ -90,10 +91,10 @@ class Summary extends React.PureComponent<Props> {
|
||||
}, null);
|
||||
}
|
||||
|
||||
private calcValidatorLow (): ExtendedBalance | null {
|
||||
private calcValidatorLow (): RxBalance | null {
|
||||
const { balances, validators } = this.props;
|
||||
|
||||
return validators.reduce((low: ExtendedBalance | null, addr) => {
|
||||
return validators.reduce((low: RxBalance | null, addr) => {
|
||||
const balance = balances[addr] || null;
|
||||
|
||||
if (low === null || (balance && low.stakingBalance.gt(balance.stakingBalance))) {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { BareProps } from '@polkadot/ui-app/types';
|
||||
import { ExtendedBalanceMap } from '@polkadot/ui-react-rx/types';
|
||||
import { RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
|
||||
import React from 'react';
|
||||
import Page from '@polkadot/ui-app/Page';
|
||||
@ -17,7 +17,7 @@ import StakeList from './StakeList';
|
||||
import Summary from './Summary';
|
||||
|
||||
type Props = BareProps & {
|
||||
validatingBalances?: ExtendedBalanceMap,
|
||||
validatingBalances?: RxBalanceMap,
|
||||
stakingIntentions?: Array<string>,
|
||||
sessionValidators?: Array<string>
|
||||
};
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/app-accounts": "^0.19.30",
|
||||
"@polkadot/app-addresses": "^0.19.30",
|
||||
"@polkadot/app-democracy": "^0.19.30",
|
||||
"@polkadot/app-example": "^0.19.30",
|
||||
"@polkadot/app-explorer": "^0.19.30",
|
||||
"@polkadot/app-extrinsics": "^0.19.30",
|
||||
|
||||
1
packages/apps/public/locales/en/democracy.json
Normal file
1
packages/apps/public/locales/en/democracy.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
||||
1
packages/apps/public/locales/en/staking.json
Normal file
1
packages/apps/public/locales/en/staking.json
Normal file
@ -0,0 +1 @@
|
||||
{}
|
||||
20
packages/apps/src/routing/democracy.ts
Normal file
20
packages/apps/src/routing/democracy.ts
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2017-2018 @polkadot/apps authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { Routes } from '../types';
|
||||
|
||||
import Democracy from '@polkadot/app-democracy/index';
|
||||
|
||||
export default ([
|
||||
{
|
||||
Component: Democracy,
|
||||
i18n: {
|
||||
defaultValue: 'Democracy'
|
||||
},
|
||||
icon: 'calendar check',
|
||||
isExact: false,
|
||||
isHidden: false,
|
||||
name: 'democracy'
|
||||
}
|
||||
] as Routes);
|
||||
@ -6,6 +6,7 @@ import { Routing, Routes } from '../types';
|
||||
|
||||
import accounts from './accounts';
|
||||
import addresses from './addresses';
|
||||
import democracy from './democracy';
|
||||
import example from './example';
|
||||
import explorer from './explorer';
|
||||
import extrinsics from './extrinsics';
|
||||
@ -21,7 +22,20 @@ import vanitygen from './vanitygen';
|
||||
export default ({
|
||||
default: 'explorer',
|
||||
routes: ([] as Routes).concat(
|
||||
example, explorer, staking, extrinsics, storage, null, accounts, addresses, vanitygen, null, rpc, toolbox
|
||||
example,
|
||||
explorer,
|
||||
staking,
|
||||
democracy,
|
||||
null,
|
||||
extrinsics,
|
||||
storage,
|
||||
null,
|
||||
accounts,
|
||||
addresses,
|
||||
vanitygen,
|
||||
null,
|
||||
rpc,
|
||||
toolbox
|
||||
),
|
||||
unknown
|
||||
} as Routing);
|
||||
|
||||
@ -10,7 +10,25 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
const packages = ['app-accounts', 'app-addresses', 'app-example', 'app-explorer', 'app-extrinsics', 'app-rpc', 'app-staking', 'app-storage', 'app-toolbox', 'app-vanitygen', 'ui-app', 'ui-identicon', 'ui-keyring', 'ui-react-rx', 'ui-react', 'ui-signer'];
|
||||
const packages = [
|
||||
'app-accounts',
|
||||
'app-addresses',
|
||||
'app-democracy',
|
||||
'app-example',
|
||||
'app-explorer',
|
||||
'app-extrinsics',
|
||||
'app-rpc',
|
||||
'app-staking',
|
||||
'app-storage',
|
||||
'app-toolbox',
|
||||
'app-vanitygen',
|
||||
'ui-app',
|
||||
'ui-identicon',
|
||||
'ui-keyring',
|
||||
'ui-react-rx',
|
||||
'ui-react',
|
||||
'ui-signer'
|
||||
];
|
||||
|
||||
function createWebpack ({ alias = {}, context, name = 'index' }) {
|
||||
const pkgJson = require(path.join(context, 'package.json'));
|
||||
|
||||
@ -9,28 +9,26 @@
|
||||
],
|
||||
"contributors": [],
|
||||
"license": "ISC",
|
||||
"scripts": {
|
||||
"build": "polkadot-dev-build-babel",
|
||||
"check": "stylelint 'src/**/*.css' && eslint src && flow check",
|
||||
"test": "jest --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/extrinsics": "^0.28.9",
|
||||
"@polkadot/storage": "^0.28.9",
|
||||
"@polkadot/extrinsics": "^0.28.11",
|
||||
"@polkadot/storage": "^0.28.11",
|
||||
"@polkadot/ui-keyring": "^0.19.30",
|
||||
"@polkadot/ui-react": "^0.19.30",
|
||||
"@polkadot/ui-react-rx": "^0.19.30",
|
||||
"@types/chart.js": "^2.7.30",
|
||||
"@types/i18next-browser-languagedetector": "^2.0.1",
|
||||
"@types/i18next-xhr-backend": "^1.4.1",
|
||||
"@types/react-copy-to-clipboard": "^4.2.5",
|
||||
"@types/react-dropzone": "^4.2.0",
|
||||
"@types/react-i18next": "^7.6.1",
|
||||
"@types/react-router-dom": "^4.2.7",
|
||||
"chart.js": "^2.7.2",
|
||||
"i18next": "^11.1.1",
|
||||
"i18next-browser-languagedetector": "^2.2.0",
|
||||
"i18next-xhr-backend": "^1.5.1",
|
||||
"react": "^16.4.1",
|
||||
"react-chartjs-2": "^2.7.4",
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-i18next": "^7.7.0",
|
||||
|
||||
@ -14,6 +14,7 @@ import Balance from './Balance';
|
||||
|
||||
type Props = BareProps & {
|
||||
balance?: BN | Array<BN>,
|
||||
isPadded?: boolean,
|
||||
isShort?: boolean,
|
||||
value?: string,
|
||||
withBalance?: boolean
|
||||
@ -21,7 +22,7 @@ type Props = BareProps & {
|
||||
|
||||
export default class AddressMini extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, isShort = true, style, value } = this.props;
|
||||
const { className, isPadded = true, isShort = true, style, value } = this.props;
|
||||
|
||||
if (!value) {
|
||||
return null;
|
||||
@ -29,7 +30,7 @@ export default class AddressMini extends React.PureComponent<Props> {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('ui--AddressMini', className)}
|
||||
className={classes('ui--AddressMini', isPadded ? 'padded' : '', className)}
|
||||
style={style}
|
||||
>
|
||||
<div className='ui--AddressMini-info'>
|
||||
|
||||
@ -17,7 +17,7 @@ import Or from './Or';
|
||||
|
||||
class Button extends React.PureComponent<ButtonProps> {
|
||||
render () {
|
||||
const { children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isNegative = false, isPrimary = false, onClick, size, style, text } = this.props;
|
||||
const { children, className, floated, icon, isBasic = false, isCircular = false, isDisabled = false, isNegative = false, isPositive = false, isPrimary = false, onClick, size, style, text } = this.props;
|
||||
|
||||
const props = {
|
||||
basic: isBasic || false,
|
||||
@ -28,9 +28,10 @@ class Button extends React.PureComponent<ButtonProps> {
|
||||
icon,
|
||||
negative: isNegative,
|
||||
onClick,
|
||||
positive: isPositive,
|
||||
primary: isPrimary,
|
||||
size,
|
||||
secondary: isBasic && !(isPrimary || isNegative || false),
|
||||
secondary: isBasic && !(isPositive || isPrimary || isNegative || false),
|
||||
style
|
||||
};
|
||||
|
||||
|
||||
1
packages/ui-app/src/Button/types.d.ts
vendored
1
packages/ui-app/src/Button/types.d.ts
vendored
@ -14,6 +14,7 @@ export type ButtonProps = BareProps & {
|
||||
isCircular?: boolean,
|
||||
isDisabled?: boolean,
|
||||
isNegative?: boolean,
|
||||
isPositive?: boolean,
|
||||
isPrimary?: boolean,
|
||||
onClick?: () => void | Promise<void>,
|
||||
size?: Button$Sizes,
|
||||
|
||||
@ -38,7 +38,7 @@ export default class CardSummary extends React.PureComponent<Props> {
|
||||
<div className='ui--CardSummary-large'>
|
||||
{children}{
|
||||
progress && (
|
||||
(isUndefined(progress.value) || progress.value.ltn(0)) || isUndefined(progress.total)
|
||||
(isUndefined(progress.value) || isUndefined(progress.total) || progress.value.ltn(0)) || progress.value.gt(progress.total) || progress.total.eqn(0)
|
||||
? '-'
|
||||
: `${progress.value.toString()}/${progress.total.toString()}`
|
||||
)
|
||||
|
||||
69
packages/ui-app/src/Chart/Doughnut.tsx
Normal file
69
packages/ui-app/src/Chart/Doughnut.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2017-2018 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { BareProps } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import { Doughnut } from 'react-chartjs-2';
|
||||
import bnToBn from '@polkadot/util/bn/toBn';
|
||||
|
||||
import classes from '../util/classes';
|
||||
|
||||
type Value = {
|
||||
colors: Array<string>,
|
||||
label: string,
|
||||
value: number | BN
|
||||
};
|
||||
|
||||
type Props = BareProps & {
|
||||
size?: number,
|
||||
values: Array<Value>
|
||||
};
|
||||
|
||||
type Options = {
|
||||
colorNormal: Array<string>,
|
||||
colorHover: Array<string>,
|
||||
data: Array<number>,
|
||||
labels: Array<string>
|
||||
};
|
||||
|
||||
export default class ChartDoughnut extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, size = 100, style, values } = this.props;
|
||||
|
||||
const options = values.reduce((options, { colors: [normalColor = '#00f', hoverColor], label, value }) => {
|
||||
options.colorNormal.push(normalColor);
|
||||
options.colorHover.push(hoverColor || normalColor);
|
||||
options.data.push(bnToBn(value).toNumber());
|
||||
options.labels.push(label);
|
||||
|
||||
return options;
|
||||
}, {
|
||||
colorNormal: [],
|
||||
colorHover: [],
|
||||
data: [],
|
||||
labels: []
|
||||
} as Options);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('ui--Chart', className)}
|
||||
style={style}
|
||||
>
|
||||
<Doughnut
|
||||
data={{
|
||||
labels: options.labels,
|
||||
datasets: [{
|
||||
data: options.data,
|
||||
backgroundColor: options.colorNormal,
|
||||
hoverBackgroundColor: options.colorHover
|
||||
}]
|
||||
}}
|
||||
height={size}
|
||||
width={size} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ export default class Account extends React.PureComponent<Props> {
|
||||
style={style}
|
||||
>
|
||||
<InputAddress
|
||||
className='large'
|
||||
className={isDisabled ? 'full' : 'large'}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
@ -37,7 +37,7 @@ export default class Account extends React.PureComponent<Props> {
|
||||
onChange = (value?: Uint8Array): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: !!value && value.length === 32,
|
||||
value
|
||||
});
|
||||
|
||||
@ -21,8 +21,8 @@ export default class Amount extends React.PureComponent<Props> {
|
||||
style={style}
|
||||
>
|
||||
<Input
|
||||
className='small'
|
||||
defaultValue={defaultValue || 0}
|
||||
className={isDisabled ? 'full' : 'small'}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
label={label}
|
||||
@ -38,7 +38,7 @@ export default class Amount extends React.PureComponent<Props> {
|
||||
onChange = (value: string): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: true,
|
||||
value: new BN(value || 0)
|
||||
});
|
||||
|
||||
@ -11,20 +11,21 @@ import Labelled from '../../Labelled';
|
||||
import Bare from './Bare';
|
||||
|
||||
type Props = BareProps & {
|
||||
children: any, // node?
|
||||
children: React.ReactNode,
|
||||
isDisabled?: boolean,
|
||||
label?: string,
|
||||
size?: Size,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
export default function Base ({ children, className, label, size = 'medium', style, withLabel }: Props) {
|
||||
export default function Base ({ children, className, isDisabled, label, size = 'medium', style, withLabel }: Props) {
|
||||
return (
|
||||
<Bare
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
className={size}
|
||||
className={isDisabled ? 'full' : size}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
|
||||
@ -8,6 +8,7 @@ import React from 'react';
|
||||
import hexToU8a from '@polkadot/util/hex/toU8a';
|
||||
import bnToU8a from '@polkadot/util/bn/toU8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
import u8aToHex from '@polkadot/util/u8a/toHex';
|
||||
|
||||
import Input from '../../Input';
|
||||
import Bare from './Bare';
|
||||
@ -24,7 +25,10 @@ const defaultValidate = (u8a: Uint8Array): boolean =>
|
||||
|
||||
export default class BaseBytes extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, isDisabled, isError, label, size = 'full', style, withLabel } = this.props;
|
||||
const { className, defaultValue: { value }, isDisabled, isError, label, size = 'full', style, withLabel } = this.props;
|
||||
const defaultValue = value
|
||||
? u8aToHex(value as Uint8Array)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Bare
|
||||
@ -33,6 +37,7 @@ export default class BaseBytes extends React.PureComponent<Props> {
|
||||
>
|
||||
<Input
|
||||
className={size}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
label={label}
|
||||
@ -61,7 +66,7 @@ export default class BaseBytes extends React.PureComponent<Props> {
|
||||
: u8a.length !== 0;
|
||||
const isValid = isValidLength && validate(u8a);
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid,
|
||||
value: u8aConcat(
|
||||
withLength
|
||||
|
||||
@ -25,7 +25,7 @@ export default class Bool extends React.PureComponent<Props> {
|
||||
style={style}
|
||||
>
|
||||
<Dropdown
|
||||
className='small'
|
||||
className={isDisabled ? 'full' : 'small'}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
@ -41,7 +41,7 @@ export default class Bool extends React.PureComponent<Props> {
|
||||
onChange = (value: boolean): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: true,
|
||||
value
|
||||
});
|
||||
|
||||
@ -9,15 +9,20 @@ import React from 'react';
|
||||
import bnToU8a from '@polkadot/util/bn/toU8a';
|
||||
import u8aConcat from '@polkadot/util/u8a/concat';
|
||||
|
||||
import Bytes from './Bytes';
|
||||
import BytesFile from './File';
|
||||
|
||||
export default class Code extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const { className, defaultValue, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const Component = isDisabled
|
||||
? Bytes
|
||||
: BytesFile;
|
||||
|
||||
return (
|
||||
<BytesFile
|
||||
<Component
|
||||
className={className}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
label={label}
|
||||
@ -32,7 +37,7 @@ export default class Code extends React.PureComponent<Props> {
|
||||
onChange = (value: Uint8Array): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: value.length !== 0,
|
||||
value: u8aConcat(bnToU8a(value.length, 32, true), value)
|
||||
});
|
||||
|
||||
@ -16,7 +16,7 @@ type Props = BareProps & {
|
||||
isDisabled?: boolean,
|
||||
isError?: boolean,
|
||||
label: string,
|
||||
onChange: (contents: Uint8Array) => void,
|
||||
onChange?: (contents: Uint8Array) => void,
|
||||
placeholder?: string,
|
||||
t: TranslationFunction,
|
||||
withLabel?: boolean
|
||||
@ -87,7 +87,7 @@ class BytesFile extends React.PureComponent<Props, State> {
|
||||
reader.onload = ({ target: { result } }: LoadEvent) => {
|
||||
const data = new Uint8Array(result);
|
||||
|
||||
onChange(data);
|
||||
onChange && onChange(data);
|
||||
|
||||
this.setState({
|
||||
file: {
|
||||
|
||||
@ -19,7 +19,7 @@ export default function Hash ({ className, defaultValue, isDisabled, isError, la
|
||||
length={32}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
size='medium'
|
||||
size={isDisabled ? 'full' : 'medium'}
|
||||
style={style}
|
||||
withLabel={withLabel}
|
||||
/>
|
||||
|
||||
@ -23,7 +23,7 @@ type State = {
|
||||
value: State$Param
|
||||
};
|
||||
|
||||
export default class KeyValue extends React.PureComponent<Props, State> {
|
||||
export default class StorageKeyValue extends React.PureComponent<Props, State> {
|
||||
state: State = {
|
||||
key: {
|
||||
isValid: false,
|
||||
@ -91,7 +91,7 @@ export default class KeyValue extends React.PureComponent<Props, State> {
|
||||
(prevState: State, { onChange }: Props) => {
|
||||
const { key = prevState.key, value = prevState.value } = newState;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: key.isValid && value.isValid,
|
||||
value: u8aConcat(
|
||||
u8aConcat(bnToU8a(key.u8a.length, 32, true), key.u8a),
|
||||
@ -4,15 +4,18 @@
|
||||
|
||||
import { TranslationFunction } from 'i18next';
|
||||
import { KeyValue } from '@polkadot/params/types';
|
||||
import { Props as BaseProps } from '../types';
|
||||
import { Props as BaseProps, RawParam } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import assert from '@polkadot/util/assert';
|
||||
import isHex from '@polkadot/util/is/hex';
|
||||
import u8aToUtf8 from '@polkadot/util/u8a/toUtf8';
|
||||
import toU8a from '@polkadot/util/u8a/toU8a';
|
||||
import u8aToHex from '@polkadot/util/u8a/toHex';
|
||||
|
||||
import translate from '../../translate';
|
||||
import Base from './Base';
|
||||
import Bytes from './Bytes';
|
||||
import BytesFile from './File';
|
||||
|
||||
type Props = BaseProps & {
|
||||
@ -23,7 +26,9 @@ type State = {
|
||||
placeholder?: string;
|
||||
};
|
||||
|
||||
class KeyValueStorageArray extends React.PureComponent<Props, State> {
|
||||
type Pairs = Array<KeyValue>;
|
||||
|
||||
class StorageKeyValueArray extends React.PureComponent<Props, State> {
|
||||
private placeholderEmpty: string;
|
||||
|
||||
constructor (props: Props) {
|
||||
@ -41,6 +46,10 @@ class KeyValueStorageArray extends React.PureComponent<Props, State> {
|
||||
const { className, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const { placeholder } = this.state;
|
||||
|
||||
if (isDisabled) {
|
||||
return this.renderReadOnly();
|
||||
}
|
||||
|
||||
return (
|
||||
<BytesFile
|
||||
className={className}
|
||||
@ -55,7 +64,33 @@ class KeyValueStorageArray extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
|
||||
onChange = (raw: Uint8Array): void => {
|
||||
private renderReadOnly () {
|
||||
const { className, defaultValue: { value }, label, style } = this.props;
|
||||
|
||||
return (
|
||||
<Base
|
||||
className={className}
|
||||
label={label}
|
||||
size='full'
|
||||
style={style}
|
||||
>
|
||||
{(value as Pairs).map(({ key, value }) => {
|
||||
const keyHex = u8aToHex(key);
|
||||
|
||||
return (
|
||||
<Bytes
|
||||
defaultValue={{ value } as RawParam}
|
||||
key={keyHex}
|
||||
label={keyHex}
|
||||
name={keyHex}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Base>
|
||||
);
|
||||
}
|
||||
|
||||
private onChange = (raw: Uint8Array): void => {
|
||||
const { onChange, t } = this.props;
|
||||
let value: KeyValue[] = [];
|
||||
|
||||
@ -78,7 +113,7 @@ class KeyValueStorageArray extends React.PureComponent<Props, State> {
|
||||
});
|
||||
}
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: value.length !== 0,
|
||||
value
|
||||
});
|
||||
@ -100,4 +135,4 @@ class KeyValueStorageArray extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(KeyValueStorageArray);
|
||||
export default translate(StorageKeyValueArray);
|
||||
@ -11,7 +11,8 @@ import Bare from './Bare';
|
||||
|
||||
export default class StringParam extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const defaultValue = value as string;
|
||||
|
||||
return (
|
||||
<Bare
|
||||
@ -20,6 +21,7 @@ export default class StringParam extends React.PureComponent<Props> {
|
||||
>
|
||||
<Input
|
||||
className='full'
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
label={label}
|
||||
@ -34,10 +36,9 @@ export default class StringParam extends React.PureComponent<Props> {
|
||||
|
||||
onChange = (value: string): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
const isValid = value.length !== 0;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid,
|
||||
value
|
||||
});
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import bnToBn from '@polkadot/util/bn/toBn';
|
||||
|
||||
import Dropdown from '../../Dropdown';
|
||||
import Bare from './Bare';
|
||||
@ -26,7 +27,7 @@ export const textMap = options.reduce((textMap, { text, value }) => {
|
||||
export default class VoteThreshold extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, defaultValue: { value }, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
const defaultValue = (value as number);
|
||||
const defaultValue = bnToBn(value as number).toNumber();
|
||||
|
||||
return (
|
||||
<Bare
|
||||
@ -34,7 +35,7 @@ export default class VoteThreshold extends React.PureComponent<Props> {
|
||||
style={style}
|
||||
>
|
||||
<Dropdown
|
||||
className='small'
|
||||
className={isDisabled ? 'full' : 'small'}
|
||||
defaultValue={defaultValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
@ -50,7 +51,7 @@ export default class VoteThreshold extends React.PureComponent<Props> {
|
||||
onChange = (value: number): void => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
onChange && onChange({
|
||||
isValid: true,
|
||||
value
|
||||
});
|
||||
|
||||
@ -11,8 +11,8 @@ import Bool from './Bool';
|
||||
import Bytes from './Bytes';
|
||||
import Code from './Code';
|
||||
import Hash from './Hash';
|
||||
import KeyValue from './KeyValue';
|
||||
import KeyValueStorageArray from './KeyValueStorageArray';
|
||||
import StorageKeyValue from './StorageKeyValue';
|
||||
import StorageKeyValueArray from './StorageKeyValueArray';
|
||||
import StringParam from './String';
|
||||
import Unknown from './Unknown';
|
||||
import VoteThreshold from './VoteThreshold';
|
||||
@ -28,9 +28,9 @@ const components: ComponentMap = {
|
||||
'Digest': Unknown,
|
||||
'Hash': Hash,
|
||||
'Index': Amount,
|
||||
'KeyValue': KeyValue,
|
||||
'KeyValueStorage': KeyValue,
|
||||
'KeyValueStorage[]': KeyValueStorageArray,
|
||||
'KeyValue': StorageKeyValue,
|
||||
'StorageKeyValue': StorageKeyValue,
|
||||
'StorageKeyValue[]': StorageKeyValueArray,
|
||||
'MisbehaviorReport': Unknown,
|
||||
'ParachainId': Amount,
|
||||
'PropIndex': Amount,
|
||||
@ -46,7 +46,7 @@ const components: ComponentMap = {
|
||||
'VoteThreshold': VoteThreshold
|
||||
};
|
||||
|
||||
export default function findComponent (type: Param$Types, overrides: ComponentMap = {}): React.ComponentType<Props> {
|
||||
function getFromMap (type: Param$Types, overrides: ComponentMap): React.ComponentType<Props> | [React.ComponentType<Props>, React.ComponentType<Props>] {
|
||||
if (Array.isArray(type)) {
|
||||
// Special case for components where we have a specific override formatter
|
||||
if (type.length === 1) {
|
||||
@ -60,3 +60,11 @@ export default function findComponent (type: Param$Types, overrides: ComponentMa
|
||||
|
||||
return overrides[type] || components[type] || Unknown;
|
||||
}
|
||||
|
||||
export default function findComponent (type: Param$Types, overrides: ComponentMap = {}, isDisabled: boolean = false): React.ComponentType<Props> {
|
||||
const component = getFromMap(type, overrides);
|
||||
|
||||
return Array.isArray(component)
|
||||
? component[0]
|
||||
: component;
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import translate from '../../translate';
|
||||
import findComponent from './findComponent';
|
||||
|
||||
type Props = I18nProps & BaseProps & {
|
||||
isDisabled?: boolean,
|
||||
overrides?: ComponentMap
|
||||
};
|
||||
|
||||
@ -26,11 +27,11 @@ class ParamComponent extends React.PureComponent<Props, State> {
|
||||
Component: null
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ defaultValue: { type }, overrides }: Props): State {
|
||||
static getDerivedStateFromProps ({ defaultValue: { type }, isDisabled, overrides }: Props): State {
|
||||
return {
|
||||
Component: !type
|
||||
? null
|
||||
: findComponent(type, overrides)
|
||||
: findComponent(type, overrides, isDisabled)
|
||||
} as State;
|
||||
}
|
||||
|
||||
@ -41,7 +42,7 @@ class ParamComponent extends React.PureComponent<Props, State> {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { className, defaultValue, name, onChange, style } = this.props;
|
||||
const { className, defaultValue, isDisabled, name, onChange, style } = this.props;
|
||||
const type = typeToString(defaultValue.type);
|
||||
|
||||
return (
|
||||
@ -49,6 +50,7 @@ class ParamComponent extends React.PureComponent<Props, State> {
|
||||
className={classes('ui--Param', className)}
|
||||
defaultValue={defaultValue}
|
||||
key={`${name}:${type}`}
|
||||
isDisabled={isDisabled}
|
||||
label={`${name}: ${type}`}
|
||||
name={name}
|
||||
onChange={onChange}
|
||||
|
||||
@ -16,9 +16,11 @@ import Param from './Param';
|
||||
import createValues from './values';
|
||||
|
||||
type Props<S> = I18nProps & {
|
||||
isDisabled?: boolean,
|
||||
item: S,
|
||||
onChange: (value: RawParams) => void,
|
||||
overrides?: ComponentMap
|
||||
onChange?: (value: RawParams) => void,
|
||||
overrides?: ComponentMap,
|
||||
values?: RawParams
|
||||
};
|
||||
|
||||
type State<S> = {
|
||||
@ -40,7 +42,9 @@ class Params<T, S extends SectionItem<T>> extends React.PureComponent<Props<S>,
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps (props: Props<any>, { item, onChangeParam }: State<any>): State<any> | null {
|
||||
if (item && item.name === props.item.name && item.section === props.item.section) {
|
||||
const isSame = item && item.name === props.item.name && item.section === props.item.section;
|
||||
|
||||
if (props.isDisabled || isSame) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -61,19 +65,19 @@ class Params<T, S extends SectionItem<T>> extends React.PureComponent<Props<S>,
|
||||
|
||||
// NOTE This is needed in the case where the item changes, i.e. the values get initialised and we need to alert the parent that we have new values
|
||||
componentDidUpdate (prevProps: Props<S>, prevState: State<S>) {
|
||||
const { onChange } = this.props;
|
||||
const { onChange, isDisabled } = this.props;
|
||||
const { values } = this.state;
|
||||
|
||||
if (prevState.values !== values) {
|
||||
onChange(values);
|
||||
if (!isDisabled && prevState.values !== values) {
|
||||
onChange && onChange(values);
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, item: { params }, overrides, style } = this.props;
|
||||
const { handlers, values } = this.state;
|
||||
const { className, isDisabled, item: { params }, overrides, style } = this.props;
|
||||
const { handlers = [], values = this.props.values } = this.state;
|
||||
|
||||
if (values.length === 0 || params.length === 0) {
|
||||
if (!values || values.length === 0 || params.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -86,6 +90,7 @@ class Params<T, S extends SectionItem<T>> extends React.PureComponent<Props<S>,
|
||||
{params.map(({ name }, index) => (
|
||||
<Param
|
||||
defaultValue={values[index]}
|
||||
isDisabled={isDisabled}
|
||||
key={`${name}:${name}:${index}`}
|
||||
name={name}
|
||||
onChange={handlers[index]}
|
||||
@ -97,7 +102,13 @@ class Params<T, S extends SectionItem<T>> extends React.PureComponent<Props<S>,
|
||||
);
|
||||
}
|
||||
|
||||
onChangeParam = (at: number, { isValid = false, value }: RawParam$OnChange$Value): void => {
|
||||
private onChangeParam = (at: number, { isValid = false, value }: RawParam$OnChange$Value): void => {
|
||||
const { isDisabled } = this.props;
|
||||
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState(
|
||||
(prevState: State<S>): State<S> => ({
|
||||
values: prevState.values.map((prev, index) =>
|
||||
@ -116,9 +127,13 @@ class Params<T, S extends SectionItem<T>> extends React.PureComponent<Props<S>,
|
||||
|
||||
triggerUpdate = (): void => {
|
||||
const { values } = this.state;
|
||||
const { onChange } = this.props;
|
||||
const { onChange, isDisabled } = this.props;
|
||||
|
||||
onChange(values);
|
||||
if (isDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
onChange && onChange(values);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ export default function getInitValue (type: Param$Types): RawParam$Value | Array
|
||||
case 'Hash':
|
||||
case 'Header':
|
||||
case 'KeyValue':
|
||||
case 'KeyValueStorage':
|
||||
case 'StorageKeyValue':
|
||||
case 'MisbehaviorReport':
|
||||
case 'Proposal':
|
||||
case 'Signature':
|
||||
|
||||
5
packages/ui-app/src/Params/types.d.ts
vendored
5
packages/ui-app/src/Params/types.d.ts
vendored
@ -25,12 +25,13 @@ export type RawParams = Array<RawParam>;
|
||||
export type BaseProps = BareProps & {
|
||||
defaultValue: RawParam,
|
||||
name: string,
|
||||
onChange: RawParam$OnChange
|
||||
onChange?: RawParam$OnChange
|
||||
};
|
||||
|
||||
export type Props = BaseProps & {
|
||||
isDisabled?: boolean,
|
||||
isError?: boolean,
|
||||
isReadOnly?: boolean,
|
||||
label: string,
|
||||
withLabel?: boolean
|
||||
};
|
||||
@ -38,5 +39,5 @@ export type Props = BaseProps & {
|
||||
export type Size = 'full' | 'large' | 'medium' | 'small';
|
||||
|
||||
export type ComponentMap = {
|
||||
[index: string]: React.ComponentType<Props> // Param$Type
|
||||
[index: string]: React.ComponentType<Props> | [React.ComponentType<Props>, React.ComponentType<Props>] // Param$Type
|
||||
};
|
||||
|
||||
@ -16,3 +16,9 @@ body {
|
||||
font-family: sans-serif;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: rgba(0, 0, 0, .6);
|
||||
font-weight: 400;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
@ -32,6 +32,11 @@
|
||||
}
|
||||
|
||||
.ui--AddressMini {
|
||||
display: inline-block;
|
||||
padding: 0 0.25rem 0 0;
|
||||
}
|
||||
|
||||
.ui--AddressMini.padded {
|
||||
display: inline-block;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
@ -137,6 +142,14 @@
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.ui--Chart {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 1em 1em 0;
|
||||
height: 15vw;
|
||||
width: 15vw;
|
||||
}
|
||||
|
||||
.ui--CardSummary-large {
|
||||
font-size: 3rem;
|
||||
line-height: 3rem;
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/api-rx": "^0.28.9",
|
||||
"@polkadot/extrinsics": "^0.28.9",
|
||||
"@polkadot/storage": "^0.28.9",
|
||||
"@polkadot/api-rx": "^0.28.11",
|
||||
"@polkadot/extrinsics": "^0.28.11",
|
||||
"@polkadot/storage": "^0.28.11",
|
||||
"rxjs-compat": "^6.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -5,20 +5,25 @@
|
||||
import { Header } from '@polkadot/primitives/header';
|
||||
import { RxApiInterface, RxApiInterface$Method } from '@polkadot/api-rx/types';
|
||||
import { Interfaces } from '@polkadot/jsonrpc/types';
|
||||
import { SectionItem } from '@polkadot/params/types';
|
||||
import { ExtrinsicDecoded, SectionItem } from '@polkadot/params/types';
|
||||
import { Storages } from '@polkadot/storage/types';
|
||||
import { ExtendedBalance, ExtendedBalanceMap, ObservableApiInterface, KeyWithParams } from './types';
|
||||
import { RxBalance, RxBalanceMap, RxProposal, RxProposalDeposits, RxReferendum, ObservableApiInterface, KeyWithParams, RxReferendumVote } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable, combineLatest } from 'rxjs';
|
||||
import { concatMap, defaultIfEmpty, map } from 'rxjs/operators';
|
||||
import { EMPTY, Observable, combineLatest } from 'rxjs';
|
||||
import { switchMap, defaultIfEmpty, map } from 'rxjs/operators';
|
||||
import storage from '@polkadot/storage';
|
||||
import assert from '@polkadot/util/assert';
|
||||
import isUndefined from '@polkadot/util/is/undefined';
|
||||
|
||||
type OptBN = BN | undefined;
|
||||
type OptDate = Date | undefined;
|
||||
type MapFn<R, T> = (combined: R) => T;
|
||||
|
||||
type ResultReferendum = [BN, ExtrinsicDecoded, number];
|
||||
type ResultProposal = [BN, ExtrinsicDecoded, string];
|
||||
type ResultProposalDeposits = [BN, Array<string>];
|
||||
|
||||
const defaultMapFn = (result: any): any =>
|
||||
result;
|
||||
|
||||
@ -52,31 +57,218 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
rawStorage = <T> (key: SectionItem<Storages>, ...params: Array<any>): Observable<T> => {
|
||||
return this
|
||||
.rawStorageMulti([key, ...params] as KeyWithParams)
|
||||
.pipe(map(([result]: Array<T>): T =>
|
||||
result
|
||||
));
|
||||
.pipe(
|
||||
map(([result]: Array<T>): T =>
|
||||
result
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
rawStorageMulti = <T> (...keys: Array<KeyWithParams>): Observable<T> => {
|
||||
return this.api.state
|
||||
.subscribeStorage(keys)
|
||||
.pipe(map((result?: any) =>
|
||||
result || []
|
||||
));
|
||||
.pipe(
|
||||
map((result?: any) =>
|
||||
isUndefined(result)
|
||||
? []
|
||||
: result
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
bestNumber = (): Observable<OptBN> => {
|
||||
return this.chainNewHead().pipe(
|
||||
map((header?: Header): OptBN =>
|
||||
header && header.number
|
||||
? header.number
|
||||
: undefined
|
||||
return this
|
||||
.chainNewHead()
|
||||
.pipe(
|
||||
map((header?: Header): OptBN =>
|
||||
header && header.number
|
||||
? header.number
|
||||
: undefined
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
chainNewHead = (): Observable<Header | undefined> => {
|
||||
return this.api.chain.subscribeNewHead().pipe(
|
||||
defaultIfEmpty()
|
||||
);
|
||||
}
|
||||
|
||||
democracyLaunchPeriod = (): Observable<OptBN> => {
|
||||
return this.rawStorage(storage.democracy.public.launchPeriod);
|
||||
}
|
||||
|
||||
democracyNextTally = (): Observable<OptBN> => {
|
||||
return this.rawStorage(storage.democracy.public.nextTally);
|
||||
}
|
||||
|
||||
democracyProposals = (): Observable<Array<RxProposal>> => {
|
||||
return this
|
||||
.rawStorage(storage.democracy.public.proposals)
|
||||
.pipe(
|
||||
map((proposals: Array<ResultProposal> = []) =>
|
||||
proposals
|
||||
.map((result: ResultProposal): RxProposal | undefined =>
|
||||
result && result[1]
|
||||
? {
|
||||
address: result[2],
|
||||
id: result[0],
|
||||
proposal: result[1]
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
.filter((proposal) =>
|
||||
proposal
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyProposalCount = (): Observable<number> => {
|
||||
return this
|
||||
.democracyProposals()
|
||||
.pipe(
|
||||
map((proposals: Array<RxProposal>) =>
|
||||
proposals.length
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyProposalDeposits = (proposalId: BN): Observable<RxProposalDeposits | undefined> => {
|
||||
return this
|
||||
.rawStorage(storage.democracy.public.depositOf, proposalId)
|
||||
.pipe(
|
||||
map((result: ResultProposalDeposits): RxProposalDeposits | undefined =>
|
||||
result && result[0]
|
||||
? {
|
||||
addresses: result[1] || [],
|
||||
balance: result[0]
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyReferendumCount = (): Observable<OptBN> => {
|
||||
return this.rawStorage(storage.democracy.public.referendumCount);
|
||||
}
|
||||
|
||||
democracyReferendumInfoOf = (referendumId: BN | number): Observable<RxReferendum> => {
|
||||
return this
|
||||
.rawStorage(storage.democracy.public.referendumInfoOf, referendumId)
|
||||
.pipe(
|
||||
map((result: ResultReferendum) =>
|
||||
result && result[1]
|
||||
? {
|
||||
blockNumber: result[0],
|
||||
id: new BN(referendumId),
|
||||
proposal: result[1],
|
||||
voteThreshold: result[2]
|
||||
}
|
||||
: undefined
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyReferendumInfos = (referendumIds: Array<number>): Observable<Array<RxReferendum>> => {
|
||||
return this.combine(
|
||||
referendumIds.map((referendumId) =>
|
||||
this.democracyReferendumInfoOf(referendumId)
|
||||
),
|
||||
(referendums: Array<RxReferendum> = []): Array<RxReferendum> =>
|
||||
referendums.filter((referendum) =>
|
||||
referendum
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyReferendumVoters = (referendumId: BN): Observable<Array<RxReferendumVote>> => {
|
||||
return this.combine(
|
||||
[
|
||||
this.democacyVotersFor(referendumId),
|
||||
this.democracyVotersBalancesOf(referendumId),
|
||||
this.democracyVotersVotesOf(referendumId)
|
||||
],
|
||||
([voters, balances, votes]: [Array<string>, Array<BN>, Array<boolean>]): Array<RxReferendumVote> =>
|
||||
voters.map((address, index): RxReferendumVote => ({
|
||||
address,
|
||||
balance: balances[index] || new BN(0),
|
||||
vote: votes[index] || false
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
democracyReferendums = (): Observable<Array<RxReferendum>> => {
|
||||
return this.combine(
|
||||
[
|
||||
this.democracyReferendumCount(),
|
||||
this.democracyNextTally()
|
||||
]
|
||||
).pipe(
|
||||
switchMap(([referendumCount, nextTally]: [OptBN, OptBN]): Observable<Array<RxReferendum>> =>
|
||||
referendumCount && nextTally && referendumCount.gt(nextTally) && referendumCount.gtn(0)
|
||||
? this.democracyReferendumInfos(
|
||||
[...Array(referendumCount.sub(nextTally).toNumber())].map((_, i) =>
|
||||
nextTally.addn(i).toNumber()
|
||||
)
|
||||
)
|
||||
: EMPTY
|
||||
),
|
||||
defaultIfEmpty([])
|
||||
);
|
||||
}
|
||||
|
||||
democacyVoteOf = (index: BN, address: string): Observable<boolean> => {
|
||||
return this.rawStorage(storage.democracy.public.voteOf, index, address);
|
||||
}
|
||||
|
||||
democracyVotesOf = (index: BN, addresses: Array<string>): Observable<boolean> => {
|
||||
return this.combine(
|
||||
addresses.map((address) =>
|
||||
this.democacyVoteOf(index, address)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
chainNewHead = (): Observable<Header | undefined> => {
|
||||
return this.api.chain.subscribeNewHead();
|
||||
democacyVotersFor = (index: BN): Observable<Array<string>> => {
|
||||
return this
|
||||
.rawStorage(storage.democracy.public.votersFor, index)
|
||||
.pipe(
|
||||
map((voters: Array<string> = []) =>
|
||||
voters
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyVotersBalancesOf = (referendumId: BN): Observable<Array<BN>> => {
|
||||
return this
|
||||
.democacyVotersFor(referendumId)
|
||||
.pipe(
|
||||
switchMap((voters: Array<string> = []) =>
|
||||
this.votingBalances(...voters)
|
||||
),
|
||||
defaultIfEmpty([]),
|
||||
map((balances: Array<RxBalance>) =>
|
||||
balances.map(({ votingBalance }) =>
|
||||
votingBalance
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
democracyVotersVotesOf = (referendumId: BN): Observable<Array<boolean>> => {
|
||||
return this
|
||||
.democacyVotersFor(referendumId)
|
||||
.pipe(
|
||||
switchMap((voters: Array<string> = []) =>
|
||||
this.democracyVotesOf(referendumId, voters)
|
||||
),
|
||||
defaultIfEmpty([])
|
||||
);
|
||||
}
|
||||
|
||||
democracyVotingPeriod = (): Observable<OptBN> => {
|
||||
return this.rawStorage(storage.democracy.public.votingPeriod);
|
||||
}
|
||||
|
||||
eraBlockLength = (): Observable<OptBN> => {
|
||||
@ -231,17 +423,21 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
sessionValidators = (): Observable<Array<string>> => {
|
||||
return this
|
||||
.rawStorage(storage.session.public.validators)
|
||||
.pipe(map((validators: Array<string> = []) =>
|
||||
validators
|
||||
));
|
||||
.pipe(
|
||||
map((validators: Array<string> = []) =>
|
||||
validators
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
stakingIntentions = (): Observable<Array<string>> => {
|
||||
return this
|
||||
.rawStorage(storage.staking.public.intentions)
|
||||
.pipe(map((intentions: Array<string> = []) =>
|
||||
intentions
|
||||
));
|
||||
.pipe(
|
||||
map((intentions: Array<string> = []) =>
|
||||
intentions
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
stakingFreeBalanceOf = (address: string): Observable<OptBN> => {
|
||||
@ -251,9 +447,11 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
stakingNominatorsFor = (address: string): Observable<Array<string>> => {
|
||||
return this
|
||||
.rawStorage(storage.staking.public.nominatorsFor, address)
|
||||
.pipe(map((nominators: Array<string> = []) =>
|
||||
nominators
|
||||
));
|
||||
.pipe(
|
||||
map((nominators: Array<string> = []) =>
|
||||
nominators
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
stakingNominating = (address: string): Observable<string | undefined> => {
|
||||
@ -276,14 +474,14 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
return this.rawStorage(storage.system.public.accountIndexOf, address);
|
||||
}
|
||||
|
||||
validatingBalance = (address: string): Observable<ExtendedBalance> => {
|
||||
validatingBalance = (address: string): Observable<RxBalance> => {
|
||||
return this.combine(
|
||||
[
|
||||
this.votingBalance(address),
|
||||
this.votingBalancesNominatorsFor(address)
|
||||
],
|
||||
([balance, nominators = []]: [ExtendedBalance, Array<ExtendedBalance>]): ExtendedBalance => {
|
||||
const nominatedBalance = nominators.reduce((total, nominator: ExtendedBalance) => {
|
||||
([balance, nominators = []]: [RxBalance, Array<RxBalance>]): RxBalance => {
|
||||
const nominatedBalance = nominators.reduce((total, nominator: RxBalance) => {
|
||||
return total.add(nominator.votingBalance);
|
||||
}, new BN(0));
|
||||
|
||||
@ -299,27 +497,27 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
);
|
||||
}
|
||||
|
||||
validatingBalances = (...addresses: Array<string>): Observable<ExtendedBalanceMap> => {
|
||||
validatingBalances = (...addresses: Array<string>): Observable<RxBalanceMap> => {
|
||||
return this.combine(
|
||||
addresses.map((address) =>
|
||||
this.validatingBalance(address)
|
||||
),
|
||||
(result: Array<ExtendedBalance>): ExtendedBalanceMap =>
|
||||
(result: Array<RxBalance>): RxBalanceMap =>
|
||||
result.reduce((balances, balance) => {
|
||||
balances[balance.address] = balance;
|
||||
|
||||
return balances;
|
||||
}, {} as ExtendedBalanceMap)
|
||||
}, {} as RxBalanceMap)
|
||||
);
|
||||
}
|
||||
|
||||
votingBalance = (address: string): Observable<ExtendedBalance> => {
|
||||
votingBalance = (address: string): Observable<RxBalance> => {
|
||||
return this.combine(
|
||||
[
|
||||
this.stakingFreeBalanceOf(address),
|
||||
this.stakingReservedBalanceOf(address)
|
||||
],
|
||||
([freeBalance = new BN(0), reservedBalance = new BN(0)]: [OptBN, OptBN]): ExtendedBalance => ({
|
||||
([freeBalance = new BN(0), reservedBalance = new BN(0)]: [OptBN, OptBN]): RxBalance => ({
|
||||
address,
|
||||
freeBalance,
|
||||
nominatedBalance: new BN(0),
|
||||
@ -331,15 +529,17 @@ export default class ObservableApi implements ObservableApiInterface {
|
||||
}
|
||||
|
||||
votingBalancesNominatorsFor = (address: string) => {
|
||||
return this.stakingNominatorsFor(address).pipe(
|
||||
concatMap((nominators: Array<string>) =>
|
||||
this.votingBalances(...nominators)
|
||||
),
|
||||
defaultIfEmpty([])
|
||||
);
|
||||
return this
|
||||
.stakingNominatorsFor(address)
|
||||
.pipe(
|
||||
switchMap((nominators: Array<string>) =>
|
||||
this.votingBalances(...nominators)
|
||||
),
|
||||
defaultIfEmpty([])
|
||||
);
|
||||
}
|
||||
|
||||
votingBalances = (...addresses: Array<string>): Observable<ExtendedBalance[]> => {
|
||||
votingBalances = (...addresses: Array<string>): Observable<RxBalance[]> => {
|
||||
return this.combine(
|
||||
addresses.map((address) =>
|
||||
this.votingBalance(address)
|
||||
92
packages/ui-react-rx/src/ApiObservable/types.d.ts
vendored
Normal file
92
packages/ui-react-rx/src/ApiObservable/types.d.ts
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2017-2018 @polkadot/ui-react-rx authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Interfaces } from '@polkadot/jsonrpc/types';
|
||||
import { ExtrinsicDecoded, SectionItem } from '@polkadot/params/types';
|
||||
import { Header } from '@polkadot/primitives/header';
|
||||
import { Storages } from '@polkadot/storage/types';
|
||||
|
||||
export type RxBalance = {
|
||||
address: string,
|
||||
freeBalance: BN,
|
||||
nominatedBalance: BN,
|
||||
reservedBalance: BN,
|
||||
votingBalance: BN,
|
||||
stakingBalance: BN,
|
||||
nominators?: Array<RxBalance>
|
||||
}
|
||||
|
||||
export type RxProposal = {
|
||||
address: string,
|
||||
id: BN,
|
||||
proposal: ExtrinsicDecoded
|
||||
};
|
||||
|
||||
export type RxProposalDeposits = {
|
||||
balance: BN,
|
||||
addresses: Array<string>
|
||||
}
|
||||
|
||||
export type RxReferendum = {
|
||||
blockNumber: BN,
|
||||
id: BN,
|
||||
proposal: ExtrinsicDecoded,
|
||||
voteThreshold: number
|
||||
}
|
||||
|
||||
export type RxReferendumVote = {
|
||||
address: string,
|
||||
balance: BN,
|
||||
vote: boolean
|
||||
};
|
||||
|
||||
export type RxBalanceMap = {
|
||||
[index: string]: RxBalance
|
||||
}
|
||||
|
||||
export type KeyWithParams = [SectionItem<Storages>, any];
|
||||
|
||||
export interface ObservableApiInterface {
|
||||
rawCall: <T> ({ name, section }: SectionItem<Interfaces>, ...params: Array<any>) => Observable<T>,
|
||||
rawStorage: <T> (key: SectionItem<Storages>, ...params: Array<any>) => Observable<T>,
|
||||
rawStorageMulti: <T> (...keys: Array<[SectionItem<Storages>, any]>) => Observable<T>,
|
||||
bestNumber: () => Observable<BN | undefined>,
|
||||
chainNewHead: () => Observable<Header | undefined>,
|
||||
democracyLaunchPeriod: () => Observable<BN | undefined>,
|
||||
democracyNextTally: () => Observable<BN | undefined>,
|
||||
democracyProposalCount: () => Observable<number>,
|
||||
democracyProposalDeposits: (index: BN) => Observable<RxProposalDeposits | undefined>,
|
||||
democracyProposals: () => Observable<Array<RxProposal>>,
|
||||
democracyReferendumCount: () => Observable<BN | undefined>,
|
||||
democracyReferendums: () => Observable<Array<RxReferendum>>,
|
||||
democracyReferendumVoters:(index: BN) => Observable<Array<RxReferendumVote>>,
|
||||
democracyVotingPeriod: () => Observable<BN | undefined>,
|
||||
eraBlockLength: () => Observable<BN | undefined>,
|
||||
eraBlockProgress: () => Observable<BN | undefined>,
|
||||
eraBlockRemaining: () => Observable<BN | undefined>,
|
||||
sessionBlockProgress: () => Observable<BN | undefined>,
|
||||
sessionBlockRemaining: () => Observable<BN | undefined>,
|
||||
sessionBrokenPercentLate: () => Observable<BN | undefined>,
|
||||
sessionBrokenValue: () => Observable<BN | undefined>,
|
||||
sessionLength: () => Observable<BN | undefined>,
|
||||
sessionTimeExpected: () => Observable<BN | undefined>,
|
||||
sessionTimeRemaining: () => Observable<BN | undefined>,
|
||||
sessionValidators: () => Observable<Array<string>>,
|
||||
stakingFreeBalanceOf: (address: string) => Observable<BN | undefined>,
|
||||
stakingIntentions: () => Observable<Array<string>>,
|
||||
stakingNominatorsFor: (address: string) => Observable<Array<string>>,
|
||||
stakingNominating: (address: string) => Observable<string | undefined>,
|
||||
stakingReservedBalanceOf: (address: string) => Observable<BN | undefined>,
|
||||
systemAccountIndexOf: (address: string) => Observable<BN | undefined>,
|
||||
timestampBlockPeriod: () => Observable<BN | undefined>,
|
||||
timestampNow: () => Observable<Date | undefined>,
|
||||
validatingBalance: (address: string) => Observable<RxBalance>,
|
||||
validatingBalances: (...addresses: Array<string>) => Observable<RxBalanceMap>,
|
||||
votingBalance: (address: string) => Observable<RxBalance>,
|
||||
votingBalances: (...addresses: Array<string>) => Observable<RxBalance[]>
|
||||
}
|
||||
|
||||
export type ObservableApiNames = keyof ObservableApiInterface;
|
||||
50
packages/ui-react-rx/src/types.d.ts
vendored
50
packages/ui-react-rx/src/types.d.ts
vendored
@ -10,61 +10,13 @@ import { Interfaces } from '@polkadot/jsonrpc/types';
|
||||
import { EncodingVersions, SectionItem } from '@polkadot/params/types';
|
||||
import { Header } from '@polkadot/primitives/header';
|
||||
import { Storages, Storage$Key$Value } from '@polkadot/storage/types';
|
||||
import { ObservableApiInterface } from './ApiObservable/types';
|
||||
|
||||
export type BareProps = {
|
||||
className?: string,
|
||||
style?: { [index: string]: any }
|
||||
};
|
||||
|
||||
export type ExtendedBalance = {
|
||||
address: string,
|
||||
freeBalance: BN,
|
||||
nominatedBalance: BN,
|
||||
reservedBalance: BN,
|
||||
votingBalance: BN,
|
||||
stakingBalance: BN,
|
||||
nominators?: Array<ExtendedBalance>
|
||||
}
|
||||
|
||||
export type ExtendedBalanceMap = {
|
||||
[index: string]: ExtendedBalance
|
||||
}
|
||||
|
||||
export type KeyWithParams = [SectionItem<Storages>, any];
|
||||
|
||||
export interface ObservableApiInterface {
|
||||
rawCall: <T> ({ name, section }: SectionItem<Interfaces>, ...params: Array<any>) => Observable<T>,
|
||||
rawStorage: <T> (key: SectionItem<Storages>, ...params: Array<any>) => Observable<T>,
|
||||
rawStorageMulti: <T> (...keys: Array<[SectionItem<Storages>, any]>) => Observable<T>,
|
||||
bestNumber: () => Observable<BN | undefined>,
|
||||
chainNewHead: () => Observable<Header | undefined>,
|
||||
eraBlockLength: () => Observable<BN | undefined>,
|
||||
eraBlockProgress: () => Observable<BN | undefined>,
|
||||
eraBlockRemaining: () => Observable<BN | undefined>,
|
||||
sessionBlockProgress: () => Observable<BN | undefined>,
|
||||
sessionBlockRemaining: () => Observable<BN | undefined>,
|
||||
sessionBrokenPercentLate: () => Observable<BN | undefined>,
|
||||
sessionBrokenValue: () => Observable<BN | undefined>,
|
||||
sessionLength: () => Observable<BN | undefined>,
|
||||
sessionTimeExpected: () => Observable<BN | undefined>,
|
||||
sessionTimeRemaining: () => Observable<BN | undefined>,
|
||||
sessionValidators: () => Observable<Array<string>>,
|
||||
stakingFreeBalanceOf: (address: string) => Observable<BN | undefined>,
|
||||
stakingIntentions: () => Observable<Array<string>>,
|
||||
stakingNominatorsFor: (address: string) => Observable<Array<string>>,
|
||||
stakingNominating: (address: string) => Observable<string | undefined>,
|
||||
stakingReservedBalanceOf: (address: string) => Observable<BN | undefined>,
|
||||
systemAccountIndexOf: (address: string) => Observable<BN | undefined>,
|
||||
timestampBlockPeriod: () => Observable<BN | undefined>,
|
||||
timestampNow: () => Observable<Date | undefined>,
|
||||
validatingBalance: (address: string) => Observable<ExtendedBalance>,
|
||||
validatingBalances: (...addresses: Array<string>) => Observable<ExtendedBalanceMap>,
|
||||
votingBalance: (address: string) => Observable<ExtendedBalance>,
|
||||
votingBalances: (...addresses: Array<string>) => Observable<ExtendedBalance[]>
|
||||
}
|
||||
|
||||
export type ObservableApiNames = keyof ObservableApiInterface;
|
||||
|
||||
export type ApiProps = {
|
||||
api: RxApiInterface,
|
||||
apiConnected: boolean,
|
||||
|
||||
@ -4,7 +4,8 @@
|
||||
|
||||
// TODO: Lots of duplicated code between this and withObservable, surely there ois a better way of doing this?
|
||||
|
||||
import { RxProps, ObservableApiNames } from '../types';
|
||||
import { ObservableApiNames } from '../ApiObservable/types';
|
||||
import { RxProps } from '../types';
|
||||
import { HOC, Options, DefaultProps, RenderFn } from './types';
|
||||
|
||||
import React from 'react';
|
||||
@ -24,8 +25,6 @@ type State<T> = RxProps<T> & {
|
||||
// FIXME proper types for attributes
|
||||
|
||||
export default function withObservable<T> (observable: ObservableApiNames, { onChange, params = [], paramProp = 'params', propName = observable, transform = echoTransform }: Options<T> = {}): HOC<T> {
|
||||
console.log('observable', observable, paramProp);
|
||||
|
||||
return (Inner: React.ComponentType<any>, defaultProps: DefaultProps<T> = {}, render?: RenderFn): React.ComponentType<any> => {
|
||||
class WithObservable extends React.Component<any, State<T>> {
|
||||
state: State<T>;
|
||||
|
||||
@ -2,7 +2,8 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { BaseProps, ObservableApiNames } from '../types';
|
||||
import { ObservableApiNames } from '../ApiObservable/types';
|
||||
import { BaseProps } from '../types';
|
||||
import { ComponentRenderer, DefaultProps, RenderFn, Options } from './types';
|
||||
|
||||
import Div from '../Div';
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.0.0-beta.51",
|
||||
"@polkadot/extrinsics": "^0.28.9",
|
||||
"@polkadot/extrinsics": "^0.28.11",
|
||||
"@polkadot/ui-app": "^0.19.30",
|
||||
"@polkadot/ui-keyring": "^0.19.30"
|
||||
},
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"paths": {
|
||||
"@polkadot/app-accounts/*": [ "packages/app-accounts/src/*" ],
|
||||
"@polkadot/app-addresses/*": [ "packages/app-addresses/src/*" ],
|
||||
"@polkadot/app-democracy/*": [ "packages/app-democracy/src/*" ],
|
||||
"@polkadot/app-explorer/*": [ "packages/app-explorer/src/*" ],
|
||||
"@polkadot/app-example/*": [ "packages/app-example/src/*" ],
|
||||
"@polkadot/app-extrinsics/*": [ "packages/app-extrinsics/src/*" ],
|
||||
|
||||
125
yarn.lock
125
yarn.lock
@ -765,22 +765,22 @@
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.0.tgz#50c1e2260ac0ed9439a181de3725a0168d59c48a"
|
||||
|
||||
"@polkadot/api-format@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.28.9.tgz#1360e37534d21e871b1bee0d58a0a2ebb99ad753"
|
||||
"@polkadot/api-format@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-format/-/api-format-0.28.11.tgz#7497f36d764016cd715795b6a62de62424d78c5b"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/jsonrpc" "^0.28.9"
|
||||
"@polkadot/primitives" "^0.28.9"
|
||||
"@polkadot/jsonrpc" "^0.28.11"
|
||||
"@polkadot/primitives" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
"@polkadot/util-keyring" "^0.28.1"
|
||||
|
||||
"@polkadot/api-provider@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.28.9.tgz#642cc45d9248a61c7f80969290e19461c8f67047"
|
||||
"@polkadot/api-provider@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-provider/-/api-provider-0.28.11.tgz#3d2ccbb039d84130e828e8a9883d4e5cdee10d99"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/storage" "^0.28.9"
|
||||
"@polkadot/storage" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
"@polkadot/util-crypto" "^0.28.1"
|
||||
"@polkadot/util-keyring" "^0.28.1"
|
||||
@ -789,25 +789,25 @@
|
||||
isomorphic-fetch "^2.2.1"
|
||||
websocket "^1.0.25"
|
||||
|
||||
"@polkadot/api-rx@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.28.9.tgz#5ad6352ce42df7888c37baef40c2acf24e5a7d76"
|
||||
"@polkadot/api-rx@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api-rx/-/api-rx-0.28.11.tgz#5f0a057ea7b160b3242f12f153bff581278c9271"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/api" "^0.28.9"
|
||||
"@polkadot/api-provider" "^0.28.9"
|
||||
"@polkadot/api" "^0.28.11"
|
||||
"@polkadot/api-provider" "^0.28.11"
|
||||
"@types/rx" "^4.1.1"
|
||||
rxjs "^6.2.2"
|
||||
|
||||
"@polkadot/api@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.28.9.tgz#86c2f2db81256ba4d101d37ca18c3fcaa076e0c7"
|
||||
"@polkadot/api@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.28.11.tgz#46b2a7b395dabdc9cb47a769aec3c419a7c2e405"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/api-format" "^0.28.9"
|
||||
"@polkadot/api-provider" "^0.28.9"
|
||||
"@polkadot/jsonrpc" "^0.28.9"
|
||||
"@polkadot/params" "^0.28.9"
|
||||
"@polkadot/api-format" "^0.28.11"
|
||||
"@polkadot/api-provider" "^0.28.11"
|
||||
"@polkadot/jsonrpc" "^0.28.11"
|
||||
"@polkadot/params" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
|
||||
"@polkadot/dev-react@^0.20.12":
|
||||
@ -877,48 +877,48 @@
|
||||
typedoc "^0.11.1"
|
||||
typescript "^2.9.2"
|
||||
|
||||
"@polkadot/extrinsics@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.28.9.tgz#b7804179153c29e793a9d549b566f23a13f98558"
|
||||
"@polkadot/extrinsics@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.28.11.tgz#834c04b58dbdeee9750bdca7a2cc125c2411bb2e"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/params" "^0.28.9"
|
||||
"@polkadot/primitives" "^0.28.9"
|
||||
"@polkadot/params" "^0.28.11"
|
||||
"@polkadot/primitives" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
|
||||
"@polkadot/jsonrpc@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.28.9.tgz#564116660f703084048139c3bda7f01c979e55b4"
|
||||
"@polkadot/jsonrpc@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.28.11.tgz#0687b93077be6ed3dc16f1d8937918ed9647b5e8"
|
||||
dependencies:
|
||||
"@polkadot/params" "^0.28.9"
|
||||
"@polkadot/params" "^0.28.11"
|
||||
babel-runtime "^6.26.0"
|
||||
|
||||
"@polkadot/params@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/params/-/params-0.28.9.tgz#220888b70d147c71f195d06b1e38525c520e04aa"
|
||||
"@polkadot/params@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/params/-/params-0.28.11.tgz#9dea2efa3c6b4725547fd6dd8b3c2312d1d226d7"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/extrinsics" "^0.28.9"
|
||||
"@polkadot/params" "^0.28.9"
|
||||
"@polkadot/primitives" "^0.28.9"
|
||||
"@polkadot/extrinsics" "^0.28.11"
|
||||
"@polkadot/params" "^0.28.11"
|
||||
"@polkadot/primitives" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
"@polkadot/util-keyring" "^0.28.1"
|
||||
|
||||
"@polkadot/primitives@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.28.9.tgz#e451adc1faf78b397f7020f0f036d8542e48aab0"
|
||||
"@polkadot/primitives@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.28.11.tgz#4c32f181a779f002d9def60cecf46237034ef270"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/trie-hash" "^0.28.1"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
|
||||
"@polkadot/storage@^0.28.9":
|
||||
version "0.28.9"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.28.9.tgz#2ac372d64ba1f92310da88476a1be16f92a30443"
|
||||
"@polkadot/storage@^0.28.11":
|
||||
version "0.28.11"
|
||||
resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.28.11.tgz#c388142dcc409fb151512f2c34b6d191656c9bd3"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0-beta.51"
|
||||
"@polkadot/params" "^0.28.9"
|
||||
"@polkadot/primitives" "^0.28.9"
|
||||
"@polkadot/params" "^0.28.11"
|
||||
"@polkadot/primitives" "^0.28.11"
|
||||
"@polkadot/util" "^0.28.1"
|
||||
"@polkadot/util-crypto" "^0.28.1"
|
||||
"@polkadot/util-keyring" "^0.28.1"
|
||||
@ -1021,6 +1021,10 @@
|
||||
dependencies:
|
||||
"@types/base-x" "*"
|
||||
|
||||
"@types/chart.js@^2.7.30":
|
||||
version "2.7.30"
|
||||
resolved "https://registry.yarnpkg.com/@types/chart.js/-/chart.js-2.7.30.tgz#b3a973d4790ff5cbf1352ee756f4bfde5ae1cd27"
|
||||
|
||||
"@types/color-convert@*":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-1.9.0.tgz#bfa8203e41e7c65471e9841d7e306a7cd8b5172d"
|
||||
@ -2862,6 +2866,26 @@ chardet@^0.4.0:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
|
||||
|
||||
chart.js@^2.7.2:
|
||||
version "2.7.2"
|
||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.7.2.tgz#3c9fde4dc5b95608211bdefeda7e5d33dffa5714"
|
||||
dependencies:
|
||||
chartjs-color "^2.1.0"
|
||||
moment "^2.10.2"
|
||||
|
||||
chartjs-color-string@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz#8d3752d8581d86687c35bfe2cb80ac5213ceb8c1"
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
|
||||
chartjs-color@^2.1.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.2.0.tgz#84a2fb755787ed85c39dd6dd8c7b1d88429baeae"
|
||||
dependencies:
|
||||
chartjs-color-string "^0.5.0"
|
||||
color-convert "^0.5.3"
|
||||
|
||||
cheerio@^1.0.0-rc.2:
|
||||
version "1.0.0-rc.2"
|
||||
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db"
|
||||
@ -3092,6 +3116,10 @@ collection-visit@^1.0.0:
|
||||
map-visit "^1.0.0"
|
||||
object-visit "^1.0.0"
|
||||
|
||||
color-convert@^0.5.3:
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
|
||||
|
||||
color-convert@^1.3.0, color-convert@^1.8.2, color-convert@^1.9.0, color-convert@^1.9.1:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147"
|
||||
@ -7570,7 +7598,7 @@ modify-values@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
|
||||
|
||||
moment@^2.22.2, moment@^2.6.0:
|
||||
moment@^2.10.2, moment@^2.22.2, moment@^2.6.0:
|
||||
version "2.22.2"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
|
||||
|
||||
@ -9225,6 +9253,13 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-chartjs-2@^2.7.4:
|
||||
version "2.7.4"
|
||||
resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-2.7.4.tgz#e41ea4e81491dc78347111126a48e96ee57db1a6"
|
||||
dependencies:
|
||||
lodash "^4.17.4"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-copy-to-clipboard@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user