Split parachain proposals (#4423)

This commit is contained in:
Jaco Greeff 2021-01-15 11:07:22 +01:00 committed by GitHub
parent b2278488ad
commit dd994a67be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 109 additions and 65 deletions

View File

@ -4,36 +4,16 @@
import React from 'react';
import { Button } from '@polkadot/react-components';
import { useAccounts, useApi, useToggle } from '@polkadot/react-hooks';
import Propose from '../modals/Propose';
import { useTranslation } from '../translate';
interface Props {
className?: string;
}
function Actions (): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { hasAccounts } = useAccounts();
const [showPropose, togglePropose] = useToggle();
return (
<>
<Button.Group>
{api.query.proposeParachain && (
<Button
icon='plus'
isDisabled={!hasAccounts}
label={t<string>('Propose')}
onClick={togglePropose}
/>
)}
</Button.Group>
{showPropose && (
<Propose onClose={togglePropose} />
)}
</>
);
}

View File

@ -13,7 +13,7 @@ import { useApi, useCall, useCallMulti, useParaApi } from '@polkadot/react-hooks
import { BlockToTime, FormatBalance } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
import { sliceHex } from './util';
import { sliceHex } from '../util';
interface Props {
bestNumber?: BN;

View File

@ -10,7 +10,7 @@ import { useApi, useCall } from '@polkadot/react-hooks';
import { formatNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
import { sliceHex } from './util';
import { sliceHex } from '../util';
interface Props {
id: ParaId;

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { ParaId } from '@polkadot/types/interfaces';
import type { Proposals } from '../types';
import React from 'react';
@ -9,23 +10,21 @@ import { useApi, useCall } from '@polkadot/react-hooks';
import Actions from './Actions';
import Parachains from './ParachainList';
import Proposals from './Proposals';
import Summary from './Summary';
import Upcoming from './UpcomingList';
import useProposals from './useProposals';
interface Props {
className?: string;
proposals?: Proposals;
}
function Overview (): React.ReactElement<Props> {
function Overview ({ className, proposals }: Props): React.ReactElement<Props> {
const { api } = useApi();
const paraIds = useCall<ParaId[]>(api.query.paras?.parachains);
const upcomingIds = useCall<ParaId[]>(api.query.paras?.upcomingParas);
const proposals = useProposals();
return (
<>
<div className={className}>
<Summary
parachainCount={paraIds?.length}
proposalCount={proposals?.proposalIds.length}
@ -38,10 +37,7 @@ function Overview (): React.ReactElement<Props> {
<Upcoming ids={upcomingIds} />
</>
)}
{api.query.proposeParachain && (
<Proposals proposals={proposals} />
)}
</>
</div>
);
}

View File

@ -0,0 +1,38 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import React from 'react';
import { Button } from '@polkadot/react-components';
import { useAccounts, useToggle } from '@polkadot/react-hooks';
import Propose from '../modals/Propose';
import { useTranslation } from '../translate';
interface Props {
className?: string;
}
function Actions (): React.ReactElement<Props> {
const { t } = useTranslation();
const { hasAccounts } = useAccounts();
const [showPropose, togglePropose] = useToggle();
return (
<>
<Button.Group>
<Button
icon='plus'
isDisabled={!hasAccounts}
label={t<string>('Propose')}
onClick={togglePropose}
/>
</Button.Group>
{showPropose && (
<Propose onClose={togglePropose} />
)}
</>
);
}
export default React.memo(Actions);

View File

@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
import type { ParaId } from '@polkadot/types/interfaces';
import type { ScheduledProposals } from './types';
import type { ScheduledProposals } from '../types';
import React, { useMemo } from 'react';
@ -12,8 +12,8 @@ import { FormatBalance } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
import { useTranslation } from '../translate';
import { sliceHex } from '../util';
import { useProposal } from './useProposals';
import { sliceHex } from './util';
interface Props {
approvedIds: ParaId[];

View File

@ -1,7 +1,7 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Proposals as UseProposals } from './types';
import type { Proposals as UseProposals } from '../types';
import React, { useRef } from 'react';

View File

@ -0,0 +1,25 @@
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Proposals } from '../types';
import React from 'react';
import Actions from './Actions';
import ProposalList from './Proposals';
interface Props {
className?: string;
proposals?: Proposals;
}
function ProposalsTab ({ className, proposals }: Props): React.ReactElement<Props> {
return (
<div className={className}>
<Actions />
<ProposalList proposals={proposals} />
</div>
);
}
export default React.memo(ProposalsTab);

View File

@ -3,7 +3,7 @@
import type { Option } from '@polkadot/types';
import type { EventRecord, ParachainProposal, ParaId, SessionIndex } from '@polkadot/types/interfaces';
import type { ProposalExt, Proposals, ScheduledProposals } from './types';
import type { ProposalExt, Proposals, ScheduledProposals } from '../types';
import { useEffect, useMemo, useState } from 'react';

View File

@ -3,43 +3,63 @@
import React, { useMemo } from 'react';
import { Route, Switch } from 'react-router';
import { useLocation } from 'react-router-dom';
import styled from 'styled-components';
import { Tabs } from '@polkadot/react-components';
import { useApi } from '@polkadot/react-hooks';
import useProposals from './Proposals/useProposals';
import Overview from './Overview';
import Proposals from './Proposals';
import { useTranslation } from './translate';
interface Props {
basePath: string;
className?: string;
}
function ParachainsApp ({ basePath }: Props): React.ReactElement<Props> {
function ParachainsApp ({ basePath, className }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const { pathname } = useLocation();
const proposals = useProposals();
const items = useMemo(() => [
{
isRoot: true,
name: 'overview',
text: t<string>('Parachains overview')
},
api.query.proposeParachain && {
name: 'proposals',
text: t<string>('Proposals')
}
], [t]);
].filter((q): q is { name: string; text: string } => !!q), [api, t]);
return (
<main>
<main className={className}>
<header>
<Tabs
basePath={basePath}
isSequence
items={items}
/>
</header>
<Switch>
<Route>
<Overview />
<Route path={`${basePath}/proposals`}>
<Proposals proposals={proposals} />
</Route>
</Switch>
<Overview
className={basePath === pathname ? '' : 'parachains--hidden'}
proposals={proposals}
/>
</main>
);
}
export default React.memo(ParachainsApp);
export default React.memo(styled(ParachainsApp)`
.parachains--hidden {
display: none;
}
`);

View File

@ -13,7 +13,6 @@ import styled from 'styled-components';
import { HelpOverlay } from '@polkadot/react-components';
import Tabs from '@polkadot/react-components/Tabs';
import { useAccounts, useApi, useAvailableSlashes, useCall, useFavorites, useOwnStashInfos } from '@polkadot/react-hooks';
import { isFunction } from '@polkadot/util';
import basicMd from './md/basic.md';
import Summary from './Overview/Summary';
@ -71,12 +70,10 @@ function StakingApp ({ basePath, className = '' }: Props): React.ReactElement<Pr
name: 'actions',
text: t<string>('Account actions')
},
isFunction(api.query.staking.activeEra)
? {
name: 'payout',
text: t<string>('Payouts')
}
: null,
api.query.staking.activeEra && {
name: 'payout',
text: t<string>('Payouts')
},
{
alias: 'returns',
name: 'targets',

View File

@ -9,25 +9,22 @@ import { NavLink } from 'react-router-dom';
import styled from 'styled-components';
import Badge from '../Badge';
import Icon from '../Icon';
interface Props extends TabItem {
basePath: string;
className?: string;
count?: number;
index: number;
isSequence?: boolean;
num: number;
}
function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRoot, isSequence, name, num, text }: Props): React.ReactElement<Props> {
function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRoot, name, text }: Props): React.ReactElement<Props> {
const to = isRoot
? basePath
: `${basePath}/${name}`;
// only do exact matching when not the fallback (first position tab),
// params are problematic for dynamic hidden such as app-accounts
const tabIsExact = isExact || !hasParams || (!isSequence && index === 0);
const tabIsExact = isExact || !hasParams || index === 0;
return (
<NavLink
@ -37,13 +34,7 @@ function Tab ({ basePath, className = '', count, hasParams, index, isExact, isRo
strict={tabIsExact}
to={to}
>
{text}{(isSequence && index < (num - 1)) && (
<Icon
className='tabIcon'
icon='arrow-right'
/>
)}
{!!count && (
{text}{!!count && (
<Badge
className='tabCounter'
color='counter'

View File

@ -15,10 +15,9 @@ interface Props {
basePath: string;
hidden?: (string | boolean | undefined)[];
items: TabItem[];
isSequence?: boolean;
}
function Tabs ({ basePath, className = '', hidden, isSequence, items }: Props): React.ReactElement<Props> {
function Tabs ({ basePath, className = '', hidden, items }: Props): React.ReactElement<Props> {
const location = useLocation();
// redirect on invalid tabs
@ -50,9 +49,7 @@ function Tabs ({ basePath, className = '', hidden, isSequence, items }: Props):
{...tab}
basePath={basePath}
index={index}
isSequence={isSequence}
key={tab.name}
num={filtered.length}
/>
))}
</div>