More func component conversions (#1641)
* More func component conversions * ExtrinsicInput * Selection inputs -> functional * Cleanups * State Selection & linting fixes
This commit is contained in:
parent
b70b7d3aa0
commit
aef86d373a
@ -37,98 +37,98 @@ interface CacheInstance {
|
||||
|
||||
const cache: CacheInstance[] = [];
|
||||
|
||||
function keyToName (isConst: boolean, _key: Uint8Array | StorageEntryPromise | ConstValue): string {
|
||||
if (isConst) {
|
||||
const key = _key as ConstValue;
|
||||
|
||||
return `const ${key.section}.${key.method}`;
|
||||
}
|
||||
|
||||
const key = _key as Uint8Array | StorageEntryPromise;
|
||||
|
||||
if (isU8a(key)) {
|
||||
const u8a = Compact.stripLengthPrefix(key);
|
||||
|
||||
// If the string starts with `:`, handle it as a pure string
|
||||
return u8a[0] === 0x3a
|
||||
? u8aToString(u8a)
|
||||
: u8aToHex(u8a);
|
||||
}
|
||||
|
||||
return `${key.creator.section}.${key.creator.method}`;
|
||||
}
|
||||
|
||||
function typeToString (key: StorageEntryPromise): string {
|
||||
const type = key.creator.meta.type.isDoubleMap
|
||||
? key.creator.meta.type.asDoubleMap.value.toString()
|
||||
: key.creator.meta.type.toString();
|
||||
|
||||
return key.creator.meta.modifier.isOptional
|
||||
? `Option<${type}>`
|
||||
: type;
|
||||
}
|
||||
|
||||
function createComponent (type: string, Component: React.ComponentType<any>, defaultProps: DefaultProps, renderHelper: ComponentRenderer): { Component: React.ComponentType<any>; render: (createComponent: RenderFn) => React.ComponentType<any>; refresh: (swallowErrors: boolean, contentShorten: boolean) => React.ComponentType<any> } {
|
||||
return {
|
||||
Component,
|
||||
// In order to replace the default component during runtime we can provide a RenderFn to create a new 'plugged' component
|
||||
render: (createComponent: RenderFn): React.ComponentType<any> => {
|
||||
return renderHelper(createComponent, defaultProps);
|
||||
},
|
||||
// In order to modify the parameters which are used to render the default component, we can use this method
|
||||
refresh: (swallowErrors: boolean, contentShorten: boolean): React.ComponentType<any> => {
|
||||
return renderHelper(
|
||||
(value: any): React.ReactNode => valueToText(type, value, swallowErrors, contentShorten),
|
||||
defaultProps
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getCachedComponent (query: QueryTypes): CacheInstance {
|
||||
const { id, isConst, key, params = [] } = query as StorageModuleQuery;
|
||||
|
||||
if (!cache[id]) {
|
||||
let renderHelper;
|
||||
let type: string;
|
||||
|
||||
if (isConst) {
|
||||
const { meta, method, section } = key as unknown as ConstValue;
|
||||
|
||||
renderHelper = withCallDiv(`consts.${section}.${method}`);
|
||||
type = meta.type.toString();
|
||||
} else {
|
||||
const values: any[] = params.map(({ value }): any => value);
|
||||
|
||||
// render function to create an element for the query results which is plugged to the api
|
||||
renderHelper = withCallDiv('subscribe', {
|
||||
paramName: 'params',
|
||||
paramValid: true,
|
||||
params: [key, ...values]
|
||||
});
|
||||
type = key.creator && key.creator.meta
|
||||
? typeToString(key)
|
||||
: 'Data';
|
||||
}
|
||||
|
||||
const defaultProps = { className: 'ui--output' };
|
||||
const Component = renderHelper(
|
||||
// By default we render a simple div node component with the query results in it
|
||||
(value: any): React.ReactNode => valueToText(type, value, true, true),
|
||||
defaultProps
|
||||
);
|
||||
|
||||
cache[query.id] = createComponent(type, Component, defaultProps, renderHelper);
|
||||
}
|
||||
|
||||
return cache[id];
|
||||
}
|
||||
|
||||
class Query extends React.PureComponent<Props, State> {
|
||||
public state: State = { spread: {} };
|
||||
|
||||
private static keyToName (isConst: boolean, _key: Uint8Array | StorageEntryPromise | ConstValue): string {
|
||||
if (isConst) {
|
||||
const key = _key as ConstValue;
|
||||
|
||||
return `const ${key.section}.${key.method}`;
|
||||
}
|
||||
|
||||
const key = _key as Uint8Array | StorageEntryPromise;
|
||||
|
||||
if (isU8a(key)) {
|
||||
const u8a = Compact.stripLengthPrefix(key);
|
||||
|
||||
// If the string starts with `:`, handle it as a pure string
|
||||
return u8a[0] === 0x3a
|
||||
? u8aToString(u8a)
|
||||
: u8aToHex(u8a);
|
||||
}
|
||||
|
||||
return `${key.creator.section}.${key.creator.method}`;
|
||||
}
|
||||
|
||||
private static typeToString (key: StorageEntryPromise): string {
|
||||
const type = key.creator.meta.type.isDoubleMap
|
||||
? key.creator.meta.type.asDoubleMap.value.toString()
|
||||
: key.creator.meta.type.toString();
|
||||
|
||||
return key.creator.meta.modifier.isOptional
|
||||
? `Option<${type}>`
|
||||
: type;
|
||||
}
|
||||
|
||||
public static getCachedComponent (query: QueryTypes): CacheInstance {
|
||||
const { id, isConst, key, params = [] } = query as StorageModuleQuery;
|
||||
|
||||
if (!cache[id]) {
|
||||
let renderHelper;
|
||||
let type: string;
|
||||
|
||||
if (isConst) {
|
||||
const { meta, method, section } = key as unknown as ConstValue;
|
||||
|
||||
renderHelper = withCallDiv(`consts.${section}.${method}`);
|
||||
type = meta.type.toString();
|
||||
} else {
|
||||
const values: any[] = params.map(({ value }): any => value);
|
||||
|
||||
// render function to create an element for the query results which is plugged to the api
|
||||
renderHelper = withCallDiv('subscribe', {
|
||||
paramName: 'params',
|
||||
paramValid: true,
|
||||
params: [key, ...values]
|
||||
});
|
||||
type = key.creator.meta
|
||||
? Query.typeToString(key)
|
||||
: 'Data';
|
||||
}
|
||||
|
||||
const defaultProps = { className: 'ui--output' };
|
||||
const Component = renderHelper(
|
||||
// By default we render a simple div node component with the query results in it
|
||||
(value: any): React.ReactNode => valueToText(type, value, true, true),
|
||||
defaultProps
|
||||
);
|
||||
|
||||
cache[query.id] = Query.createComponent(type, Component, defaultProps, renderHelper);
|
||||
}
|
||||
|
||||
return cache[id];
|
||||
}
|
||||
|
||||
public static createComponent (type: string, Component: React.ComponentType<any>, defaultProps: DefaultProps, renderHelper: ComponentRenderer): { Component: React.ComponentType<any>; render: (createComponent: RenderFn) => React.ComponentType<any>; refresh: (swallowErrors: boolean, contentShorten: boolean) => React.ComponentType<any> } {
|
||||
return {
|
||||
Component,
|
||||
// In order to replace the default component during runtime we can provide a RenderFn to create a new 'plugged' component
|
||||
render: (createComponent: RenderFn): React.ComponentType<any> => {
|
||||
return renderHelper(createComponent, defaultProps);
|
||||
},
|
||||
// In order to modify the parameters which are used to render the default component, we can use this method
|
||||
refresh: (swallowErrors: boolean, contentShorten: boolean): React.ComponentType<any> => {
|
||||
return renderHelper(
|
||||
(value: any): React.ReactNode => valueToText(type, value, swallowErrors, contentShorten),
|
||||
defaultProps
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps ({ value }: Props): Pick<State, never> {
|
||||
const Component = Query.getCachedComponent(value).Component;
|
||||
const Component = getCachedComponent(value).Component;
|
||||
const inputs: React.ReactNode[] = isU8a(value.key)
|
||||
? []
|
||||
// FIXME We need to render the actual key params
|
||||
@ -149,12 +149,12 @@ class Query extends React.PureComponent<Props, State> {
|
||||
public render (): React.ReactNode {
|
||||
const { className, value } = this.props;
|
||||
const { Component } = this.state;
|
||||
const { isConst, key } = value;
|
||||
const { id, isConst, key } = value;
|
||||
const type = isConst
|
||||
? (key as unknown as ConstValue).meta.type.toString()
|
||||
: isU8a(key)
|
||||
? 'Data'
|
||||
: Query.typeToString(key as StorageEntryPromise);
|
||||
: typeToString(key as StorageEntryPromise);
|
||||
|
||||
if (!Component) {
|
||||
return null;
|
||||
@ -166,7 +166,7 @@ class Query extends React.PureComponent<Props, State> {
|
||||
<Labelled
|
||||
label={
|
||||
<div className='ui--Param-text'>
|
||||
{Query.keyToName(isConst, key)}: {type}
|
||||
{keyToName(isConst, key)}: {type}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
@ -175,45 +175,25 @@ class Query extends React.PureComponent<Props, State> {
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<div className='container'>
|
||||
{this.renderButtons()}
|
||||
{(key as StorageEntryPromise).creator && (key as StorageEntryPromise).creator.meta && ['Bytes', 'Data'].includes((key as StorageEntryPromise).creator.meta.type.toString()) && (
|
||||
<Button
|
||||
icon='ellipsis horizontal'
|
||||
key='spread'
|
||||
onClick={this.spreadHandler(id)}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
icon='close'
|
||||
isNegative
|
||||
key='close'
|
||||
onClick={this.onRemove}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderButtons (): React.ReactNode {
|
||||
const { id, key } = this.props.value as StorageModuleQuery;
|
||||
|
||||
const buttons = [
|
||||
<Button
|
||||
icon='close'
|
||||
isNegative
|
||||
key='close'
|
||||
onClick={this.onRemove}
|
||||
/>
|
||||
];
|
||||
|
||||
if (key.creator && key.creator.meta && ['Bytes', 'Data'].includes(key.creator.meta.type.toString())) {
|
||||
// TODO We are currently not performing a copy
|
||||
// buttons.unshift(
|
||||
// <Button
|
||||
// icon='copy'
|
||||
// onClick={this.copyHandler(id)}
|
||||
// />
|
||||
// );
|
||||
buttons.unshift(
|
||||
<Button
|
||||
icon='ellipsis horizontal'
|
||||
key='spread'
|
||||
onClick={this.spreadHandler(id)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private spreadHandler (id: number): () => void {
|
||||
return (): void => {
|
||||
const { spread } = this.state;
|
||||
@ -238,20 +218,22 @@ class Query extends React.PureComponent<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(styled(Query as React.ComponentClass<Props>)`
|
||||
margin-bottom: 0.25em;
|
||||
export default translate(
|
||||
styled(Query as React.ComponentClass<Props>)`
|
||||
margin-bottom: 0.25em;
|
||||
|
||||
label {
|
||||
text-transform: none !important;
|
||||
}
|
||||
label {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.ui.disabled.dropdown.selection {
|
||||
color: #aaa;
|
||||
opacity: 1;
|
||||
}
|
||||
.ui.disabled.dropdown.selection {
|
||||
color: #aaa;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ui--IdentityIcon {
|
||||
margin: -10px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
`);
|
||||
.ui--IdentityIcon {
|
||||
margin: -10px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
@ -2,96 +2,67 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { TabItem } from '@polkadot/react-components/Tabs';
|
||||
import { ComponentProps, QueryTypes, ParitalQueryTypes } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { Route, Switch } from 'react-router';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import { Tabs } from '@polkadot/react-components';
|
||||
import { withApi } from '@polkadot/react-api';
|
||||
|
||||
import Consts from './Consts';
|
||||
import Modules from './Modules';
|
||||
import Raw from './Raw';
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
basePath: string;
|
||||
onAdd: (query: QueryTypes) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
items: TabItem[];
|
||||
}
|
||||
|
||||
let id = -1;
|
||||
|
||||
class Selection extends React.PureComponent<Props, State> {
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
function Selection ({ basePath, onAdd, t }: Props): React.ReactElement<Props> {
|
||||
const { isSubstrateV2 } = useContext(ApiContext);
|
||||
const _onAdd = (query: ParitalQueryTypes): void => onAdd({ ...query, id: ++id });
|
||||
const _renderComponent = (Component: React.ComponentType<ComponentProps>): () => React.ReactNode =>
|
||||
// eslint-disable-next-line react/display-name
|
||||
(): React.ReactNode => <Component onAdd={_onAdd} />;
|
||||
|
||||
const { t } = this.props;
|
||||
|
||||
this.state = {
|
||||
items: [
|
||||
{
|
||||
isRoot: true,
|
||||
name: 'modules',
|
||||
text: t('Storage')
|
||||
},
|
||||
{
|
||||
name: 'constants',
|
||||
text: t('Constants')
|
||||
},
|
||||
{
|
||||
name: 'raw',
|
||||
text: t('Raw storage')
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { basePath, isSubstrateV2 } = this.props;
|
||||
const { items } = this.state;
|
||||
const hidden = isSubstrateV2 ? [] : ['constants'];
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
hidden={hidden}
|
||||
items={items}
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/constants`} render={this.renderComponent(Consts)} />
|
||||
<Route path={`${basePath}/raw`} render={this.renderComponent(Raw)} />
|
||||
<Route render={this.renderComponent(Modules)} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private renderComponent (Component: React.ComponentType<ComponentProps>): () => React.ReactNode {
|
||||
return (): React.ReactNode => {
|
||||
return (
|
||||
<Component onAdd={this.onAdd} />
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
private onAdd = (query: ParitalQueryTypes): void => {
|
||||
const { onAdd } = this.props;
|
||||
|
||||
onAdd({
|
||||
...query,
|
||||
id: ++id
|
||||
});
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<Tabs
|
||||
basePath={basePath}
|
||||
hidden={
|
||||
isSubstrateV2
|
||||
? []
|
||||
: ['constants']
|
||||
}
|
||||
items={[
|
||||
{
|
||||
isRoot: true,
|
||||
name: 'modules',
|
||||
text: t('Storage')
|
||||
},
|
||||
{
|
||||
name: 'constants',
|
||||
text: t('Constants')
|
||||
},
|
||||
{
|
||||
name: 'raw',
|
||||
text: t('Raw storage')
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</header>
|
||||
<Switch>
|
||||
<Route path={`${basePath}/constants`} render={_renderComponent(Consts)} />
|
||||
<Route path={`${basePath}/raw`} render={_renderComponent(Raw)} />
|
||||
<Route render={_renderComponent(Modules)} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(withApi(Selection));
|
||||
export default translate(Selection);
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ConstantCodec } from '@polkadot/api-metadata/consts/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { DropdownOptions } from '../util/types';
|
||||
import { I18nProps } from '../types';
|
||||
import { ConstValue, ConstValueBase } from './types';
|
||||
|
||||
import '../InputExtrinsic/InputExtrinsic.css';
|
||||
|
||||
import React from 'react';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
|
||||
import Labelled from '../Labelled';
|
||||
import translate from '../translate';
|
||||
@ -20,7 +20,7 @@ import SelectSection from './SelectSection';
|
||||
import keyOptions from './options/key';
|
||||
import sectionOptions from './options/section';
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
defaultValue: ConstValueBase;
|
||||
help?: React.ReactNode;
|
||||
isError?: boolean;
|
||||
@ -29,104 +29,75 @@ interface Props extends ApiProps, I18nProps {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
optionsMethod: DropdownOptions;
|
||||
optionsSection: DropdownOptions;
|
||||
value: ConstValue;
|
||||
function getValue (api: ApiPromise, { method, section }: ConstValueBase): ConstValue {
|
||||
const firstSec = Object.keys(api.consts)[0];
|
||||
const firstMet = Object.keys(api.consts[firstSec])[0];
|
||||
const value = (api.consts[section] && api.consts[section][method])
|
||||
? { method, section }
|
||||
: { method: firstMet, section: firstSec };
|
||||
|
||||
return {
|
||||
...value,
|
||||
meta: (api.consts[value.section][value.method] as ConstantCodec).meta
|
||||
};
|
||||
}
|
||||
|
||||
class InputConsts extends React.PureComponent<Props, State> {
|
||||
public state: State;
|
||||
function InputConsts ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(keyOptions(api, defaultValue.section));
|
||||
const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
|
||||
const [value, setValue] = useState<ConstValue>(getValue(api, defaultValue));
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { api, defaultValue: { method, section } } = this.props;
|
||||
const firstSec = Object.keys(api.consts)[0];
|
||||
const firstMet = Object.keys(api.consts[firstSec])[0];
|
||||
const value = (api.consts[section] && api.consts[section][method])
|
||||
? { method, section }
|
||||
: { method: firstMet, section: firstSec };
|
||||
|
||||
this.state = {
|
||||
optionsMethod: keyOptions(api, section),
|
||||
optionsSection: sectionOptions(api),
|
||||
value: {
|
||||
...value,
|
||||
meta: (api.consts[value.section][value.method] as ConstantCodec).meta
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, help, label, style, withLabel } = this.props;
|
||||
const { optionsMethod, optionsSection, value } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={this.onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectKey
|
||||
className='large'
|
||||
onChange={this.onKeyChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onKeyChange = (newValue: ConstValueBase): void => {
|
||||
const { api, onChange } = this.props;
|
||||
const { value: saveValue } = this.state;
|
||||
|
||||
if (saveValue.section === newValue.section && saveValue.method === newValue.method) {
|
||||
const _onKeyChange = (newValue: ConstValueBase): void => {
|
||||
if (value.section === newValue.section && value.method === newValue.method) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { method, section } = newValue;
|
||||
const meta = (api.consts[section][method] as ConstantCodec).meta;
|
||||
const value = { meta, method, section };
|
||||
const updated = { meta, method, section };
|
||||
|
||||
this.setState({ value }, (): void =>
|
||||
onChange && onChange(value)
|
||||
);
|
||||
}
|
||||
|
||||
private onSectionChange = (newSection: string): void => {
|
||||
const { api } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (newSection === value.section) {
|
||||
setValue(updated);
|
||||
onChange && onChange(updated);
|
||||
};
|
||||
const _onSectionChange = (section: string): void => {
|
||||
if (section === value.section) {
|
||||
return;
|
||||
}
|
||||
|
||||
const optionsMethod = keyOptions(api, newSection);
|
||||
const newValue = { method: optionsMethod[0].value, section: newSection };
|
||||
const optionsMethod = keyOptions(api, section);
|
||||
|
||||
this.setState({ optionsMethod }, (): void =>
|
||||
this.onKeyChange(newValue)
|
||||
);
|
||||
}
|
||||
setOptionsMethod(optionsMethod);
|
||||
_onKeyChange({ method: optionsMethod[0].value, section });
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={_onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectKey
|
||||
className='large'
|
||||
onChange={_onKeyChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
InputConsts,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(InputConsts);
|
||||
|
||||
@ -3,14 +3,13 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { CallFunction } from '@polkadot/types/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '../types';
|
||||
import { DropdownOptions } from '../util/types';
|
||||
|
||||
import './InputExtrinsic.css';
|
||||
|
||||
import React from 'react';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
|
||||
import Labelled from '../Labelled';
|
||||
import translate from '../translate';
|
||||
@ -19,7 +18,7 @@ import SelectSection from './SelectSection';
|
||||
import methodOptions from './options/method';
|
||||
import sectionOptions from './options/section';
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
defaultValue: CallFunction;
|
||||
help?: React.ReactNode;
|
||||
isDisabled?: boolean;
|
||||
@ -30,96 +29,60 @@ interface Props extends ApiProps, I18nProps {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
optionsMethod?: DropdownOptions;
|
||||
optionsSection?: DropdownOptions;
|
||||
value: CallFunction;
|
||||
}
|
||||
|
||||
class InputExtrinsic extends React.PureComponent<Props, State> {
|
||||
public state: State;
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
value: this.props.defaultValue
|
||||
};
|
||||
}
|
||||
|
||||
public static getDerivedStateFromProps ({ api }: Props, { value }: State): Pick<State, never> {
|
||||
return {
|
||||
optionsMethod: methodOptions(api, value.section),
|
||||
optionsSection: sectionOptions(api)
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { api, className, help, label, style, withLabel } = this.props;
|
||||
const { optionsMethod, optionsSection, value } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={this.onSectionChange}
|
||||
options={optionsSection || []}
|
||||
value={value}
|
||||
/>
|
||||
<SelectMethod
|
||||
api={api}
|
||||
className='large'
|
||||
onChange={this.onKeyChange}
|
||||
options={optionsMethod || []}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onKeyChange = (newValue: CallFunction): void => {
|
||||
const { onChange } = this.props;
|
||||
const { value } = this.state;
|
||||
function InputExtrinsic ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(methodOptions(api, defaultValue.section));
|
||||
const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
|
||||
const [value, setValue] = useState<CallFunction>((): CallFunction => defaultValue);
|
||||
|
||||
const _onKeyChange = (newValue: CallFunction): void => {
|
||||
if (value.section === newValue.section && value.method === newValue.method) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ value: newValue }, (): void =>
|
||||
onChange(newValue)
|
||||
);
|
||||
}
|
||||
|
||||
private onSectionChange = (newSection: string): void => {
|
||||
const { api } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (newSection === value.section) {
|
||||
// set this via callback, since the we are setting a function (aletrnatively... we have issues)
|
||||
setValue((): CallFunction => newValue);
|
||||
onChange(newValue);
|
||||
};
|
||||
const _onSectionChange = (section: string): void => {
|
||||
if (section === value.section) {
|
||||
return;
|
||||
}
|
||||
|
||||
const optionsMethod = methodOptions(api, newSection);
|
||||
const fn = api.tx[newSection][optionsMethod[0].value];
|
||||
const optionsMethod = methodOptions(api, section);
|
||||
|
||||
this.setState({ optionsMethod }, (): void =>
|
||||
this.onKeyChange(fn)
|
||||
);
|
||||
}
|
||||
setOptionsMethod(optionsMethod);
|
||||
_onKeyChange(api.tx[section][optionsMethod[0].value]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={_onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectMethod
|
||||
api={api}
|
||||
className='large'
|
||||
onChange={_onKeyChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
InputExtrinsic,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(InputExtrinsic);
|
||||
|
||||
@ -5,15 +5,14 @@
|
||||
// TODO: We have a lot shared between this and InputExtrinsic & InputStorage
|
||||
|
||||
import { RpcMethod } from '@polkadot/jsonrpc/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { DropdownOptions } from '../util/types';
|
||||
import { I18nProps } from '../types';
|
||||
|
||||
import '../InputExtrinsic/InputExtrinsic.css';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import map from '@polkadot/jsonrpc';
|
||||
import { withApi } from '@polkadot/react-api';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
|
||||
import Labelled from '../Labelled';
|
||||
import translate from '../translate';
|
||||
@ -22,7 +21,7 @@ import SelectSection from './SelectSection';
|
||||
import methodOptions from './options/method';
|
||||
import sectionOptions from './options/section';
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
defaultValue: RpcMethod;
|
||||
help?: React.ReactNode;
|
||||
isError?: boolean;
|
||||
@ -31,88 +30,59 @@ interface Props extends ApiProps, I18nProps {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
optionsMethod: DropdownOptions;
|
||||
optionsSection: DropdownOptions;
|
||||
value: RpcMethod;
|
||||
}
|
||||
|
||||
class InputRpc extends React.PureComponent<Props, State> {
|
||||
public state: State;
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { section } = this.props.defaultValue;
|
||||
|
||||
this.state = {
|
||||
optionsMethod: methodOptions(props.api, section),
|
||||
optionsSection: sectionOptions(props.api),
|
||||
value: this.props.defaultValue
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, help, label, style, withLabel } = this.props;
|
||||
const { optionsMethod, optionsSection, value } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={this.onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectMethod
|
||||
className='large'
|
||||
onChange={this.onMethodChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onMethodChange = (newValue: RpcMethod): void => {
|
||||
const { onChange } = this.props;
|
||||
const { value } = this.state;
|
||||
function InputRpc ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(methodOptions(api, defaultValue.section));
|
||||
const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
|
||||
const [value, setValue] = useState<RpcMethod>((): RpcMethod => defaultValue);
|
||||
|
||||
const _onMethodChange = (newValue: RpcMethod): void => {
|
||||
if (value.section === newValue.section && value.method === newValue.method) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ value: newValue }, (): void =>
|
||||
onChange && onChange(newValue)
|
||||
);
|
||||
}
|
||||
|
||||
private onSectionChange = (newSection: string): void => {
|
||||
const { api } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (newSection === value.section) {
|
||||
// set via callback since the method is a function itself
|
||||
setValue((): RpcMethod => newValue);
|
||||
onChange && onChange(newValue);
|
||||
};
|
||||
const _onSectionChange = (section: string): void => {
|
||||
if (section === value.section) {
|
||||
return;
|
||||
}
|
||||
|
||||
const optionsMethod = methodOptions(api, newSection);
|
||||
const newValue = map[newSection].methods[optionsMethod[0].value];
|
||||
const optionsMethod = methodOptions(api, section);
|
||||
|
||||
this.setState({ optionsMethod }, (): void =>
|
||||
this.onMethodChange(newValue)
|
||||
);
|
||||
}
|
||||
setOptionsMethod(optionsMethod);
|
||||
_onMethodChange(map[section].methods[optionsMethod[0].value]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={_onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectMethod
|
||||
className='large'
|
||||
onChange={_onMethodChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(withApi(InputRpc));
|
||||
export default translate(InputRpc);
|
||||
|
||||
@ -4,15 +4,14 @@
|
||||
|
||||
// TODO: We have a lot shared between this and InputExtrinsic
|
||||
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { StorageEntryPromise } from '@polkadot/api/types';
|
||||
import { DropdownOptions } from '../util/types';
|
||||
import { I18nProps } from '../types';
|
||||
|
||||
import '../InputExtrinsic/InputExtrinsic.css';
|
||||
|
||||
import React from 'react';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
|
||||
import Labelled from '../Labelled';
|
||||
import translate from '../translate';
|
||||
@ -21,7 +20,7 @@ import SelectSection from './SelectSection';
|
||||
import keyOptions from './options/key';
|
||||
import sectionOptions from './options/section';
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
defaultValue: StorageEntryPromise;
|
||||
help?: React.ReactNode;
|
||||
isError?: boolean;
|
||||
@ -30,92 +29,59 @@ interface Props extends ApiProps, I18nProps {
|
||||
withLabel?: boolean;
|
||||
}
|
||||
|
||||
interface State {
|
||||
optionsMethod: DropdownOptions;
|
||||
optionsSection: DropdownOptions;
|
||||
value: StorageEntryPromise;
|
||||
}
|
||||
|
||||
class InputStorage extends React.PureComponent<Props, State> {
|
||||
public state: State;
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { api, defaultValue: { creator: { method, section } } } = this.props;
|
||||
|
||||
this.state = {
|
||||
optionsMethod: keyOptions(api, section),
|
||||
optionsSection: sectionOptions(api),
|
||||
value: api.query[section][method]
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { className, help, label, style, withLabel } = this.props;
|
||||
const { optionsMethod, optionsSection, value } = this.state;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={this.onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectKey
|
||||
className='large'
|
||||
onChange={this.onKeyChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onKeyChange = (newValue: StorageEntryPromise): void => {
|
||||
const { onChange } = this.props;
|
||||
const { value } = this.state;
|
||||
function InputStorage ({ className, defaultValue, help, label, onChange, style, withLabel }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [optionsMethod, setOptionsMethod] = useState<DropdownOptions>(keyOptions(api, defaultValue.creator.section));
|
||||
const [optionsSection] = useState<DropdownOptions>(sectionOptions(api));
|
||||
const [value, setValue] = useState<StorageEntryPromise>((): StorageEntryPromise => defaultValue);
|
||||
|
||||
const _onKeyChange = (newValue: StorageEntryPromise): void => {
|
||||
if (value.creator.section === newValue.creator.section && value.creator.method === newValue.creator.method) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ value: newValue }, (): void =>
|
||||
onChange && onChange(newValue)
|
||||
);
|
||||
}
|
||||
|
||||
private onSectionChange = (newSection: string): void => {
|
||||
const { api } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
if (newSection === value.creator.section) {
|
||||
// set via callback
|
||||
setValue((): StorageEntryPromise => newValue);
|
||||
onChange && onChange(newValue);
|
||||
};
|
||||
const _onSectionChange = (section: string): void => {
|
||||
if (section === value.creator.section) {
|
||||
return;
|
||||
}
|
||||
|
||||
const optionsMethod = keyOptions(api, newSection);
|
||||
const newValue = api.query[newSection][optionsMethod[0].value];
|
||||
const optionsMethod = keyOptions(api, section);
|
||||
|
||||
this.setState({ optionsMethod }, (): void =>
|
||||
this.onKeyChange(newValue)
|
||||
);
|
||||
}
|
||||
setOptionsMethod(optionsMethod);
|
||||
_onKeyChange(api.query[section][optionsMethod[0].value]);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<Labelled
|
||||
help={help}
|
||||
label={label}
|
||||
withLabel={withLabel}
|
||||
>
|
||||
<div className=' ui--DropdownLinked ui--row'>
|
||||
<SelectSection
|
||||
className='small'
|
||||
onChange={_onSectionChange}
|
||||
options={optionsSection}
|
||||
value={value}
|
||||
/>
|
||||
<SelectKey
|
||||
className='large'
|
||||
onChange={_onKeyChange}
|
||||
options={optionsMethod}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
</Labelled>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
InputStorage,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(InputStorage);
|
||||
|
||||
@ -3,16 +3,15 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { DerivedFees, DerivedBalances, DerivedContractFees } from '@polkadot/api-derive/types';
|
||||
import { IExtrinsic } from '@polkadot/types/types';
|
||||
import { ExtraFees } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import React, { useContext, useState, useEffect } from 'react';
|
||||
import { Compact, UInt } from '@polkadot/types';
|
||||
import { withCalls } from '@polkadot/react-api';
|
||||
import { ApiContext, withCalls } from '@polkadot/react-api';
|
||||
import { Icon } from '@polkadot/react-components';
|
||||
import { compactToU8a, formatBalance } from '@polkadot/util';
|
||||
|
||||
@ -23,7 +22,7 @@ import Proposal from './Proposal';
|
||||
import Transfer from './Transfer';
|
||||
import { MAX_SIZE_BYTES, MAX_SIZE_MB, ZERO_BALANCE, ZERO_FEES_BALANCES, ZERO_FEES_CONTRACT } from './constants';
|
||||
|
||||
interface State extends ExtraFees {
|
||||
interface State {
|
||||
allFees: BN;
|
||||
allTotal: BN;
|
||||
allWarn: boolean;
|
||||
@ -35,7 +34,7 @@ interface State extends ExtraFees {
|
||||
overLimit: boolean;
|
||||
}
|
||||
|
||||
interface Props extends ApiProps, I18nProps {
|
||||
interface Props extends I18nProps {
|
||||
balances_fees?: DerivedFees;
|
||||
balances_all?: DerivedBalances;
|
||||
contract_fees?: DerivedContractFees;
|
||||
@ -65,23 +64,26 @@ export const calcTxLength = (extrinsic?: IExtrinsic | null, nonce?: BN, tip?: BN
|
||||
);
|
||||
};
|
||||
|
||||
export class FeeDisplay extends React.PureComponent<Props, State> {
|
||||
public state: State = {
|
||||
export function FeeDisplay ({ accountId, balances_all = ZERO_BALANCE, balances_fees = ZERO_FEES_BALANCES, className, contract_fees = ZERO_FEES_CONTRACT, extrinsic, isSendable, onChange, system_accountNonce = ZERO, t, tip }: Props): React.ReactElement<Props> | null {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [state, setState] = useState<State>({
|
||||
allFees: ZERO,
|
||||
allTotal: ZERO,
|
||||
allWarn: false,
|
||||
extraAmount: ZERO,
|
||||
extraFees: ZERO,
|
||||
extraWarn: false,
|
||||
hasAvailable: false,
|
||||
isRemovable: false,
|
||||
isReserved: false,
|
||||
overLimit: false
|
||||
};
|
||||
});
|
||||
const [extra, setExtra] = useState<ExtraFees>({
|
||||
extraAmount: ZERO,
|
||||
extraFees: ZERO,
|
||||
extraWarn: false
|
||||
});
|
||||
|
||||
public static getDerivedStateFromProps ({ accountId, balances_all = ZERO_BALANCE, api, extrinsic, balances_fees = ZERO_FEES_BALANCES, system_accountNonce = ZERO, tip }: Props, prevState: State): State | null {
|
||||
useEffect((): void => {
|
||||
if (!accountId || !extrinsic) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
const fn = api.findCall(extrinsic.callIndex);
|
||||
@ -89,15 +91,15 @@ export class FeeDisplay extends React.PureComponent<Props, State> {
|
||||
const extSection = fn.section;
|
||||
const txLength = calcTxLength(extrinsic, system_accountNonce, tip);
|
||||
|
||||
const isSameExtrinsic = prevState.extMethod === extMethod && prevState.extSection === extSection;
|
||||
const isSameExtrinsic = state.extMethod === extMethod && state.extSection === extSection;
|
||||
const extraAmount = isSameExtrinsic
|
||||
? prevState.extraAmount
|
||||
? extra.extraAmount
|
||||
: ZERO;
|
||||
const extraFees = isSameExtrinsic
|
||||
? prevState.extraFees
|
||||
? extra.extraFees
|
||||
: ZERO;
|
||||
const extraWarn = isSameExtrinsic
|
||||
? prevState.extraWarn
|
||||
? extra.extraWarn
|
||||
: false;
|
||||
const allFees = extraFees
|
||||
.add(balances_fees.transactionBaseFee)
|
||||
@ -110,185 +112,142 @@ export class FeeDisplay extends React.PureComponent<Props, State> {
|
||||
const allWarn = extraWarn;
|
||||
const overLimit = txLength.gten(MAX_SIZE_BYTES);
|
||||
|
||||
return {
|
||||
(hasAvailable !== state.hasAvailable) && onChange && onChange(hasAvailable);
|
||||
|
||||
setExtra({
|
||||
extraAmount,
|
||||
extraFees,
|
||||
extraWarn
|
||||
});
|
||||
setState({
|
||||
allFees,
|
||||
allTotal,
|
||||
allWarn,
|
||||
extMethod,
|
||||
extSection,
|
||||
extraAmount,
|
||||
extraFees,
|
||||
extraWarn,
|
||||
hasAvailable,
|
||||
isRemovable,
|
||||
isReserved,
|
||||
overLimit
|
||||
};
|
||||
});
|
||||
}, [accountId, balances_all, extrinsic, balances_fees, system_accountNonce, tip]);
|
||||
|
||||
if (!accountId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public componentDidUpdate (): void {
|
||||
const { onChange } = this.props;
|
||||
const { hasAvailable } = this.state;
|
||||
const { allFees, allTotal, allWarn, extMethod, extSection, hasAvailable, isRemovable, isReserved, overLimit } = state;
|
||||
const feeClass = !hasAvailable || overLimit || isRemovable
|
||||
? 'error'
|
||||
: allWarn
|
||||
? 'warning'
|
||||
: 'normal';
|
||||
|
||||
onChange && onChange(hasAvailable);
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { accountId, balances_fees, className, isSendable, t } = this.props;
|
||||
const { allFees, allTotal, allWarn, hasAvailable, isRemovable, isReserved, overLimit } = this.state;
|
||||
|
||||
if (!accountId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const feeClass = !hasAvailable || overLimit || isRemovable
|
||||
? 'error'
|
||||
: allWarn
|
||||
? 'warning'
|
||||
: 'normal';
|
||||
|
||||
// display all the errors, warning and information messages (in that order)
|
||||
return (
|
||||
<article
|
||||
className={[className, feeClass, 'padded'].join(' ')}
|
||||
key='txinfo'
|
||||
>
|
||||
{
|
||||
isSendable
|
||||
? undefined
|
||||
: <div><Icon name='ban' />{t('The selected account does not exist on your keyring')}</div>
|
||||
}
|
||||
{
|
||||
hasAvailable
|
||||
? undefined
|
||||
: <div><Icon name='ban' />{t('The selected account does not have the required balance available for this transaction')}</div>
|
||||
}
|
||||
{
|
||||
overLimit
|
||||
? <div><Icon name='ban' />{t(`This transaction will be rejected by the node as it is greater than the maximum size of ${MAX_SIZE_MB}MB`)}</div>
|
||||
: undefined
|
||||
}
|
||||
{
|
||||
isRemovable && hasAvailable
|
||||
? (
|
||||
<div>
|
||||
<Icon name='ban' />
|
||||
{t('Submitting this transaction will drop the account balance to below the existential amount ({{existentialDeposit}}), which can result in the account being removed from the chain state and its associated funds burned.',
|
||||
{
|
||||
replace: {
|
||||
existentialDeposit: formatBalance(balances_fees && balances_fees.existentialDeposit)
|
||||
}
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
: undefined
|
||||
}
|
||||
{this.renderTransfer()}
|
||||
{this.renderProposal()}
|
||||
{this.renderCall()}
|
||||
{this.renderDeploy()}
|
||||
{
|
||||
isReserved
|
||||
? <div><Icon name='arrow right' />{t('This account does have a reserved/locked balance, not taken into account')}</div>
|
||||
: undefined
|
||||
}
|
||||
<div><Icon name='arrow right' />{t('Fees includes the transaction fee and the per-byte fee')}</div>
|
||||
<div><Icon name='arrow right' />{t('Fees totalling {{fees}} will be applied to the submission', {
|
||||
// display all the errors, warning and information messages (in that order)
|
||||
return (
|
||||
<article
|
||||
className={[className, feeClass, 'padded'].join(' ')}
|
||||
key='txinfo'
|
||||
>
|
||||
{isSendable && (
|
||||
<div>
|
||||
<Icon name='ban' />
|
||||
{t('The selected account does not exist on your keyring')}
|
||||
</div>
|
||||
)}
|
||||
{!hasAvailable && (
|
||||
<div>
|
||||
<Icon name='ban' />
|
||||
{t('The selected account does not have the required balance available for this transaction')}
|
||||
</div>
|
||||
)}
|
||||
{overLimit && (
|
||||
<div>
|
||||
<Icon name='ban' />
|
||||
{t(`This transaction will be rejected by the node as it is greater than the maximum size of ${MAX_SIZE_MB}MB`)}
|
||||
</div>
|
||||
)}
|
||||
{isRemovable && hasAvailable && balances_fees && (
|
||||
<div>
|
||||
<Icon name='ban' />
|
||||
{t('Submitting this transaction will drop the account balance to below the existential amount ({{existentialDeposit}}), which can result in the account being removed from the chain state and its associated funds burned.',
|
||||
{
|
||||
replace: {
|
||||
existentialDeposit: formatBalance(balances_fees.existentialDeposit)
|
||||
}
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{balances_fees && extrinsic && (
|
||||
<>
|
||||
{(extSection === 'balances' && extMethod === 'transfer') && (
|
||||
<Transfer
|
||||
amount={extrinsic.args[1]}
|
||||
fees={balances_fees}
|
||||
recipientId={extrinsic.args[0]}
|
||||
onChange={setExtra}
|
||||
/>
|
||||
)}
|
||||
{(extSection === 'democracy' && extMethod === 'propose') && (
|
||||
<Proposal
|
||||
deposit={extrinsic.args[1]}
|
||||
fees={balances_fees}
|
||||
onChange={setExtra}
|
||||
/>
|
||||
)}
|
||||
{(extSection === 'contract') && (
|
||||
<>
|
||||
{(extMethod === 'call') && (
|
||||
<ContractCall
|
||||
endowment={extrinsic.args[1] as unknown as Compact<UInt>}
|
||||
fees={contract_fees}
|
||||
onChange={setExtra}
|
||||
/>
|
||||
)}
|
||||
{(extMethod === 'create') && (
|
||||
<ContractDeploy
|
||||
endowment={extrinsic.args[0] as unknown as Compact<UInt>}
|
||||
fees={contract_fees}
|
||||
onChange={setExtra}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{isReserved && (
|
||||
<div>
|
||||
<Icon name='arrow right' />
|
||||
{t('This account does have a reserved/locked balance, not taken into account')}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Icon name='arrow right' />
|
||||
{t('Fees includes the transaction fee and the per-byte fee')}
|
||||
</div>
|
||||
<div>
|
||||
<Icon name='arrow right' />
|
||||
{t('Fees totalling {{fees}} will be applied to the submission', {
|
||||
replace: {
|
||||
fees: formatBalance(allFees)
|
||||
}
|
||||
})}</div>
|
||||
<div><Icon name='arrow right' />{t('{{total}} estimated total amount (fees + value)', {
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Icon name='arrow right' />
|
||||
{t('{{total}} estimated total amount (fees + value)', {
|
||||
replace: {
|
||||
total: formatBalance(allTotal)
|
||||
}
|
||||
})}</div>
|
||||
<div><Icon name='dot circle outline' />{t('Estimation does not account for the transaction weight')}</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
private renderProposal (): React.ReactNode {
|
||||
const { extrinsic, balances_fees } = this.props;
|
||||
const { extMethod, extSection } = this.state;
|
||||
|
||||
if (!balances_fees || !extrinsic || extSection !== 'democracy' || extMethod !== 'propose') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [, deposit] = extrinsic.args;
|
||||
|
||||
return (
|
||||
<Proposal
|
||||
deposit={deposit}
|
||||
fees={balances_fees}
|
||||
onChange={this.onExtraUpdate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderTransfer (): React.ReactNode {
|
||||
const { extrinsic, balances_fees } = this.props;
|
||||
const { extMethod, extSection } = this.state;
|
||||
|
||||
if (!balances_fees || !extrinsic || extSection !== 'balances' || extMethod !== 'transfer') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [recipientId, amount] = extrinsic.args;
|
||||
|
||||
return (
|
||||
<Transfer
|
||||
amount={amount}
|
||||
fees={balances_fees}
|
||||
recipientId={recipientId}
|
||||
onChange={this.onExtraUpdate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderCall (): React.ReactNode {
|
||||
const { extrinsic, contract_fees = ZERO_FEES_CONTRACT } = this.props;
|
||||
const { extMethod, extSection } = this.state;
|
||||
|
||||
if (!contract_fees || !extrinsic || extSection !== 'contract' || extMethod !== 'call') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [, endowment] = extrinsic.args;
|
||||
|
||||
return (
|
||||
<ContractCall
|
||||
endowment={endowment as unknown as Compact<UInt>}
|
||||
fees={contract_fees}
|
||||
onChange={this.onExtraUpdate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderDeploy (): React.ReactNode {
|
||||
const { extrinsic, contract_fees = ZERO_FEES_CONTRACT } = this.props;
|
||||
const { extMethod, extSection } = this.state;
|
||||
|
||||
if (!contract_fees || !extrinsic || extSection !== 'contract' || extMethod !== 'create') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [endowment] = extrinsic.args;
|
||||
|
||||
return (
|
||||
<ContractDeploy
|
||||
endowment={endowment as unknown as Compact<UInt>}
|
||||
fees={contract_fees}
|
||||
onChange={this.onExtraUpdate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private onExtraUpdate = (extra: ExtraFees): void => {
|
||||
this.setState({ ...extra });
|
||||
}
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Icon name='dot circle outline' />
|
||||
{t('Estimation does not account for the transaction weight')}
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user