API cleanups (#2139)

* API cleanups

* Revert ready setting

* ... oops

* Adjust dropdown right margin

* API -> functional
This commit is contained in:
Jaco Greeff 2020-01-17 13:04:41 +01:00 committed by GitHub
parent f95cb193ce
commit e9de3cf489
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 91 additions and 155 deletions

View File

@ -245,7 +245,6 @@ export default styled(Playground)`
}
.js--Dropdown {
margin-right: 100px;
position: relative;
z-index: 200;

View File

@ -2,14 +2,12 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { ProviderInterface } from '@polkadot/rpc-provider/types';
import { QueueTxPayloadAdd, QueueTxMessageSetStatus } from '@polkadot/react-components/Status/types';
import { ApiProps } from './types';
import { ApiState } from './types';
import React from 'react';
import React, { useEffect, useState } from 'react';
import ApiPromise from '@polkadot/api/promise';
import { isWeb3Injected, web3Accounts, web3Enable } from '@polkadot/extension-dapp';
import defaults from '@polkadot/rpc-provider/defaults';
import { WsProvider } from '@polkadot/rpc-provider';
import { TokenUnit } from '@polkadot/react-components/InputNumber';
import keyring from '@polkadot/ui-keyring';
@ -31,7 +29,7 @@ interface Props {
url?: string;
}
interface State extends ApiProps {
interface State extends ApiState {
chain?: string | null;
}
@ -50,163 +48,100 @@ let api: ApiPromise;
export { api };
export default class Api extends React.PureComponent<Props, State> {
public state: State = {} as unknown as State;
async function loadOnReady (api: ApiPromise): Promise<State> {
const [properties, _systemChain, _systemName, _systemVersion, injectedAccounts] = await Promise.all([
api.rpc.system.properties(),
api.rpc.system.chain(),
api.rpc.system.name(),
api.rpc.system.version(),
web3Accounts().then((accounts): InjectedAccountExt[] =>
accounts.map(({ address, meta }): InjectedAccountExt => ({
address,
meta: {
...meta,
name: `${meta.name} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})`
}
}))
)
]);
const ss58Format = uiSettings.prefix === -1
? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber()
: uiSettings.prefix;
const tokenSymbol = properties.tokenSymbol.unwrapOr('DEV').toString();
const tokenDecimals = properties.tokenDecimals.unwrapOr(DEFAULT_DECIMALS).toNumber();
const systemChain = _systemChain
? _systemChain.toString()
: '<unknown>';
const isDevelopment = isTestChain(systemChain);
constructor (props: Props) {
super(props);
console.log('api: found chain', systemChain, JSON.stringify(properties));
const { queuePayload, queueSetTxStatus, url } = props;
// first setup the UI helpers
formatBalance.setDefaults({
decimals: tokenDecimals,
unit: tokenSymbol
});
TokenUnit.setAbbr(tokenSymbol);
// finally load the keyring
keyring.loadAll({
addressPrefix: ss58Format,
genesisHash: api.genesisHash,
isDevelopment,
ss58Format,
type: 'ed25519'
}, injectedAccounts);
const defaultSection = Object.keys(api.tx)[0];
const defaultMethod = Object.keys(api.tx[defaultSection])[0];
const apiDefaultTx = api.tx[defaultSection][defaultMethod];
const apiDefaultTxSudo = (api.tx.system && api.tx.system.setCode) || apiDefaultTx;
const isSubstrateV2 = !!Object.keys(api.consts).length;
return {
apiDefaultTx,
apiDefaultTxSudo,
isApiReady: true,
isDevelopment,
isSubstrateV2,
systemChain,
systemName: _systemName.toString(),
systemVersion: _systemVersion.toString()
} as State;
}
export default function Api ({ children, queuePayload, queueSetTxStatus, url }: Props): React.ReactElement<Props> | null {
const [state, setState] = useState<State>({ isApiReady: false } as Partial<State> as State);
const [isApiConnected, setIsApiConnected] = useState(false);
const [isWaitingInjected, setIsWaitingInjected] = useState(isWeb3Injected);
// initial initialization
useEffect((): void => {
const provider = new WsProvider(url);
const signer = new ApiSigner(queuePayload, queueSetTxStatus);
const setApi = (provider: ProviderInterface): void => {
api = this.createApi(provider, signer);
this.setState({ api }, (): void => {
this.subscribeEvents();
});
};
const setApiUrl = (url: string = defaults.WS_URL): void =>
setApi(new WsProvider(url));
api = this.createApi(provider, signer);
this.state = {
api,
isApiConnected: false,
isApiReady: false,
isSubstrateV2: true,
isWaitingInjected: isWeb3Injected,
setApiUrl
} as unknown as State;
}
private createApi (provider: ProviderInterface, signer: ApiSigner): ApiPromise {
return new ApiPromise({
provider,
registry,
signer,
typesChain,
typesSpec
});
}
public componentDidMount (): void {
this.subscribeEvents();
injectedPromise
.then((): void => this.setState({ isWaitingInjected: false }))
.catch((error: Error) => console.error(error));
}
private subscribeEvents (): void {
const { api } = this.state;
api.on('connected', (): void => {
this.setState({ isApiConnected: true });
});
api.on('disconnected', (): void => {
this.setState({ isApiConnected: false });
});
api = new ApiPromise({ provider, registry, signer, typesChain, typesSpec });
api.on('connected', (): void => setIsApiConnected(true));
api.on('disconnected', (): void => setIsApiConnected(false));
api.on('ready', async (): Promise<void> => {
try {
await this.loadOnReady(api);
setState(await loadOnReady(api));
} catch (error) {
console.error('Unable to load chain', error);
}
});
}
private async loadOnReady (api: ApiPromise): Promise<void> {
const [properties, _systemChain, _systemName, _systemVersion, injectedAccounts] = await Promise.all([
api.rpc.system.properties(),
api.rpc.system.chain(),
api.rpc.system.name(),
api.rpc.system.version(),
web3Accounts().then((accounts): InjectedAccountExt[] =>
accounts.map(({ address, meta }): InjectedAccountExt => ({
address,
meta: {
...meta,
name: `${meta.name} (${meta.source === 'polkadot-js' ? 'extension' : meta.source})`
}
}))
)
]);
const ss58Format = uiSettings.prefix === -1
? properties.ss58Format.unwrapOr(DEFAULT_SS58).toNumber()
: uiSettings.prefix;
const tokenSymbol = properties.tokenSymbol.unwrapOr('DEV').toString();
const tokenDecimals = properties.tokenDecimals.unwrapOr(DEFAULT_DECIMALS).toNumber();
const systemChain = _systemChain
? _systemChain.toString()
: '<unknown>';
const isDevelopment = isTestChain(systemChain);
injectedPromise
.then((): void => setIsWaitingInjected(false))
.catch((error: Error) => console.error(error));
}, []);
console.log('api: found chain', systemChain, JSON.stringify(properties));
// first setup the UI helpers
formatBalance.setDefaults({
decimals: tokenDecimals,
unit: tokenSymbol
});
TokenUnit.setAbbr(tokenSymbol);
// finally load the keyring
keyring.loadAll({
addressPrefix: ss58Format,
genesisHash: api.genesisHash,
isDevelopment,
ss58Format,
type: 'ed25519'
}, injectedAccounts);
const defaultSection = Object.keys(api.tx)[0];
const defaultMethod = Object.keys(api.tx[defaultSection])[0];
const apiDefaultTx = api.tx[defaultSection][defaultMethod];
const apiDefaultTxSudo =
(api.tx.system && api.tx.system.setCode) || // 2.x
(api.tx.consensus && api.tx.consensus.setCode) || // 1.x
apiDefaultTx; // other
const isSubstrateV2 = !!Object.keys(api.consts).length;
this.setState({
apiDefaultTx,
apiDefaultTxSudo,
isApiReady: true,
isDevelopment,
isSubstrateV2,
systemChain,
systemName: _systemName.toString(),
systemVersion: _systemVersion.toString()
});
}
public render (): React.ReactNode {
const { api, apiDefaultTx, apiDefaultTxSudo, isApiConnected, isApiReady, isDevelopment, isSubstrateV2, isWaitingInjected, setApiUrl, systemChain, systemName, systemVersion } = this.state;
return (
<ApiContext.Provider
value={{
api,
apiDefaultTx,
apiDefaultTxSudo,
isApiConnected,
isApiReady: isApiReady && !!systemChain,
isDevelopment,
isSubstrateV2,
isWaitingInjected,
setApiUrl,
systemChain,
systemName,
systemVersion
}}
>
{this.props.children}
return api
? (
<ApiContext.Provider value={{ ...state, api, isApiConnected, isWaitingInjected }}>
{children}
</ApiContext.Provider>
);
}
)
: null;
}

View File

@ -15,21 +15,23 @@ export interface BareProps {
style?: Record<string, any>;
}
export interface ApiProps {
api: ApiPromise;
export interface ApiState {
apiDefaultTx: SubmittableExtrinsicFunction;
apiDefaultTxSudo: SubmittableExtrinsicFunction;
isApiConnected: boolean;
isApiReady: boolean;
isDevelopment: boolean;
isSubstrateV2: boolean;
isWaitingInjected: boolean;
setApiUrl: (url?: string) => void;
systemChain: string;
systemName: string;
systemVersion: string;
}
export interface ApiProps extends ApiState {
api: ApiPromise;
isWaitingInjected: boolean;
isApiConnected: boolean;
}
export interface OnChangeCbObs {
next: (value?: any) => any;
}