Swap referendum pass/fail to Tag (#2448)

This commit is contained in:
Jaco Greeff 2020-03-24 08:27:15 +01:00 committed by GitHub
parent 51852e7834
commit f309743b2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 46 deletions

View File

@ -7,9 +7,8 @@ import { ActionStatus } from '@polkadot/react-components/Status/types';
import { RecoveryConfig } from '@polkadot/types/interfaces';
import React, { useCallback, useState, useEffect } from 'react';
import { Label } from 'semantic-ui-react';
import styled from 'styled-components';
import { AddressInfo, AddressSmall, Badge, Button, ChainLock, Forget, Icon, IdentityIcon, InputTags, LinkExternal, Menu, Popup, Input } from '@polkadot/react-components';
import { AddressInfo, AddressSmall, Badge, Button, ChainLock, Forget, Icon, IdentityIcon, Input, InputTags, LinkExternal, Menu, Popup, Tag } from '@polkadot/react-components';
import { useApi, useCall, useToggle } from '@polkadot/react-hooks';
import { Option } from '@polkadot/types';
import keyring from '@polkadot/ui-keyring';
@ -309,7 +308,7 @@ function Account ({ address, className, filter, isFavorite, toggleFavorite }: Pr
<div className='tags--toggle' onClick={toggleEditTags}>
{tags.length
? tags.map((tag): React.ReactNode => (
<Label key={tag} size='tiny' color='grey'>{tag}</Label>
<Tag key={tag} label={tag} />
))
: <label>{t('no tags')}</label>
}

View File

@ -7,9 +7,8 @@ import { KeyringAddress } from '@polkadot/ui-keyring/types';
import { ActionStatus } from '@polkadot/react-components/Status/types';
import React, { useEffect, useState } from 'react';
import { Label } from 'semantic-ui-react';
import styled from 'styled-components';
import { AddressSmall, AddressInfo, Button, ChainLock, Icon, InputTags, Input, LinkExternal, Forget, Menu, Popup } from '@polkadot/react-components';
import { AddressSmall, AddressInfo, Button, ChainLock, Icon, InputTags, Input, LinkExternal, Forget, Menu, Popup, Tag } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import keyring from '@polkadot/ui-keyring';
import Transfer from '@polkadot/app-accounts/modals/Transfer';
@ -222,7 +221,7 @@ function Address ({ address, className, filter, isFavorite, toggleFavorite }: Pr
<div className='tags--toggle' onClick={_toggleEditTags}>
{tags.length
? tags.map((tag): React.ReactNode => (
<Label key={tag} size='tiny' color='grey'>{tag}</Label>
<Tag key={tag} label={tag} />
))
: <label>{t('no tags')}</label>
}

View File

@ -7,7 +7,7 @@ import { BlockNumber } from '@polkadot/types/interfaces';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { AddressMini, Badge, Button, Expander, Icon, LinkExternal } from '@polkadot/react-components';
import { AddressMini, Button, Expander, LinkExternal, Tag } from '@polkadot/react-components';
import { useApi, useCall } from '@polkadot/react-hooks';
import { FormatBalance, BlockToTime } from '@polkadot/react-query';
import { formatNumber, isBoolean } from '@polkadot/util';
@ -84,12 +84,10 @@ function Referendum ({ className, value }: Props): React.ReactElement<Props> | n
</td>
<td className='padtop top'>
{isBoolean(isPassing) && (
<Badge
<Tag
color={isPassing ? 'green' : 'red'}
hover={isPassing ? t('{{threshold}}, passing', { replace: { threshold } }) : t('{{threshold}}, not passing', { replace: { threshold } })}
info={<Icon name={isPassing ? 'check' : 'cancel'} />}
isInline
isTooltip
type={isPassing ? 'green' : 'brown'}
label={isPassing ? t('passing') : t('failing')}
/>
)}
</td>

View File

@ -46,17 +46,11 @@ function newtonIteration (n: BN, x0: BN): BN {
return newtonIteration(n, x1);
}
// https://golb.hplar.ch/2018/09/javascript-bigint.html
function sqrt (value: BN): BN {
if (value.ltn(0)) {
throw new Error('square root of negative numbers is not supported');
}
if (value.ltn(2)) {
return value;
}
return newtonIteration(value, new BN(1));
// TODO Replace with bnSqrt from @polkadot/util once that hits 2.7
function bnSqrt (value: BN): BN {
return value.ltn(2)
? value
: newtonIteration(value, new BN(1));
}
export default function useIsPassing (referendum: DerivedReferendum): boolean | undefined {
@ -65,26 +59,22 @@ export default function useIsPassing (referendum: DerivedReferendum): boolean |
const [isPassing, setIsPassing] = useState<boolean | undefined>(undefined);
useEffect((): void => {
try {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const { tally, threshold } = (referendum.status as ReferendumStatus);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const { tally, threshold } = (referendum.status as ReferendumStatus);
if (totalIssuance && tally) {
const sqrtVoters = sqrt(tally.turnout);
const sqrtElectorate = sqrt(totalIssuance);
if (totalIssuance && tally) {
const sqrtVoters = bnSqrt(tally.turnout);
const sqrtElectorate = bnSqrt(totalIssuance);
setIsPassing(
sqrtVoters.isZero()
? false
: threshold.isSimplemajority
? tally.ayes.gt(tally.nays)
: threshold.isSupermajorityapproval
? compareRationals(tally.nays, sqrtVoters, tally.ayes, sqrtElectorate)
: compareRationals(tally.nays, sqrtElectorate, tally.ayes, sqrtVoters)
);
}
} catch (error) {
console.error(error);
setIsPassing(
sqrtVoters.isZero()
? false
: threshold.isSimplemajority
? tally.ayes.gt(tally.nays)
: threshold.isSupermajorityapproval
? compareRationals(tally.nays, sqrtVoters, tally.ayes, sqrtElectorate)
: compareRationals(tally.nays, sqrtElectorate, tally.ayes, sqrtVoters)
);
}
}, [referendum, totalIssuance]);

View File

@ -22,12 +22,12 @@ interface Props {
let badgeId = 0;
function Badge ({ className, hover, info, isGray, isInline, isSmall, isTooltip, onClick, type }: Props): React.ReactElement<Props> | null {
const [key] = useState(`${Date.now()}-${badgeId++}`);
const [trigger] = useState(`badge-hover-${Date.now()}-${badgeId++}`);
return (
<div
className={`ui--Badge ${isGray && 'isGray'} ${isInline && 'isInline'} ${isTooltip && 'isTooltip'} ${isSmall && 'isSmall'} ${onClick && 'isClickable'} ${type} ${className}`}
data-for={`badge-status-${key}`}
data-for={trigger}
data-tip={true}
data-tip-disable={!isTooltip}
onClick={onClick}
@ -40,7 +40,7 @@ function Badge ({ className, hover, info, isGray, isInline, isSmall, isTooltip,
</div>
{hover && (
<Tooltip
trigger={`badge-status-${key}`}
trigger={trigger}
text={hover}
/>
)}

View File

@ -5,7 +5,6 @@
import { DeriveAccountInfo } from '@polkadot/api-derive/types';
import { KeyringItemType } from '@polkadot/ui-keyring/types';
import { Label } from 'semantic-ui-react';
import React from 'react';
import Button from './Button';
@ -13,6 +12,7 @@ import { classes, toShortAddress } from './util';
import CopyButton from './CopyButton';
import Input from './Input';
import InputTags from './InputTags';
import Tag from './Tag';
export const styles = `
text-align: left;
@ -354,7 +354,7 @@ export default class Row<P extends RowProps, S extends RowState> extends React.P
!tags.length
? (isEditable ? <span className='addTags'>add tags</span> : undefined)
: tags.map((tag): React.ReactNode => (
<Label key={tag} size='tiny' color='grey'>{tag}</Label>
<Tag key={tag} label={tag} />
))
}
{isEditable && this.renderEditIcon()}

View File

@ -0,0 +1,42 @@
// Copyright 2017-2020 @polkadot/react-components authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import React, { useState } from 'react';
import { Label } from 'semantic-ui-react';
import Tooltip from './Tooltip';
interface Props {
className?: string;
color?: 'green' | 'grey' | 'red';
hover?: React.ReactNode;
label: React.ReactNode;
}
let tagId = 0;
function Tag ({ className, color, hover, label }: Props): React.ReactElement<Props> {
const [trigger] = useState(`tag-hover-${Date.now()}-${tagId++}`);
return (
<Label
className={className}
color={color || 'grey'}
data-for={trigger}
data-tip={true}
size='small'
tag
>
{label}
{hover && (
<Tooltip
trigger={trigger}
text={hover}
/>
)}
</Label>
);
}
export default React.memo(Tag);

View File

@ -77,6 +77,7 @@ export { default as Status, StatusContext } from './Status';
export { default as SummaryBox } from './SummaryBox';
export { default as Table } from './Table';
export { default as Tabs } from './Tabs';
export { default as Tag } from './Tag';
export { default as Toggle } from './Toggle';
export { default as Tooltip } from './Tooltip';
export { default as TxButton } from './TxButton';