Parachains registration (#4318)
* Parachains registration * Registrar dialog
This commit is contained in:
parent
26f592cf5e
commit
c5bf0de631
38
packages/page-parachains/src/Overview/Actions.tsx
Normal file
38
packages/page-parachains/src/Overview/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 { useApi, useToggle } from '@polkadot/react-hooks';
|
||||
|
||||
import Register from '../modals/Register';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
canRegister?: boolean;
|
||||
}
|
||||
|
||||
function Actions ({ canRegister }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [showRegister, toggleRegister] = useToggle();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button.Group>
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!canRegister || !api.tx.registrar?.registerParathread}
|
||||
label={t<string>('Register')}
|
||||
onClick={toggleRegister}
|
||||
/>
|
||||
</Button.Group>
|
||||
{showRegister && (
|
||||
<Register onClose={toggleRegister} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Actions);
|
||||
@ -12,6 +12,7 @@ import { useTranslation } from '../translate';
|
||||
import Parachain from './Parachain';
|
||||
|
||||
interface Props {
|
||||
canRegister?: boolean;
|
||||
ids?: ParaId[];
|
||||
}
|
||||
|
||||
|
||||
@ -11,11 +11,12 @@ import { formatNumber, isNumber } from '@polkadot/util';
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
canRegister?: boolean;
|
||||
parachainCount?: number;
|
||||
upcomingCount?: number;
|
||||
}
|
||||
|
||||
function Summary ({ parachainCount, upcomingCount }: Props): React.ReactElement<Props> {
|
||||
function Summary ({ canRegister, parachainCount, upcomingCount }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
|
||||
@ -39,6 +40,11 @@ function Summary ({ parachainCount, upcomingCount }: Props): React.ReactElement<
|
||||
</CardSummary>
|
||||
)}
|
||||
</section>
|
||||
<section>
|
||||
<CardSummary label={t<string>('registration')}>
|
||||
{canRegister ? t<string>('open') : t<string>('closed')}
|
||||
</CardSummary>
|
||||
</section>
|
||||
<section>
|
||||
<CardSummary
|
||||
className='media--800'
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { bool } from '@polkadot/types';
|
||||
import type { ParaId } from '@polkadot/types/interfaces';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
|
||||
import Actions from './Actions';
|
||||
import Parachains from './Parachains';
|
||||
import Summary from './Summary';
|
||||
import Upcoming from './Upcoming';
|
||||
@ -15,20 +17,30 @@ interface Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const transformRegister = {
|
||||
transform: (value: bool): boolean => value.isTrue
|
||||
};
|
||||
|
||||
function Overview (): React.ReactElement<Props> {
|
||||
const { api } = useApi();
|
||||
const paraIds = useCall<ParaId[]>(api.query.paras?.parachains);
|
||||
const upcomingIds = useCall<ParaId[]>(api.query.paras?.upcomingParas);
|
||||
const canRegister = useCall<boolean>(api.query.registrar?.parathreadsRegistrationEnabled, [], transformRegister);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Summary
|
||||
canRegister={canRegister}
|
||||
parachainCount={paraIds?.length}
|
||||
upcomingCount={upcomingIds?.length}
|
||||
/>
|
||||
<Actions canRegister={canRegister} />
|
||||
{api.query.paras && (
|
||||
<>
|
||||
<Parachains ids={paraIds} />
|
||||
<Parachains
|
||||
canRegister={canRegister}
|
||||
ids={paraIds}
|
||||
/>
|
||||
<Upcoming ids={upcomingIds} />
|
||||
</>
|
||||
)}
|
||||
|
||||
118
packages/page-parachains/src/modals/Register.tsx
Normal file
118
packages/page-parachains/src/modals/Register.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
// Copyright 2017-2021 @polkadot/app-parachains authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import React, { useCallback, useState } from 'react';
|
||||
|
||||
import { InputAddress, InputFile, InputNumber, InputWasm, Modal, TxButton } from '@polkadot/react-components';
|
||||
import { useApi } from '@polkadot/react-hooks';
|
||||
import { BN_ZERO, compactAddLength } from '@polkadot/util';
|
||||
|
||||
import { useTranslation } from '../translate';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface CodeState {
|
||||
isWasmValid: boolean;
|
||||
wasm: Uint8Array | null;
|
||||
}
|
||||
|
||||
function Register ({ className, onClose }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { api } = useApi();
|
||||
const [accountId, setAccountId] = useState<string | null>(null);
|
||||
const [paraId, setParaId] = useState(BN_ZERO);
|
||||
const [{ isWasmValid, wasm }, setWasm] = useState<CodeState>({ isWasmValid: false, wasm: null });
|
||||
const [genesisState, setGenesisState] = useState<Uint8Array | null>(null);
|
||||
|
||||
const _setGenesisState = useCallback(
|
||||
(data: Uint8Array) => setGenesisState(compactAddLength(data)),
|
||||
[]
|
||||
);
|
||||
|
||||
const _setWasm = useCallback(
|
||||
(wasm: Uint8Array, isWasmValid: boolean) => setWasm({ isWasmValid, wasm }),
|
||||
[]
|
||||
);
|
||||
|
||||
console.error(genesisState);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={className}
|
||||
header={t<string>('Register parachain')}
|
||||
>
|
||||
<Modal.Content>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputAddress
|
||||
label={t<string>('register from')}
|
||||
onChange={setAccountId}
|
||||
type='account'
|
||||
value={accountId}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t<string>('This account will be associated with the parachain and pay the deposit.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputNumber
|
||||
label={t<string>('parachain id')}
|
||||
onChange={setParaId}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t<string>('The id of this parachain as known on the network')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputWasm
|
||||
help={t<string>('The compiled runtime WASM for the parachain you wish to register.')}
|
||||
isError={!isWasmValid}
|
||||
label={t<string>('code')}
|
||||
onChange={_setWasm}
|
||||
placeholder={
|
||||
wasm && !isWasmValid
|
||||
? t<string>('The code is not recognized as being in valid WASM format')
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t<string>('The WASM validation function for this parachain.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
<Modal.Columns>
|
||||
<Modal.Column>
|
||||
<InputFile
|
||||
help={t<string>('The genesis state for the parachain.')}
|
||||
isError={!genesisState}
|
||||
label={t<string>('initial state')}
|
||||
onChange={_setGenesisState}
|
||||
/>
|
||||
</Modal.Column>
|
||||
<Modal.Column>
|
||||
<p>{t<string>('The genesis state for this parachain.')}</p>
|
||||
</Modal.Column>
|
||||
</Modal.Columns>
|
||||
</Modal.Content>
|
||||
<Modal.Actions onCancel={onClose}>
|
||||
<TxButton
|
||||
accountId={accountId}
|
||||
icon='plus'
|
||||
isDisabled={!isWasmValid || !genesisState}
|
||||
onStart={onClose}
|
||||
params={[paraId, genesisState, wasm]}
|
||||
tx={api.tx.registrar.registerParathread}
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Register);
|
||||
@ -12,10 +12,7 @@ import { formatNumber, hexToU8a, isHex, u8aToString } from '@polkadot/util';
|
||||
import Labelled from './Labelled';
|
||||
import { useTranslation } from './translate';
|
||||
|
||||
export interface InputFileProps {
|
||||
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
|
||||
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
|
||||
accept?: string;
|
||||
export interface InputFilePropsBase {
|
||||
className?: string;
|
||||
clearContent?: boolean;
|
||||
help?: React.ReactNode;
|
||||
@ -23,12 +20,18 @@ export interface InputFileProps {
|
||||
isError?: boolean;
|
||||
isFull?: boolean;
|
||||
label: React.ReactNode;
|
||||
onChange?: (contents: Uint8Array, name: string) => void;
|
||||
placeholder?: React.ReactNode | null;
|
||||
withEllipsis?: boolean;
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
export interface InputFileProps extends InputFilePropsBase {
|
||||
// Reference Example Usage: https://github.com/react-dropzone/react-dropzone/tree/master/examples/Accept
|
||||
// i.e. MIME types: 'application/json, text/plain', or '.json, .txt'
|
||||
accept?: string;
|
||||
onChange?: (contents: Uint8Array, name: string) => void;
|
||||
}
|
||||
|
||||
interface FileState {
|
||||
name: string;
|
||||
size: number;
|
||||
|
||||
@ -1,24 +1,26 @@
|
||||
// Copyright 2017-2021 @polkadot/react-components authors & contributors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import type { InputFilePropsBase } from './InputFile';
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import { compactAddLength, isWasm } from '@polkadot/util';
|
||||
|
||||
import InputFile, { InputFileProps } from './InputFile';
|
||||
import InputFile from './InputFile';
|
||||
|
||||
interface Props extends Omit<InputFileProps, 'accept'> {
|
||||
isValidRef: React.MutableRefObject<boolean>;
|
||||
onChange: (contents: Uint8Array, name?: string) => void;
|
||||
interface Props extends InputFilePropsBase {
|
||||
onChange: (contents: Uint8Array, isValid: boolean, name?: string) => void;
|
||||
}
|
||||
|
||||
function InputWasm ({ isValidRef, onChange, ...props }: Props): React.ReactElement<Props> {
|
||||
function InputWasm ({ onChange, ...props }: Props): React.ReactElement<Props> {
|
||||
const _onChange = useCallback(
|
||||
(wasm: Uint8Array, name: string): void => {
|
||||
isValidRef.current = isWasm(wasm);
|
||||
onChange(compactAddLength(wasm), name);
|
||||
const isValid = isWasm(wasm);
|
||||
|
||||
onChange(compactAddLength(wasm), isValid, name);
|
||||
},
|
||||
[isValidRef, onChange]
|
||||
[onChange]
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user