Group by track (#8152)

* Group by track

* OCD

* Move trackName extraction

* Adjust empty message
This commit is contained in:
Jaco 2022-09-21 13:58:32 +03:00 committed by GitHub
parent 95027e8fca
commit 5a3680dfe9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 108 additions and 61 deletions

View File

@ -7,6 +7,7 @@ import type { BN } from '@polkadot/util';
import type { PalletReferenda } from '../../types';
import React, { useMemo } from 'react';
import styled from 'styled-components';
import { AddressMini } from '@polkadot/react-components';
@ -16,6 +17,7 @@ import Refund from './Refund';
interface Props {
canDeposit?: boolean;
canRefund?: boolean;
className?: string;
decision: Option<PalletReferendaDeposit> | null;
id: BN;
palletReferenda: PalletReferenda;
@ -23,14 +25,14 @@ interface Props {
track?: PalletReferendaTrackInfo;
}
function Deposits ({ canDeposit, canRefund, decision, id, palletReferenda, submit, track }: Props): React.ReactElement<Props> {
function Deposits ({ canDeposit, canRefund, className = '', decision, id, palletReferenda, submit, track }: Props): React.ReactElement<Props> {
const [valSubmit, valDeposit] = useMemo(
() => [submit, decision && decision.unwrapOr(null)],
[decision, submit]
);
return (
<td className='address'>
<td className={`${className} address`}>
{valSubmit && (
<AddressMini
balance={valSubmit.amount}
@ -65,4 +67,8 @@ function Deposits ({ canDeposit, canRefund, decision, id, palletReferenda, submi
);
}
export default React.memo(Deposits);
export default React.memo(styled(Deposits)`
.ui--AddressMini+.ui--Button {
margin-top: 0.25rem;
}
`);

View File

@ -10,7 +10,6 @@ import { formatNumber } from '@polkadot/util';
import Killed from './RefKilled';
import Ongoing from './RefOngoing';
import Tuple from './RefTuple';
import { getTrackName } from './util';
const Components: Record<string, React.ComponentType<Props>> = {
Killed,
@ -18,26 +17,18 @@ const Components: Record<string, React.ComponentType<Props>> = {
};
function Referendum (props: Props): React.ReactElement<Props> {
const { className, value: { id, info, track } } = props;
const { className, value: { id, info } } = props;
const Component = useMemo(
() => Components[info.type] || Tuple,
[info]
);
const trackName = useMemo(
() => track && getTrackName(track),
[track]
);
return (
<tr className={className}>
<td className='number'>
<h1>{formatNumber(id)}</h1>
</td>
<td className='number'>
{trackName}
</td>
{/* <td>
<textarea
rows={8}

View File

@ -19,7 +19,7 @@ import { getTypeDef } from '@polkadot/types/create';
import { formatNumber, isHex } from '@polkadot/util';
import { useTranslation } from '../translate';
import { getTrackName } from './util';
import { getTrackName } from '../util';
interface Props {
className?: string;

View File

@ -1,9 +1,9 @@
// Copyright 2017-2022 @polkadot/app-referenda authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { PalletReferenda, PalletVote } from '../types';
import type { PalletReferenda, PalletVote, ReferendaGroup } from '../types';
import React, { useMemo, useRef } from 'react';
import React, { useMemo } from 'react';
import AddPreimage from '@polkadot/app-preimages/Preimages/Add';
import { Button, Table } from '@polkadot/react-components';
@ -28,19 +28,14 @@ interface Props {
function Referenda ({ className, members, palletReferenda, palletVote }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { allAccounts } = useAccounts();
const [referenda, tracks] = useReferenda(palletReferenda);
const summary = useSummary(palletReferenda, referenda);
const [grouped, tracks] = useReferenda(palletReferenda);
const summary = useSummary(palletReferenda, grouped);
const isMember = useMemo(
() => !members || allAccounts.some((a) => members.includes(a)),
[allAccounts, members]
);
const headerRef = useRef([
[t('referenda'), 'start', 2],
[undefined, undefined, 3]
]);
return (
<div className={className}>
<Summary summary={summary} />
@ -53,22 +48,31 @@ function Referenda ({ className, members, palletReferenda, palletVote }: Props):
tracks={tracks}
/>
</Button.Group>
<Table
className={className}
empty={referenda && t<string>('No referendums found')}
header={headerRef.current}
>
{referenda && referenda.map((r) => (
<Referendum
isMember={isMember}
key={r.key}
members={members}
palletReferenda={palletReferenda}
palletVote={palletVote}
value={r}
/>
))}
</Table>
{grouped.map(({ referenda, trackName }: ReferendaGroup) => (
<Table
empty={referenda && t<string>('No active referenda')}
header={[
[trackName || t('referenda'), 'start', 2],
[undefined, undefined, 3]
]}
key={
trackName
? `track:${trackName}`
: 'untracked'
}
>
{referenda && referenda.map((r) => (
<Referendum
isMember={isMember}
key={r.key}
members={members}
palletReferenda={palletReferenda}
palletVote={palletVote}
value={r}
/>
))}
</Table>
))}
</div>
);
}

View File

@ -8,6 +8,12 @@ export type PalletReferenda = 'referenda' | 'rankedPolls' | 'fellowshipReferenda
export type PalletVote = 'convictionVoting' | 'rankedCollective' | 'fellowshipCollective';
export interface ReferendaGroup {
track?: PalletReferendaTrackInfo;
trackName?: string;
referenda?: Referendum[];
}
export interface Referendum {
id: BN;
info: PalletReferendaReferendumInfoConvictionVotingTally | PalletReferendaReferendumInfoRankedCollectiveTally;

View File

@ -10,11 +10,13 @@ import { createNamedHook } from '@polkadot/react-hooks';
import useReferenda from './useReferenda';
export function useCounterNamed (palletReferenda: PalletReferenda): number {
const [referanda] = useReferenda(palletReferenda);
const [grouped] = useReferenda(palletReferenda);
return useMemo(
() => (referanda && referanda.filter(({ info }) => info.isOngoing).length) || 0,
[referanda]
() => grouped
? grouped.reduce((total, { referenda }) => total + (referenda ? referenda.filter(({ info }) => info.isOngoing).length : 0), 0)
: 0,
[grouped]
);
}

View File

@ -4,7 +4,7 @@
import type { Option } from '@polkadot/types';
import type { PalletReferendaReferendumInfoConvictionVotingTally, PalletReferendaReferendumInfoRankedCollectiveTally, PalletReferendaTrackInfo } from '@polkadot/types/lookup';
import type { BN } from '@polkadot/util';
import type { PalletReferenda, Referendum } from './types';
import type { PalletReferenda, ReferendaGroup, Referendum } from './types';
import { useMemo } from 'react';
@ -12,6 +12,7 @@ import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
import useReferendaIds from './useReferendaIds';
import useTracks from './useTracks';
import { getTrackName } from './util';
const ORDER = <const> ['Ongoing', 'Approved', 'Rejected', 'Cancelled', 'Killed', 'TimedOut'];
@ -52,20 +53,57 @@ const OPT_MULTI = {
info,
isConvictionVote: isConvictionVote(info),
key: id.toString()
}))
.sort((a, b) =>
a.info.isOngoing === b.info.isOngoing
? a.info.isOngoing
? sortOngoing(a, b)
: sortOther(a, b)
: a.info.isOngoing
? -1
: 1
),
})),
withParamsTransform: true
};
function getResult (referenda?: Referendum[], tracks?: [BN, PalletReferendaTrackInfo][]): Referendum[] | undefined {
function groupReferenda (referenda?: Referendum[]): ReferendaGroup[] {
if (!referenda) {
return [{}];
}
const grouped: ReferendaGroup[] = [];
const other: ReferendaGroup = { referenda: [] };
for (let i = 0; i < referenda.length; i++) {
const ref = referenda[i];
let group: ReferendaGroup | undefined = other;
if (ref.track) {
group = grouped.find(({ track }) => ref.track === track);
if (!group) {
group = { referenda: [], track: ref.track, trackName: getTrackName(ref.track) };
grouped.push(group);
}
}
group.referenda && group.referenda.push(ref);
}
if ((other.referenda && other.referenda.length !== 0) || !grouped.length) {
grouped.push(other);
}
for (let i = 0; i < grouped.length; i++) {
const group = grouped[i];
group.referenda && group.referenda.sort((a, b) =>
a.info.isOngoing === b.info.isOngoing
? a.info.isOngoing
? sortOngoing(a, b)
: sortOther(a, b)
: a.info.isOngoing
? -1
: 1
);
}
return grouped;
}
function getResult (referenda?: Referendum[], tracks?: [BN, PalletReferendaTrackInfo][]): ReferendaGroup[] {
if (tracks && referenda) {
for (let i = 0; i < referenda.length; i++) {
if (referenda[i].info.isOngoing) {
@ -78,10 +116,10 @@ function getResult (referenda?: Referendum[], tracks?: [BN, PalletReferendaTrack
}
}
return referenda;
return groupReferenda(referenda);
}
function useReferendaImpl (palletReferenda: PalletReferenda): [Referendum[] | undefined, [BN, PalletReferendaTrackInfo][] | undefined] {
function useReferendaImpl (palletReferenda: PalletReferenda): [ReferendaGroup[], [BN, PalletReferendaTrackInfo][] | undefined] {
const { api, isApiReady } = useApi();
const ids = useReferendaIds(palletReferenda);
const tracks = useTracks(palletReferenda);
@ -90,7 +128,7 @@ function useReferendaImpl (palletReferenda: PalletReferenda): [Referendum[] | un
return useMemo(
() => [
(ids && ids.length === 0)
? []
? [{ referenda: [] }]
: getResult(referenda, tracks),
tracks
],

View File

@ -2,19 +2,19 @@
// SPDX-License-Identifier: Apache-2.0
import type { u32 } from '@polkadot/types';
import type { PalletReferenda, Referendum, Summary } from './types';
import type { PalletReferenda, ReferendaGroup, Summary } from './types';
import { useMemo } from 'react';
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
// TODO keep track of all tracks to get the number of deciding
function useSummaryImpl (palletReferenda: PalletReferenda, referenda?: Referendum[] | undefined): Summary {
function useSummaryImpl (palletReferenda: PalletReferenda, grouped?: ReferendaGroup[] | undefined): Summary {
const { api } = useApi();
const refCount = useCall<u32>(api.query[palletReferenda].referendumCount);
const refActive = useMemo(
() => referenda && referenda.length,
[referenda]
() => grouped && grouped.reduce((total, { referenda }) => total + (referenda ? referenda.length : 0), 0),
[grouped]
);
return useMemo(