Create Enum, Option & Struct from toRawType (#1277)
* Create enums from toRawType * Render with children * De-dup static rendering * Cleanups * Cater for structs * Allow breaks for params labels
This commit is contained in:
parent
d9218985b7
commit
b3e68e6089
113
packages/ui-params/src/Param/Enum.tsx
Normal file
113
packages/ui-params/src/Param/Enum.tsx
Normal file
@ -0,0 +1,113 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Props as BaseProps, RawParam } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { Enum, TypeDef, createType, getTypeDef } from '@polkadot/types';
|
||||
import { Dropdown } from '@polkadot/ui-app';
|
||||
|
||||
import Params from '../';
|
||||
import Bare from './Bare';
|
||||
import Static from './Static';
|
||||
|
||||
type Props = BaseProps;
|
||||
|
||||
type State = {
|
||||
def: TypeDef | null,
|
||||
options: Array<{ text: string, value: string }>,
|
||||
sub: Array<TypeDef>,
|
||||
type: string | null
|
||||
};
|
||||
|
||||
export default class EnumParam extends React.PureComponent<Props, State> {
|
||||
state: State = {
|
||||
def: null,
|
||||
options: [],
|
||||
sub: [],
|
||||
type: null
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ type: { type } }: Props, prevState: State) {
|
||||
if (prevState.type === type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sub = getTypeDef(createType(type).toRawType()).sub as Array<TypeDef>;
|
||||
const options = sub.map(({ name }) => ({
|
||||
text: name,
|
||||
value: name
|
||||
}));
|
||||
const def = prevState.def || sub[0];
|
||||
|
||||
return {
|
||||
def,
|
||||
options,
|
||||
sub,
|
||||
type
|
||||
} as State;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, defaultValue, isDisabled, isError, label, style, withLabel } = this.props;
|
||||
|
||||
if (isDisabled) {
|
||||
return <Static {...this.props} />;
|
||||
}
|
||||
|
||||
const { def, options } = this.state;
|
||||
const initialValue = defaultValue && defaultValue.value
|
||||
? defaultValue.value instanceof Enum
|
||||
? defaultValue.value.type
|
||||
: Object.keys(defaultValue.value)[0]
|
||||
: defaultValue;
|
||||
|
||||
return (
|
||||
<Bare
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Dropdown
|
||||
className='large'
|
||||
defaultValue={initialValue}
|
||||
isDisabled={isDisabled}
|
||||
isError={isError}
|
||||
label={label}
|
||||
options={options}
|
||||
onChange={this.onChange}
|
||||
withEllipsis
|
||||
withLabel={withLabel}
|
||||
/>
|
||||
{def && (
|
||||
<Params
|
||||
onChange={this.onChangeParam}
|
||||
params={[{ name: def.name, type: def }]}
|
||||
/>
|
||||
)}
|
||||
</Bare>
|
||||
);
|
||||
}
|
||||
|
||||
private onChange = (value: string): void => {
|
||||
const { sub } = this.state;
|
||||
|
||||
this.setState({
|
||||
def: sub.find(({ name }) => name === value) || null
|
||||
});
|
||||
}
|
||||
|
||||
private onChangeParam = ([{ isValid, value }]: Array<RawParam>): void => {
|
||||
const { onChange } = this.props;
|
||||
const { def } = this.state;
|
||||
|
||||
if (def) {
|
||||
onChange && onChange({
|
||||
isValid,
|
||||
value: {
|
||||
[def.name as string]: value
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
22
packages/ui-params/src/Param/Null.tsx
Normal file
22
packages/ui-params/src/Param/Null.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Props } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export default class Null extends React.PureComponent<Props> {
|
||||
componentDidMount () {
|
||||
const { onChange } = this.props;
|
||||
|
||||
onChange && onChange({
|
||||
isValid: true,
|
||||
value: null
|
||||
});
|
||||
}
|
||||
|
||||
render () {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
39
packages/ui-params/src/Param/Static.tsx
Normal file
39
packages/ui-params/src/Param/Static.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Props as BareProps, RawParam } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { Static } from '@polkadot/ui-app';
|
||||
import translate from '@polkadot/ui-app/translate';
|
||||
|
||||
import Bare from './Bare';
|
||||
|
||||
type Props = BareProps & WithTranslation & {
|
||||
defaultValue: RawParam,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
class StaticParam extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, defaultValue, label, style, t } = this.props;
|
||||
const value = defaultValue && defaultValue.value && defaultValue.value.toString();
|
||||
|
||||
return (
|
||||
<Bare
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Static
|
||||
className='full'
|
||||
label={label}
|
||||
value={value || t('empty')}
|
||||
/>
|
||||
</Bare>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(StaticParam);
|
||||
85
packages/ui-params/src/Param/Struct.tsx
Normal file
85
packages/ui-params/src/Param/Struct.tsx
Normal file
@ -0,0 +1,85 @@
|
||||
// Copyright 2017-2019 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Props as BaseProps, RawParam } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { TypeDef, createType, getTypeDef } from '@polkadot/types';
|
||||
|
||||
import Params from '../';
|
||||
import Base from './Base';
|
||||
import Static from './Static';
|
||||
|
||||
type Props = BaseProps;
|
||||
|
||||
type State = {
|
||||
defs: Array<TypeDef>,
|
||||
type: string | null
|
||||
};
|
||||
|
||||
export default class StructParam extends React.PureComponent<Props, State> {
|
||||
state: State = {
|
||||
defs: [],
|
||||
type: null
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps ({ type: { type } }: Props, prevState: State) {
|
||||
if (prevState.type === type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const defs = getTypeDef(createType(type).toRawType()).sub as Array<TypeDef>;
|
||||
|
||||
return {
|
||||
defs,
|
||||
type
|
||||
} as State;
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, isDisabled, label, style, withLabel } = this.props;
|
||||
|
||||
if (isDisabled) {
|
||||
return <Static {...this.props} />;
|
||||
}
|
||||
|
||||
const { defs } = this.state;
|
||||
const params = defs.map((type) => ({ name: type.name, type }));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Base
|
||||
className={className}
|
||||
label={label}
|
||||
size='full'
|
||||
style={style}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
|
||||
</Base>
|
||||
<Params
|
||||
onChange={this.onChangeParams}
|
||||
params={params}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onChangeParams = (values: Array<RawParam>) => {
|
||||
const { onChange } = this.props;
|
||||
|
||||
if (onChange) {
|
||||
const { defs } = this.state;
|
||||
|
||||
onChange({
|
||||
isValid: values.reduce((result, { isValid }) => result && isValid, true as boolean),
|
||||
value: defs.reduce((value, { name }, index) => {
|
||||
value[name as string] = values[index].value;
|
||||
|
||||
return value;
|
||||
}, {} as { [index: string]: any })
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2,40 +2,24 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { WithTranslation } from 'react-i18next';
|
||||
import { Props as BareProps, RawParam } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { Static } from '@polkadot/ui-app';
|
||||
import translate from '@polkadot/ui-app/translate';
|
||||
|
||||
import Bare from './Bare';
|
||||
import BaseBytes from './BaseBytes';
|
||||
import Static from './Static';
|
||||
|
||||
type Props = BareProps & WithTranslation & {
|
||||
type Props = BareProps & {
|
||||
defaultValue: RawParam,
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
class Unknown extends React.PureComponent<Props> {
|
||||
export default class Unknown extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, defaultValue, isDisabled, isError, label, name, onChange, onEnter, style, t, type } = this.props;
|
||||
const { className, defaultValue, isDisabled, isError, label, name, onChange, onEnter, style, type } = this.props;
|
||||
|
||||
if (isDisabled) {
|
||||
const value = defaultValue && defaultValue.value && defaultValue.value.toString();
|
||||
|
||||
return (
|
||||
<Bare
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Static
|
||||
className='full'
|
||||
label={label}
|
||||
value={value || t('empty')}
|
||||
/>
|
||||
</Bare>
|
||||
);
|
||||
return <Static {...this.props} />;
|
||||
}
|
||||
|
||||
return (
|
||||
@ -57,5 +41,3 @@ class Unknown extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Unknown);
|
||||
|
||||
@ -2,20 +2,25 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { TypeDef, TypeDefInfo, UInt, createType } from '@polkadot/types';
|
||||
import { Props, ComponentMap } from '../types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { TypeDef, TypeDefInfo, createType, getTypeDef } from '@polkadot/types';
|
||||
|
||||
import Account from './Account';
|
||||
import Amount from './Amount';
|
||||
import Balance from './Balance';
|
||||
import Bool from './Bool';
|
||||
import Bytes from './Bytes';
|
||||
import Code from './Code';
|
||||
import Enum from './Enum';
|
||||
import Hash from './Hash';
|
||||
import Moment from './Moment';
|
||||
import Proposal from './Proposal';
|
||||
import KeyValue from './KeyValue';
|
||||
import KeyValueArray from './KeyValueArray';
|
||||
import Null from './Null';
|
||||
import Struct from './Struct';
|
||||
import Text from './Text';
|
||||
import Tuple from './Tuple';
|
||||
import Unknown from './Unknown';
|
||||
@ -35,16 +40,20 @@ const components: ComponentMap = ([
|
||||
{ c: Bool, t: ['bool'] },
|
||||
{ c: Bytes, t: ['Bytes'] },
|
||||
{ c: Code, t: ['Code'] },
|
||||
{ c: Enum, t: ['Enum'] },
|
||||
{ c: Hash, t: ['CodeHash', 'Hash', 'SeedOf', 'Signature'] },
|
||||
{ c: KeyValue, t: ['KeyValue'] },
|
||||
{ c: KeyValueArray, t: ['Vec<KeyValue>'] },
|
||||
{ c: Moment, t: ['Moment', 'MomentOf'] },
|
||||
{ c: Null, t: ['Null'] },
|
||||
{ c: Proposal, t: ['Proposal'] },
|
||||
{ c: Text, t: ['String', 'Text'] },
|
||||
{ c: Struct, t: ['Struct'] },
|
||||
{ c: Tuple, t: ['Tuple'] },
|
||||
{ c: Vector, t: ['Vector'] },
|
||||
{ c: Vote, t: ['Vote'] },
|
||||
{ c: VoteThreshold, t: ['VoteThreshold'] }
|
||||
{ c: VoteThreshold, t: ['VoteThreshold'] },
|
||||
{ c: Unknown, t: ['Unknown'] }
|
||||
] as Array<TypeToComponent>).reduce((components, { c, t }) => {
|
||||
t.forEach((type) => {
|
||||
components[type] = c;
|
||||
@ -57,8 +66,15 @@ export default function findComponent (def: TypeDef, overrides: ComponentMap = {
|
||||
const type = (({ info, sub, type }: TypeDef) => {
|
||||
switch (info) {
|
||||
case TypeDefInfo.Compact:
|
||||
case TypeDefInfo.Option:
|
||||
return (sub as TypeDef).type;
|
||||
|
||||
case TypeDefInfo.Enum:
|
||||
return 'Enum';
|
||||
|
||||
case TypeDefInfo.Struct:
|
||||
return 'Struct';
|
||||
|
||||
case TypeDefInfo.Tuple:
|
||||
return 'Tuple';
|
||||
|
||||
@ -77,9 +93,12 @@ export default function findComponent (def: TypeDef, overrides: ComponentMap = {
|
||||
if (!Component) {
|
||||
try {
|
||||
const instance = createType(type);
|
||||
const raw = getTypeDef(instance.toRawType());
|
||||
|
||||
if (instance instanceof UInt) {
|
||||
if (instance instanceof BN) {
|
||||
return Amount;
|
||||
} else if ([TypeDefInfo.Enum, TypeDefInfo.Struct].includes(raw.info)) {
|
||||
return findComponent(raw, overrides);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error(error.message);
|
||||
|
||||
@ -17,6 +17,10 @@
|
||||
.ui--Params-Content {
|
||||
box-sizing: border-box;
|
||||
padding: 0 0 0 1.75rem;
|
||||
|
||||
label .withEllipsis {
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.ui--Param-text {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import { RawParam$Value } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import { Bytes, Hash, TypeDef, TypeDefInfo, U8a, UInt, createType } from '@polkadot/types';
|
||||
import { Bytes, Hash, TypeDef, TypeDefInfo, U8a, createType, getTypeDef } from '@polkadot/types';
|
||||
|
||||
export default function getInitValue (def: TypeDef): RawParam$Value | Array<RawParam$Value> {
|
||||
if (def.info === TypeDefInfo.Vector) {
|
||||
@ -15,11 +15,20 @@ export default function getInitValue (def: TypeDef): RawParam$Value | Array<RawP
|
||||
? def.sub.map((def) => getInitValue(def))
|
||||
: [];
|
||||
} else if (def.info === TypeDefInfo.Struct) {
|
||||
console.error(`Unable to determine default type from Struct ${JSON.stringify(def)}`);
|
||||
return void 0;
|
||||
return Array.isArray(def.sub)
|
||||
? def.sub.reduce((result, def) => {
|
||||
result[def.name as string] = getInitValue(def);
|
||||
|
||||
return result;
|
||||
}, {} as { [index: string]: RawParam$Value | Array<RawParam$Value> })
|
||||
: {};
|
||||
} else if (def.info === TypeDefInfo.Enum) {
|
||||
return Array.isArray(def.sub)
|
||||
? { [def.sub[0].name as string]: getInitValue(def.sub[0]) }
|
||||
: {};
|
||||
}
|
||||
|
||||
const type = def.info === TypeDefInfo.Compact
|
||||
const type = [TypeDefInfo.Compact, TypeDefInfo.Option].includes(def.info)
|
||||
? (def.sub as TypeDef).type
|
||||
: def.type;
|
||||
|
||||
@ -84,12 +93,18 @@ export default function getInitValue (def: TypeDef): RawParam$Value | Array<RawP
|
||||
case 'Extrinsic':
|
||||
return new U8a();
|
||||
|
||||
case 'Null':
|
||||
return null;
|
||||
|
||||
default: {
|
||||
try {
|
||||
const instance = createType(type);
|
||||
const raw = getTypeDef(instance.toRawType());
|
||||
|
||||
if (instance instanceof UInt) {
|
||||
if (instance instanceof BN) {
|
||||
return new BN(0);
|
||||
} else if ([TypeDefInfo.Enum, TypeDefInfo.Struct].includes(raw.info)) {
|
||||
return getInitValue(raw);
|
||||
}
|
||||
} catch (error) {
|
||||
// console.error(error.message);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user