Pass last decoded extrinsic to submission (#6964)

* Pass last decoded extrinsic to submission (partial)

* Adjust

* Vector

* Adjust

* Adjust

* Adjust

* Fix enum state

* Tweak enum

* Non-crashing enum

* Tuple

* Cleanups

* Cleanups

* CHANGELOG
This commit is contained in:
Jaco 2022-02-25 13:12:29 +01:00 committed by GitHub
parent 2550860722
commit 661ed704db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 284 additions and 188 deletions

View File

@ -6,6 +6,7 @@ Changes:
- Adjust teleport to only cater for latest XCM
- Add blocktime latency tab to Explorer
- Allow decoded extrinsics to populate submission
## 0.106.1 Feb 14, 2022

View File

@ -3,6 +3,7 @@
import type { SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@polkadot/api/types';
import type { Call } from '@polkadot/types/interfaces';
import type { DecodedExtrinsic } from './types';
import React, { useCallback, useState } from 'react';
import styled from 'styled-components';
@ -17,6 +18,7 @@ import { useTranslation } from './translate';
interface Props {
className?: string;
setLast: (value: DecodedExtrinsic | null) => void;
}
interface ExtrinsicInfo {
@ -37,7 +39,7 @@ const DEFAULT_INFO: ExtrinsicInfo = {
extrinsicHex: null
};
function Decoder ({ className }: Props): React.ReactElement<Props> {
function Decoder ({ className, setLast }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [{ decoded, extrinsic, extrinsicCall, extrinsicError, extrinsicFn }, setExtrinsicInfo] = useState<ExtrinsicInfo>(DEFAULT_INFO);
@ -68,11 +70,13 @@ function Decoder ({ className }: Props): React.ReactElement<Props> {
}
setExtrinsicInfo({ ...DEFAULT_INFO, decoded, extrinsic, extrinsicCall, extrinsicFn, extrinsicHex });
setLast({ call: extrinsicCall, fn: extrinsicFn });
} catch (e) {
setExtrinsicInfo({ ...DEFAULT_INFO, extrinsicError: (e as Error).message });
setLast(null);
}
},
[api]
[api, setLast]
);
return (

View File

@ -1,7 +1,9 @@
// Copyright 2017-2022 @polkadot/app-extrinsics authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { SubmittableExtrinsic } from '@polkadot/api/types';
import type { SubmittableExtrinsic, SubmittableExtrinsicFunction } from '@polkadot/api/types';
import type { RawParam } from '@polkadot/react-params/types';
import type { DecodedExtrinsic } from './types';
import React, { useCallback, useState } from 'react';
@ -14,22 +16,45 @@ import { useTranslation } from './translate';
interface Props {
className?: string;
defaultValue: DecodedExtrinsic | null;
}
function Selection ({ className }: Props): React.ReactElement<Props> {
interface DefaultExtrinsic {
defaultArgs?: RawParam[];
defaultFn: SubmittableExtrinsicFunction<'promise'>;
}
function extractDefaults (value: DecodedExtrinsic | null, defaultFn: SubmittableExtrinsicFunction<'promise'>): DefaultExtrinsic {
if (!value) {
return { defaultFn };
}
return {
defaultArgs: value.call.args.map((value) => ({
isValid: true,
value
})),
defaultFn: value.fn
};
}
function Selection ({ className, defaultValue }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { apiDefaultTxSudo } = useApi();
const [accountId, setAccountId] = useState<string | null>(null);
const [error, setError] = useState<string | null>(null);
const [extrinsic, setExtrinsic] = useState<SubmittableExtrinsic<'promise'> | null>(null);
const [{ defaultArgs, defaultFn }] = useState<DefaultExtrinsic>(() => extractDefaults(defaultValue, apiDefaultTxSudo));
const _onExtrinsicChange = useCallback(
(method?: SubmittableExtrinsic<'promise'>) => setExtrinsic(() => method || null),
(method?: SubmittableExtrinsic<'promise'>) =>
setExtrinsic(() => method || null),
[]
);
const _onExtrinsicError = useCallback(
(error?: Error | null) => setError(error ? error.message : null),
(error?: Error | null) =>
setError(error ? error.message : null),
[]
);
@ -47,7 +72,8 @@ function Selection ({ className }: Props): React.ReactElement<Props> {
type='account'
/>
<Extrinsic
defaultValue={apiDefaultTxSudo}
defaultArgs={defaultArgs}
defaultValue={defaultFn}
label={t<string>('submit the following extrinsic')}
onChange={_onExtrinsicChange}
onError={_onExtrinsicError}

View File

@ -2,8 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
import type { AppProps as Props } from '@polkadot/react-components/types';
import type { DecodedExtrinsic } from './types';
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import { Route, Switch } from 'react-router';
import { Tabs } from '@polkadot/react-components';
@ -14,6 +15,7 @@ import { useTranslation } from './translate';
function ExtrinsicsApp ({ basePath }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const [decoded, setDecoded] = useState<DecodedExtrinsic | null>(null);
const itemsRef = useRef([
{
@ -34,9 +36,11 @@ function ExtrinsicsApp ({ basePath }: Props): React.ReactElement<Props> {
items={itemsRef.current}
/>
<Switch>
<Route path={`${basePath}/decode`}><Decoder /></Route>
<Route path={`${basePath}/decode`}>
<Decoder setLast={setDecoded} />
</Route>
<Route>
<Submission />
<Submission defaultValue={decoded} />
</Route>
</Switch>
</main>

View File

@ -0,0 +1,10 @@
// Copyright 2017-2022 @polkadot/app-extrinsics authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { SubmittableExtrinsicFunction } from '@polkadot/api/types';
import type { Call } from '@polkadot/types/interfaces';
export interface DecodedExtrinsic {
call: Call;
fn: SubmittableExtrinsicFunction<'promise'>;
}

View File

@ -16,6 +16,7 @@ import paramComponents from './Params';
interface Props {
className?: string;
defaultArgs?: RawParam[];
defaultValue: SubmittableExtrinsicFunction<'promise'>;
isDisabled?: boolean;
isError?: boolean;
@ -28,15 +29,29 @@ interface Props {
withLabel?: boolean;
}
interface CallState {
fn: SubmittableExtrinsicFunction<'promise'>;
params: {
name: string;
type: TypeDef
}[];
interface ParamDef {
name: string;
type: TypeDef;
}
function getParams ({ meta }: SubmittableExtrinsicFunction<'promise'>): { name: string; type: TypeDef }[] {
interface CallState {
extrinsic: {
fn: SubmittableExtrinsicFunction<'promise'>;
params: ParamDef[];
},
values: RawParam[];
}
function isValuesValid (params: ParamDef[], values: RawParam[]): boolean {
return values.reduce((isValid, value): boolean =>
isValid &&
!isUndefined(value) &&
!isUndefined(value.value) &&
value.isValid, params.length === values.length
);
}
function getParams ({ meta }: SubmittableExtrinsicFunction<'promise'>): ParamDef[] {
return meta.args.map(({ name, type, typeName }): { name: string; type: TypeDef } => ({
name: name.toString(),
type: {
@ -49,21 +64,21 @@ function getParams ({ meta }: SubmittableExtrinsicFunction<'promise'>): { name:
}));
}
function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label, onChange, onEnter, onError, onEscape, withLabel }: Props): React.ReactElement<Props> {
const [extrinsic, setCall] = useState<CallState>(() => ({ fn: defaultValue, params: getParams(defaultValue) }));
const [values, setValues] = useState<RawParam[]>([]);
function getCallState (fn: SubmittableExtrinsicFunction<'promise'>, values: RawParam[] = []): CallState {
return {
extrinsic: {
fn,
params: getParams(fn)
},
values
};
}
function ExtrinsicDisplay ({ defaultArgs, defaultValue, isDisabled, isError, isPrivate, label, onChange, onEnter, onError, onEscape, withLabel }: Props): React.ReactElement<Props> {
const [{ extrinsic, values }, setDisplay] = useState<CallState>(() => getCallState(defaultValue, defaultArgs));
useEffect((): void => {
setValues([]);
}, [extrinsic]);
useEffect((): void => {
const isValid = values.reduce((isValid, value): boolean =>
isValid &&
!isUndefined(value) &&
!isUndefined(value.value) &&
value.isValid, extrinsic.params.length === values.length
);
const isValid = isValuesValid(extrinsic.params, values);
let method;
@ -81,7 +96,14 @@ function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label
}, [extrinsic, onChange, onError, values]);
const _onChangeMethod = useCallback(
(fn: SubmittableExtrinsicFunction<'promise'>): void => setCall({ fn, params: getParams(fn) }),
(fn: SubmittableExtrinsicFunction<'promise'>) =>
setDisplay(getCallState(fn)),
[]
);
const _setValues = useCallback(
(values: RawParam[]) =>
setDisplay(({ extrinsic }) => ({ extrinsic, values })),
[]
);
@ -101,11 +123,12 @@ function ExtrinsicDisplay ({ defaultValue, isDisabled, isError, isPrivate, label
/>
<Params
key={`${section}.${method}:params` /* force re-render on change */}
onChange={setValues}
onChange={_setValues}
onEnter={onEnter}
onEscape={onEscape}
overrides={paramComponents}
params={params}
values={values}
/>
</div>
);

View File

@ -10,28 +10,29 @@ import { keyring } from '@polkadot/ui-keyring';
import Bare from './Bare';
function isValidAddress (value?: string | null): boolean {
if (value) {
try {
keyring.decodeAddress(value);
return true;
} catch (err) {
console.error(err);
}
}
return false;
}
function Account ({ className = '', defaultValue: { value }, isDisabled, isError, isInOption, label, onChange, withLabel }: Props): React.ReactElement<Props> {
const [defaultValue] = useState(() => (value as string)?.toString());
const _onChange = useCallback(
(value?: string | null): void => {
let isValid = false;
if (value) {
try {
keyring.decodeAddress(value);
isValid = true;
} catch (err) {
console.error(err);
}
}
(value?: string | null) =>
onChange && onChange({
isValid,
isValid: isValidAddress(value),
value
});
},
}),
[onChange]
);

View File

@ -1,6 +1,7 @@
// Copyright 2017-2022 @polkadot/react-params authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { Registry, TypeDef } from '@polkadot/types/types';
import type { BN } from '@polkadot/util';
import type { Props } from '../types';
@ -11,6 +12,14 @@ import { bnToBn, formatNumber, isUndefined } from '@polkadot/util';
import Bare from './Bare';
function getBitLength (registry: Registry, { type }: TypeDef): number {
try {
return registry.createType(type as 'u32').bitLength();
} catch (error) {
return 32;
}
}
function Amount ({ className = '', defaultValue: { value }, isDisabled, isError, label, onChange, onEnter, registry, type, withLabel }: Props): React.ReactElement<Props> {
const defaultValue = useMemo(
() => isDisabled
@ -22,21 +31,16 @@ function Amount ({ className = '', defaultValue: { value }, isDisabled, isError,
);
const bitLength = useMemo(
(): number => {
try {
return registry.createType(type.type as 'u32').bitLength();
} catch (error) {
return 32;
}
},
() => getBitLength(registry, type),
[registry, type]
);
const _onChange = useCallback(
(value?: BN) => onChange && onChange({
isValid: !isUndefined(value),
value
}),
(value?: BN) =>
onChange && onChange({
isValid: !isUndefined(value),
value
}),
[onChange]
);

View File

@ -78,7 +78,10 @@ function BaseBytes ({ asHex, children, className = '', defaultValue: { value },
: u8aToHex(value as Uint8Array, isDisabled ? 256 : -1)
: undefined
);
const [{ isAddress, isValid, lastValue }, setValidity] = useState<Validity>(() => ({ isAddress: false, isValid: false }));
const [{ isAddress, isValid, lastValue }, setValidity] = useState<Validity>(() => ({
isAddress: false,
isValid: isHex(defaultValue)
}));
const _onChange = useCallback(
(hex: string): void => {

View File

@ -1,10 +1,10 @@
// Copyright 2017-2022 @polkadot/react-params authors & contributors
// SPDX-License-Identifier: Apache-2.0
import type { TypeDef } from '@polkadot/types/types';
import type { Registry, TypeDef } from '@polkadot/types/types';
import type { ParamDef, Props, RawParam } from '../types';
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useState } from 'react';
import { Dropdown } from '@polkadot/react-components';
import { Enum, getTypeDef } from '@polkadot/types';
@ -23,40 +23,61 @@ interface Options {
subTypes: TypeDef[];
}
interface Initial {
initialEnum: string | null;
initialValues: RawParam[] | undefined;
}
function getSubTypes (registry: Registry, type: TypeDef): TypeDef[] {
const rawType = registry.createType(type.type as 'u32').toRawType();
return getTypeDef(rawType).sub as TypeDef[];
}
function getOptions (registry: Registry, type: TypeDef): Options {
const subTypes = getSubTypes(registry, type).filter(({ name }) => !!name && !name.startsWith('__Unused'));
return {
options: subTypes.map(({ name }): Option => ({
text: name,
value: name
})),
subTypes
};
}
function getInitial (defaultValue: RawParam): Initial {
return {
initialEnum: defaultValue && defaultValue.value
? defaultValue.value instanceof Enum
? defaultValue.value.type
: Object.keys(defaultValue.value as Record<string, unknown>)[0]
: null,
initialValues: defaultValue && defaultValue.value
? defaultValue.value instanceof Enum
? [{ isValid: true, value: defaultValue.value.inner }]
: undefined
: undefined
};
}
function getCurrent (registry: Registry, type: TypeDef, defaultValue: RawParam, subTypes: TypeDef[]): ParamDef[] | null {
const subs = getSubTypes(registry, type);
return defaultValue.value instanceof Enum
? [{ name: defaultValue.value.type, type: subs[defaultValue.value.index] }]
: [{ name: subTypes[0].name, type: subTypes[0] }];
}
function EnumParam (props: Props): React.ReactElement<Props> {
const { className = '', defaultValue, isDisabled, isError, label, onChange, overrides, registry, type, withLabel } = props;
const [current, setCurrent] = useState<ParamDef[] | null>(null);
const [initialValue, setInitialValue] = useState<string | null>(null);
const [{ options, subTypes }, setOptions] = useState<Options>({ options: [], subTypes: [] });
useEffect((): void => {
const rawType = registry.createType(type.type as 'u32').toRawType();
const typeDef = getTypeDef(rawType);
const subTypes = (typeDef.sub as TypeDef[]).filter(({ name }) => !!name && !name.startsWith('__Unused'));
setOptions({
options: subTypes.map(({ name }): Option => ({
text: name,
value: name
})),
subTypes
});
setCurrent([{ name: subTypes[0].name, type: subTypes[0] }]);
}, [registry, type]);
useEffect((): void => {
setInitialValue(
defaultValue && defaultValue.value
? defaultValue.value instanceof Enum
? defaultValue.value.type
: Object.keys(defaultValue.value as Record<string, unknown>)[0]
: null
);
}, [defaultValue]);
const [{ options, subTypes }] = useState<Options>(() => getOptions(registry, type));
const [current, setCurrent] = useState<ParamDef[] | null>(() => getCurrent(registry, type, defaultValue, subTypes));
const [{ initialEnum, initialValues }] = useState<Initial>(() => getInitial(defaultValue));
const _onChange = useCallback(
(value: string): void => {
const newType = subTypes.find(({ name }): boolean => name === value) || null;
const newType = subTypes.find(({ name }) => name === value) || null;
setCurrent(
newType
@ -85,7 +106,7 @@ function EnumParam (props: Props): React.ReactElement<Props> {
<Bare className={className}>
<Dropdown
className='full'
defaultValue={initialValue}
defaultValue={initialEnum}
isDisabled={isDisabled}
isError={isError}
label={label}
@ -100,6 +121,7 @@ function EnumParam (props: Props): React.ReactElement<Props> {
overrides={overrides}
params={current}
registry={registry}
values={initialValues}
/>
)}
</Bare>

View File

@ -3,16 +3,26 @@
import type { Props, RawParam } from '../types';
import React, { useCallback } from 'react';
import React, { useCallback, useState } from 'react';
import { Struct } from '@polkadot/types';
import { isCodec } from '@polkadot/util';
import Params from '../';
import Base from './Base';
import Static from './Static';
import useParamDefs from './useParamDefs';
function extractValues ({ isValid, value }: RawParam): RawParam[] | undefined {
return (isValid && isCodec(value) && value instanceof Struct)
? value.toArray().map((value) => ({ isValid: true, value }))
: undefined;
}
function StructParam (props: Props): React.ReactElement<Props> {
const params = useParamDefs(props.registry, props.type);
const { className = '', isDisabled, label, onChange, overrides, withLabel } = props;
const { className = '', defaultValue, isDisabled, label, onChange, overrides, withLabel } = props;
const [values] = useState(() => extractValues(defaultValue));
const _onChangeParams = useCallback(
(values: RawParam[]): void => {
@ -44,6 +54,7 @@ function StructParam (props: Props): React.ReactElement<Props> {
overrides={overrides}
params={params}
registry={props.registry}
values={values}
/>
</div>
);

View File

@ -3,21 +3,30 @@
import type { Props, RawParam } from '../types';
import React, { useCallback } from 'react';
import React, { useCallback, useState } from 'react';
import { Tuple } from '@polkadot/types';
import Params from '../';
import Base from './Base';
import Static from './Static';
import useParamDefs from './useParamDefs';
function Tuple (props: Props): React.ReactElement<Props> {
function getInitialValues ({ value }: RawParam): RawParam[] {
return value instanceof Tuple
? value.map((value) => ({ isValid: true, value: value as unknown }))
: value as RawParam[];
}
function TupleDisplay (props: Props): React.ReactElement<Props> {
const params = useParamDefs(props.registry, props.type);
const { className = '', isDisabled, label, onChange, overrides, withLabel } = props;
const { className = '', defaultValue, isDisabled, label, onChange, overrides, withLabel } = props;
const [values] = useState<RawParam[]>(() => getInitialValues(defaultValue));
const _onChangeParams = useCallback(
(values: RawParam[]): void => {
onChange && onChange({
isValid: values.reduce((result: boolean, { isValid }) => result && isValid, true),
isValid: values.reduce<boolean>((result, { isValid }) => result && isValid, true),
value: values.map(({ value }) => value)
});
},
@ -40,9 +49,10 @@ function Tuple (props: Props): React.ReactElement<Props> {
overrides={overrides}
params={params}
registry={props.registry}
values={values}
/>
</div>
);
}
export default React.memo(Tuple);
export default React.memo(TupleDisplay);

View File

@ -14,32 +14,48 @@ import Params from '../';
import Base from './Base';
import useParamDefs from './useParamDefs';
function generateParam ([{ name, type }]: ParamDef[], index: number): ParamDef {
function getParam ([{ name, type }]: ParamDef[], index: number): ParamDef {
return {
name: `${index}: ${name || type.type}`,
type
};
}
export function getParams (inputParams: ParamDef[], prev: ParamDef[], max: number): ParamDef[] {
if (prev.length === max) {
return prev;
}
const params: ParamDef[] = [];
for (let index = 0; index < max; index++) {
params.push(getParam(inputParams, index));
}
return params;
}
export function getValues ({ value }: RawParam): RawParam[] {
return (value as RawParam[] || []).map((value: RawParam) =>
isUndefined(value) || isUndefined(value.isValid)
? { isValid: !isUndefined(value), value }
: value
);
}
function Vector ({ className = '', defaultValue, isDisabled = false, label, onChange, overrides, registry, type, withLabel }: Props): React.ReactElement<Props> | null {
const { t } = useTranslation();
const inputParams = useParamDefs(registry, type);
const [count, setCount] = useState(0);
const [params, setParams] = useState<ParamDef[]>([]);
const [values, setValues] = useState<RawParam[]>([]);
const [values, setValues] = useState<RawParam[]>(() => getValues(defaultValue));
const [count, setCount] = useState(() => values.length);
const [params, setParams] = useState<ParamDef[]>(() => getParams(inputParams, [], count));
// build up the list of parameters we are using
useEffect((): void => {
if (inputParams.length) {
const max = isDisabled ? (defaultValue.value as RawParam[] || []).length : count;
const params: ParamDef[] = [];
for (let index = 0; index < max; index++) {
params.push(generateParam(inputParams, index));
}
setParams(params);
}
inputParams.length &&
setParams((prev) =>
getParams(inputParams, prev, isDisabled ? (defaultValue.value as RawParam[] || []).length : count)
);
}, [count, defaultValue, isDisabled, inputParams]);
// when !isDisable, generating an input list based on count
@ -58,24 +74,12 @@ function Vector ({ className = '', defaultValue, isDisabled = false, label, onCh
return values.slice(0, count);
});
}, [count, inputParams, isDisabled, registry]);
// when isDisabled, set the values based on the defaultValue input
useEffect((): void => {
isDisabled &&
setValues(
(defaultValue.value as RawParam[] || []).map((value: RawParam) =>
isUndefined(value) || isUndefined(value.isValid)
? { isValid: !isUndefined(value), value }
: value
)
);
}, [defaultValue, isDisabled]);
}, [count, defaultValue, inputParams, isDisabled, registry]);
// when our values has changed, alert upstream
useEffect((): void => {
onChange && onChange({
isValid: values.reduce((result: boolean, { isValid }) => result && isValid, true),
isValid: values.reduce<boolean>((result, { isValid }) => result && isValid, true),
value: values.map(({ value }) => value)
});
}, [values, onChange]);

View File

@ -5,39 +5,25 @@ import type { ParamDef, Props, RawParam } from '../types';
import React, { useEffect, useState } from 'react';
import { VecFixed } from '@polkadot/types';
import { isUndefined } from '@polkadot/util';
import getInitValue from '../initValue';
import Params from '../';
import Base from './Base';
import useParamDefs from './useParamDefs';
import { getParams, getValues } from './Vector';
function generateParam ([{ name, type }]: ParamDef[], index: number): ParamDef {
return {
name: `${index}: ${name || type.type}`,
type
};
function getInitialValues (defaultValue: RawParam): RawParam[] {
return defaultValue.value instanceof VecFixed
? defaultValue.value.map((value) => ({ isValid: true, value: value as unknown }))
: getValues(defaultValue);
}
function VectorFixed ({ className = '', defaultValue, isDisabled = false, label, onChange, overrides, registry, type, withLabel }: Props): React.ReactElement<Props> | null {
const inputParams = useParamDefs(registry, type);
const [params, setParams] = useState<ParamDef[]>([]);
const [values, setValues] = useState<RawParam[]>([]);
// build up the list of parameters we are using
useEffect((): void => {
if (inputParams.length) {
const count = (inputParams[0].length || 1);
const max = isDisabled ? (defaultValue.value as RawParam[] || []).length : count;
const params: ParamDef[] = [];
for (let index = 0; index < max; index++) {
params.push(generateParam(inputParams, index));
}
setParams(params);
}
}, [defaultValue, isDisabled, inputParams]);
const [params] = useState<ParamDef[]>(() => getParams(inputParams, [], (inputParams[0].length || 1)));
const [values, setValues] = useState<RawParam[]>(() => getInitialValues(defaultValue));
// when !isDisable, generating an input list based on count
useEffect((): void => {
@ -59,18 +45,6 @@ function VectorFixed ({ className = '', defaultValue, isDisabled = false, label,
});
}, [inputParams, isDisabled, registry]);
// when isDisabled, set the values based on the defaultValue input
useEffect((): void => {
isDisabled &&
setValues(
(defaultValue.value as RawParam[] || []).map((value: RawParam) =>
isUndefined(value) || isUndefined(value.isValid)
? { isValid: !isUndefined(value), value }
: value
)
);
}, [defaultValue, isDisabled]);
// when our values has changed, alert upstream
useEffect((): void => {
onChange && onChange({

View File

@ -4,7 +4,7 @@
import type { Registry, TypeDef } from '@polkadot/types/types';
import type { ParamDef } from '../types';
import { useEffect, useState } from 'react';
import { useMemo } from 'react';
import { createNamedHook } from '@polkadot/react-hooks';
import { getTypeDef } from '@polkadot/types/create';
@ -19,26 +19,23 @@ function expandDef (registry: Registry, td: TypeDef): TypeDef {
}
}
function getDefs (registry: Registry, type: TypeDef): ParamDef[] {
const typeDef = expandDef(registry, type);
return typeDef.sub
? (Array.isArray(typeDef.sub) ? typeDef.sub : [typeDef.sub]).map((td): ParamDef => ({
length: typeDef.length,
name: td.name,
type: td
}))
: [];
}
function useParamDefsImpl (registry: Registry, type: TypeDef): ParamDef[] {
const [params, setParams] = useState<ParamDef[]>([]);
useEffect((): void => {
const typeDef = expandDef(registry, type);
if (!typeDef.sub) {
return setParams([]);
}
setParams(
(Array.isArray(typeDef.sub) ? typeDef.sub : [typeDef.sub]).map((td): ParamDef => ({
length: typeDef.length,
name: td.name,
type: td // expandDef(td)
}))
);
}, [registry, type]);
return params;
return useMemo(
() => getDefs(registry, type),
[registry, type]
);
}
export default createNamedHook('useParamDefs', useParamDefsImpl);

View File

@ -50,13 +50,15 @@ class Params extends React.PureComponent<Props, State> {
return {
params,
values: params.reduce(
(result: RawParams, param, index): RawParams => [
...result,
values && values[index]
? values[index]
: createValue(registry, param)
],
[]
(result: RawParams, param, index): RawParams => {
result.push(
values && values[index]
? values[index]
: createValue(registry, param)
);
return result;
}, []
)
};
}