parent
1c615f40b3
commit
4b0335533a
@ -21,7 +21,7 @@ function Actions (): React.ReactElement<Props> {
|
||||
return (
|
||||
<>
|
||||
<Button.Group>
|
||||
{api.query.proposeParachains && (
|
||||
{api.query.proposeParachain && (
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={true}
|
||||
|
||||
@ -5,10 +5,12 @@ import type { ProposalExt } from './types';
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { AddressMini, AddressSmall, Badge } from '@polkadot/react-components';
|
||||
import { AddressMini, AddressSmall, Badge, TxButton } from '@polkadot/react-components';
|
||||
import { useApi, useSudo } from '@polkadot/react-hooks';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
import { sliceHex } from './util';
|
||||
|
||||
interface Props {
|
||||
@ -16,6 +18,10 @@ interface Props {
|
||||
}
|
||||
|
||||
function Proposal ({ proposal: { id, isApproved, proposal: { balance, genesisHead, name, proposer, validationCode, validators } } }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const { hasSudoKey, sudoKey } = useSudo();
|
||||
|
||||
const initialHex = useMemo(
|
||||
() => sliceHex(genesisHead, 8),
|
||||
[genesisHead]
|
||||
@ -48,6 +54,18 @@ function Proposal ({ proposal: { id, isApproved, proposal: { balance, genesisHea
|
||||
value={validatorId}
|
||||
/>
|
||||
))}</td>
|
||||
<td className='button'>
|
||||
{!isApproved && (
|
||||
<TxButton
|
||||
accountId={sudoKey}
|
||||
icon='check'
|
||||
isDisabled={!hasSudoKey}
|
||||
label={t<string>('Approve')}
|
||||
params={[id]}
|
||||
tx={api.tx.proposeParachain?.approveProposal}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
@ -24,7 +24,8 @@ function Proposals ({ proposals }: Props): React.ReactElement<Props> {
|
||||
[t('balance')],
|
||||
[t('initial state'), 'start'],
|
||||
[t('validation'), 'start'],
|
||||
[t('validators'), 'address']
|
||||
[t('validators'), 'address'],
|
||||
[]
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { Option } from '@polkadot/types';
|
||||
import type { ParachainProposal, ParaId } from '@polkadot/types/interfaces';
|
||||
import type { EventRecord, ParachainProposal, ParaId } from '@polkadot/types/interfaces';
|
||||
import type { ProposalExt } from './types';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
@ -23,16 +23,28 @@ export default function useProposals (): ProposalExt[] | undefined {
|
||||
const { api } = useApi();
|
||||
const mountedRef = useIsMountedRef();
|
||||
const [state, setState] = useState<ProposalExt[] | undefined>();
|
||||
const approvedIds = useCall<ParaId[]>(api.query.proposeParachains?.approvedProposals);
|
||||
const [trigger, setTrigger] = useState(Date.now());
|
||||
const approvedIds = useCall<ParaId[]>(api.query.proposeParachain?.approvedProposals);
|
||||
const events = useCall<EventRecord[]>(api.query.system.events);
|
||||
|
||||
// trigger on any proposeParachain events
|
||||
useEffect((): void => {
|
||||
approvedIds && api.query.proposeParachain.proposals
|
||||
mountedRef.current && events && setTrigger((trigger) =>
|
||||
events.filter(({ event: { section }, phase }) => phase.isApplyExtrinsic && section === 'proposeParachain').length
|
||||
? Date.now()
|
||||
: trigger
|
||||
);
|
||||
}, [events, mountedRef]);
|
||||
|
||||
// re-get all our entries in the list
|
||||
useEffect((): void => {
|
||||
approvedIds && trigger && api.query.proposeParachain.proposals
|
||||
.entries()
|
||||
.then((entries) =>
|
||||
mountedRef.current && setState(createExt(approvedIds, entries as any))
|
||||
)
|
||||
.catch(console.error);
|
||||
}, [api, approvedIds, mountedRef]);
|
||||
}, [api, approvedIds, mountedRef, trigger]);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ import { useTranslation } from './translate';
|
||||
|
||||
function SudoApp ({ basePath }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts, isMine, sudoKey } = useSudo();
|
||||
const { allAccounts, hasSudoKey, sudoKey } = useSudo();
|
||||
|
||||
const itemsRef = useRef([
|
||||
{
|
||||
@ -37,20 +37,20 @@ function SudoApp ({ basePath }: Props): React.ReactElement<Props> {
|
||||
items={itemsRef.current}
|
||||
/>
|
||||
</header>
|
||||
{isMine
|
||||
{hasSudoKey
|
||||
? (
|
||||
<Switch>
|
||||
<Route path={`${basePath}/key`}>
|
||||
<SetKey
|
||||
allAccounts={allAccounts}
|
||||
isMine={isMine}
|
||||
isMine={hasSudoKey}
|
||||
sudoKey={sudoKey}
|
||||
/>
|
||||
</Route>
|
||||
<Route>
|
||||
<Sudo
|
||||
allAccounts={allAccounts}
|
||||
isMine={isMine}
|
||||
isMine={hasSudoKey}
|
||||
sudoKey={sudoKey}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
@ -74,8 +74,8 @@ export interface TxState extends ExtrinsicAndSenders {
|
||||
|
||||
export interface UseSudo {
|
||||
allAccounts: string[];
|
||||
hasSudoKey: boolean;
|
||||
sudoKey?: string;
|
||||
isMine: boolean;
|
||||
}
|
||||
|
||||
export interface AddressFlags extends DeriveAccountFlags {
|
||||
|
||||
@ -18,11 +18,11 @@ export function useSudo (): UseSudo {
|
||||
const { api } = useApi();
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const sudoKey = useCall<string>(hasAccounts && api.query.sudo?.key, undefined, transformSudo);
|
||||
const [isMine, setIsMine] = useState(false);
|
||||
const [hasSudoKey, setHasSudoKey] = useState(false);
|
||||
|
||||
useEffect((): void => {
|
||||
setIsMine(!!sudoKey && !!allAccounts && allAccounts.some((key) => key === sudoKey));
|
||||
setHasSudoKey(!!sudoKey && !!allAccounts && allAccounts.some((key) => key === sudoKey));
|
||||
}, [allAccounts, sudoKey]);
|
||||
|
||||
return { allAccounts, isMine, sudoKey };
|
||||
return { allAccounts, hasSudoKey, sudoKey };
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user