Split parachain proposals (#4423)
This commit is contained in:
parent
b2278488ad
commit
dd994a67be
@ -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} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
38
packages/page-parachains/src/Proposals/Actions.tsx
Normal file
38
packages/page-parachains/src/Proposals/Actions.tsx
Normal 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);
|
||||
@ -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[];
|
||||
@ -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';
|
||||
|
||||
25
packages/page-parachains/src/Proposals/index.tsx
Normal file
25
packages/page-parachains/src/Proposals/index.tsx
Normal 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);
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
}
|
||||
`);
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user