Rework query components (no refs) (#1688)
* Rework query components (no refs) * Fix raw storage queries * Alphabetical
This commit is contained in:
parent
4f2c1f679e
commit
69bc18d053
@ -2,20 +2,20 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { RenderFn, DefaultProps, ComponentRenderer } from '@polkadot/react-api/with/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ConstValue } from '@polkadot/react-components/InputConsts/types';
|
||||
import { QueryTypes, StorageEntryPromise, StorageModuleQuery } from './types';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Compact } from '@polkadot/types';
|
||||
import { Button, Labelled } from '@polkadot/react-components';
|
||||
import { withCallDiv } from '@polkadot/react-api';
|
||||
import valueToText from '@polkadot/react-params/valueToText';
|
||||
import { Compact, Data, Option } from '@polkadot/types';
|
||||
import { isU8a, u8aToHex, u8aToString } from '@polkadot/util';
|
||||
|
||||
import translate from './translate';
|
||||
import { RenderFn, DefaultProps, ComponentRenderer } from '@polkadot/react-api/with/types';
|
||||
import { ConstValue } from '@polkadot/react-components/InputConsts/types';
|
||||
|
||||
interface Props extends I18nProps {
|
||||
onRemove: (id: number) => void;
|
||||
@ -65,16 +65,14 @@ function createComponent (type: string, Component: React.ComponentType<any>, def
|
||||
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);
|
||||
},
|
||||
render: (createComponent: RenderFn): React.ComponentType<any> =>
|
||||
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(
|
||||
refresh: (swallowErrors: boolean, contentShorten: boolean): React.ComponentType<any> =>
|
||||
renderHelper(
|
||||
(value: any): React.ReactNode => valueToText(type, value, swallowErrors, contentShorten),
|
||||
defaultProps
|
||||
);
|
||||
}
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@ -93,12 +91,23 @@ function getCachedComponent (query: QueryTypes): CacheInstance {
|
||||
} 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]
|
||||
});
|
||||
if (isU8a(key)) {
|
||||
// subscribe to the raw key here
|
||||
renderHelper = withCallDiv('rpc.state.subscribeStorage', {
|
||||
paramName: 'params',
|
||||
paramValid: true,
|
||||
params: [[key]],
|
||||
transform: ([data]: Option<Data>[]): Option<Data> => data
|
||||
});
|
||||
} else {
|
||||
// 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';
|
||||
|
||||
@ -5,84 +5,54 @@
|
||||
import { ConstantCodec } from '@polkadot/api-metadata/consts/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ConstValue } from '@polkadot/react-components/InputConsts/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { ComponentProps } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { Button, InputConsts, TxComponent } from '@polkadot/react-components';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import { Button, InputConsts } from '@polkadot/react-components';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends ComponentProps, ApiProps, I18nProps {}
|
||||
interface Props extends ComponentProps, I18nProps {}
|
||||
|
||||
interface State {
|
||||
value: ConstValue;
|
||||
}
|
||||
|
||||
class Consts extends TxComponent<Props, State> {
|
||||
private defaultValue: ConstValue;
|
||||
|
||||
public state: State;
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { api } = this.props;
|
||||
function Consts ({ onAdd, t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [defaultValue] = useState<ConstValue>((): ConstValue => {
|
||||
const section = Object.keys(api.consts)[0];
|
||||
const method = Object.keys(api.consts[section])[0];
|
||||
|
||||
this.defaultValue = {
|
||||
return {
|
||||
meta: (api.consts[section][method] as ConstantCodec).meta,
|
||||
method,
|
||||
section
|
||||
};
|
||||
this.state = {
|
||||
value: this.defaultValue
|
||||
};
|
||||
}
|
||||
});
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { api, t } = this.props;
|
||||
const { value: { method, section } } = this.state;
|
||||
const meta = (api.consts[section][method] as ConstantCodec).meta;
|
||||
const _onAdd = (): void => onAdd({ isConst: true, key: value });
|
||||
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<InputConsts
|
||||
defaultValue={this.defaultValue}
|
||||
label={t('selected constant query')}
|
||||
onChange={this.onChangeConst}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isPrimary
|
||||
onClick={this.onAdd}
|
||||
ref={this.button}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
const { method, section } = value;
|
||||
const meta = (api.consts[section][method] as ConstantCodec).meta;
|
||||
|
||||
private onAdd = (): void => {
|
||||
const { onAdd } = this.props;
|
||||
const { value } = this.state;
|
||||
|
||||
onAdd({ isConst: true, key: value });
|
||||
}
|
||||
|
||||
private onChangeConst = (value: ConstValue): void => {
|
||||
this.setState({ value });
|
||||
}
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<InputConsts
|
||||
defaultValue={defaultValue}
|
||||
label={t('selected constant query')}
|
||||
onChange={setValue}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isPrimary
|
||||
onClick={_onAdd}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Consts,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(Consts);
|
||||
|
||||
@ -5,181 +5,115 @@
|
||||
import { TypeDef } from '@polkadot/types/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { RawParams } from '@polkadot/react-params/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { ComponentProps, StorageEntryPromise } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { getTypeDef } from '@polkadot/types';
|
||||
import { Button, InputStorage, TxComponent } from '@polkadot/react-components';
|
||||
import { Button, InputStorage } from '@polkadot/react-components';
|
||||
import Params from '@polkadot/react-params';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import { isNull, isUndefined } from '@polkadot/util';
|
||||
|
||||
import translate from '../translate';
|
||||
|
||||
interface Props extends ComponentProps, ApiProps, I18nProps {}
|
||||
interface Props extends ComponentProps, I18nProps {}
|
||||
|
||||
interface State {
|
||||
isLinked: boolean;
|
||||
isValid: boolean;
|
||||
key: StorageEntryPromise;
|
||||
defaultValues?: RawParams | null;
|
||||
values: RawParams;
|
||||
params: { type: TypeDef }[];
|
||||
type ParamsType = { type: TypeDef }[];
|
||||
|
||||
function areParamsValid (values: RawParams): boolean {
|
||||
return values.reduce(
|
||||
(isValid: boolean, value): boolean => (
|
||||
isValid &&
|
||||
!isUndefined(value) &&
|
||||
!isUndefined(value.value) &&
|
||||
value.isValid),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
class Modules extends TxComponent<Props, State> {
|
||||
private defaultValue: any;
|
||||
function Modules ({ onAdd, t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [{ defaultValues, isLinked, key, params }, setKey] = useState<{ defaultValues: RawParams | undefined | null; isLinked: boolean; key: StorageEntryPromise; params: ParamsType }>({ defaultValues: undefined, isLinked: false, key: api.query.timestamp.now, params: [] });
|
||||
const [{ isValid, values }, setValues] = useState<{ isValid: boolean; values: RawParams }>({ isValid: true, values: [] });
|
||||
|
||||
public state: State;
|
||||
|
||||
public constructor (props: Props) {
|
||||
super(props);
|
||||
|
||||
const { api } = this.props;
|
||||
|
||||
this.defaultValue = api.query.timestamp.now;
|
||||
this.state = {
|
||||
isLinked: false,
|
||||
isValid: true,
|
||||
key: this.defaultValue,
|
||||
values: [],
|
||||
params: []
|
||||
};
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { t } = this.props;
|
||||
const { isValid, key: { creator: { method, section, meta } }, defaultValues, params } = this.state;
|
||||
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<InputStorage
|
||||
defaultValue={this.defaultValue}
|
||||
label={t('selected state query')}
|
||||
onChange={this.onChangeKey}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
<Params
|
||||
key={`${section}.${method}:params` /* force re-render on change */}
|
||||
onChange={this.onChangeParams}
|
||||
onEnter={this.submit}
|
||||
params={params}
|
||||
values={defaultValues}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={this.onAdd}
|
||||
ref={this.button}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
private nextState (newState: Partial<State>): void {
|
||||
this.setState(
|
||||
(prevState: State): Pick<State, never> => {
|
||||
const { key = prevState.key, values = prevState.values } = newState;
|
||||
|
||||
const areParamsValid = (): boolean => {
|
||||
return values.reduce(
|
||||
(isValid: boolean, value): boolean => (
|
||||
isValid &&
|
||||
!isUndefined(value) &&
|
||||
!isUndefined(value.value) &&
|
||||
value.isValid),
|
||||
true
|
||||
);
|
||||
};
|
||||
|
||||
if (key.creator.meta.type.isDoubleMap) {
|
||||
const key1 = key.creator.meta.type.asDoubleMap.key1.toString();
|
||||
const key2 = key.creator.meta.type.asDoubleMap.key2.toString();
|
||||
|
||||
return {
|
||||
defaultValues: this.getDefaultValues(),
|
||||
isValid: values.length === 2 && areParamsValid(),
|
||||
key,
|
||||
params: [
|
||||
{ type: getTypeDef(key1) },
|
||||
{ type: getTypeDef(key2) }
|
||||
],
|
||||
values
|
||||
};
|
||||
}
|
||||
|
||||
const isMap = key.creator.meta.type.isMap;
|
||||
const isLinked = isMap && key.creator.meta.type.asMap.linked.isTrue;
|
||||
const isValid = values.length === (isMap ? 1 : 0) && areParamsValid();
|
||||
|
||||
return {
|
||||
defaultValues: null,
|
||||
isLinked,
|
||||
isValid,
|
||||
key,
|
||||
params: isMap
|
||||
? [{
|
||||
type: getTypeDef(
|
||||
isLinked
|
||||
? `Option<${key.creator.meta.type.asMap.key.toString()}>`
|
||||
: key.creator.meta.type.asMap.key.toString()
|
||||
)
|
||||
}]
|
||||
: [],
|
||||
values
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private getDefaultValues = (): RawParams | null => {
|
||||
const { api } = this.props;
|
||||
const { key } = this.state;
|
||||
|
||||
if (key.creator.section === 'session') {
|
||||
return [
|
||||
{
|
||||
isValid: true,
|
||||
value: api.consts.session.dedupKeyPrefix.toHex()
|
||||
}
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private onAdd = (): void => {
|
||||
const { onAdd } = this.props;
|
||||
const { isLinked, key, values } = this.state;
|
||||
|
||||
onAdd({
|
||||
const _onAdd = (): void => {
|
||||
isValid && onAdd({
|
||||
isConst: false,
|
||||
key,
|
||||
params: values.filter(({ value }): boolean => !isLinked || !isNull(value))
|
||||
});
|
||||
}
|
||||
|
||||
private onChangeKey = (key: StorageEntryPromise): void => {
|
||||
this.nextState({
|
||||
isValid: false,
|
||||
key,
|
||||
values: [],
|
||||
params: []
|
||||
};
|
||||
const _onChangeValues = (values: RawParams): void => {
|
||||
setValues({
|
||||
isValid: (
|
||||
key.creator.meta.type.isDoubleMap
|
||||
? values.length === 2
|
||||
: values.length === (key.creator.meta.type.isMap ? 1 : 0)
|
||||
) && areParamsValid(values),
|
||||
values
|
||||
});
|
||||
}
|
||||
};
|
||||
const _onChangeKey = (key: StorageEntryPromise): void => {
|
||||
const isMap = key.creator.meta.type.isMap;
|
||||
const isLinked = isMap && key.creator.meta.type.asMap.linked.isTrue;
|
||||
|
||||
private onChangeParams = (values: RawParams = []): void => {
|
||||
this.nextState({ values });
|
||||
}
|
||||
setKey({
|
||||
defaultValues: key.creator.section === 'session'
|
||||
? [{
|
||||
isValid: true,
|
||||
value: api.consts.session.dedupKeyPrefix.toHex()
|
||||
}]
|
||||
: null,
|
||||
isLinked,
|
||||
key,
|
||||
params: key.creator.meta.type.isDoubleMap
|
||||
? [
|
||||
{ type: getTypeDef(key.creator.meta.type.asDoubleMap.key1.toString()) },
|
||||
{ type: getTypeDef(key.creator.meta.type.asDoubleMap.key2.toString()) }
|
||||
]
|
||||
: isMap
|
||||
? [{
|
||||
type: getTypeDef(
|
||||
isLinked
|
||||
? `Option<${key.creator.meta.type.asMap.key.toString()}>`
|
||||
: key.creator.meta.type.asMap.key.toString()
|
||||
)
|
||||
}]
|
||||
: []
|
||||
});
|
||||
|
||||
_onChangeValues([]);
|
||||
};
|
||||
|
||||
const { creator: { method, section, meta } } = key;
|
||||
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<InputStorage
|
||||
defaultValue={api.query.timestamp.now}
|
||||
label={t('selected state query')}
|
||||
onChange={_onChangeKey}
|
||||
help={meta && meta.documentation && meta.documentation.join(' ')}
|
||||
/>
|
||||
<Params
|
||||
key={`${section}.${method}:params` /* force re-render on change */}
|
||||
onChange={_onChangeValues}
|
||||
onEnter={_onAdd}
|
||||
params={params}
|
||||
values={defaultValues}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={_onAdd}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Modules,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(Modules);
|
||||
|
||||
@ -5,8 +5,8 @@
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ComponentProps } from '../types';
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Input, TxComponent } from '@polkadot/react-components';
|
||||
import React, { useState } from 'react';
|
||||
import { Button, Input } from '@polkadot/react-components';
|
||||
|
||||
import translate from '../translate';
|
||||
import { u8aToU8a } from '@polkadot/util';
|
||||
@ -14,60 +14,42 @@ import { Compact } from '@polkadot/types';
|
||||
|
||||
interface Props extends ComponentProps, I18nProps {}
|
||||
|
||||
interface State {
|
||||
isValid: boolean;
|
||||
key: Uint8Array;
|
||||
}
|
||||
function Raw ({ onAdd, t }: Props): React.ReactElement<Props> {
|
||||
const [{ isValid, key }, setValue] = useState<{ isValid: boolean; key: Uint8Array }>({ isValid: false, key: new Uint8Array([]) });
|
||||
|
||||
class Raw extends TxComponent<Props, State> {
|
||||
public state: State = {
|
||||
isValid: false,
|
||||
key: new Uint8Array([])
|
||||
const _onAdd = (): void => {
|
||||
isValid && onAdd({ isConst: false, key });
|
||||
};
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { t } = this.props;
|
||||
const { isValid } = this.state;
|
||||
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<Input
|
||||
autoFocus
|
||||
label={t('hex-encoded storage key')}
|
||||
onChange={this.onChangeKey}
|
||||
onEnter={this.submit}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={this.onAdd}
|
||||
ref={this.button}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
private onAdd = (): void => {
|
||||
const { onAdd } = this.props;
|
||||
const { key } = this.state;
|
||||
|
||||
onAdd({ isConst: false, key });
|
||||
}
|
||||
|
||||
private onChangeKey = (key: string): void => {
|
||||
const _onChangeKey = (key: string): void => {
|
||||
const u8a = u8aToU8a(key);
|
||||
const isValid = u8a.length !== 0;
|
||||
|
||||
this.setState({
|
||||
setValue({
|
||||
isValid,
|
||||
key: Compact.addLengthPrefix(u8a)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className='storage--actionrow'>
|
||||
<div className='storage--actionrow-value'>
|
||||
<Input
|
||||
autoFocus
|
||||
label={t('hex-encoded storage key')}
|
||||
onChange={_onChangeKey}
|
||||
onEnter={_onAdd}
|
||||
/>
|
||||
</div>
|
||||
<div className='storage--actionrow-buttons'>
|
||||
<Button
|
||||
icon='plus'
|
||||
isDisabled={!isValid}
|
||||
isPrimary
|
||||
onClick={_onAdd}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default translate(Raw);
|
||||
|
||||
@ -18,7 +18,7 @@ interface Props extends AppProps, I18nProps {}
|
||||
function StorageApp ({ basePath }: Props): React.ReactElement<Props> {
|
||||
const [queue, setQueue] = useState<QueryTypes[]>([]);
|
||||
|
||||
const _onAdd = (query: QueryTypes): void => setQueue([query].concat(queue));
|
||||
const _onAdd = (query: QueryTypes): void => setQueue([query, ...queue]);
|
||||
const _onRemove = (id: number): void => setQueue(queue.filter((item): boolean => item.id !== id));
|
||||
|
||||
return (
|
||||
|
||||
Loading…
Reference in New Issue
Block a user