withApi -> useContext (fixes ref issues) (#1576)
This commit is contained in:
parent
596615a51c
commit
52ab9ac0e3
@ -3,12 +3,11 @@
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { Health, PeerInfo, Extrinsic } from '@polkadot/types/interfaces';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { AppProps, I18nProps } from '@polkadot/react-components/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { Info } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import { Vec } from '@polkadot/types';
|
||||
|
||||
import './index.css';
|
||||
@ -20,73 +19,19 @@ import translate from './translate';
|
||||
|
||||
const POLL_TIMEOUT = 9900;
|
||||
|
||||
type Props = ApiProps & AppProps & I18nProps;
|
||||
type Props = I18nProps;
|
||||
|
||||
interface State {
|
||||
info?: Info;
|
||||
nextRefresh: number;
|
||||
timerId?: number;
|
||||
}
|
||||
function NodeInfo ({ t }: Props): React.ReactElement<Props> {
|
||||
const { api } = useContext(ApiContext);
|
||||
const [info, setInfo] = useState<Partial<Info>>({});
|
||||
const [nextRefresh, setNextRefresh] = useState(Date.now());
|
||||
const [timerId, setTimerId] = useState(0);
|
||||
|
||||
class App extends React.PureComponent<Props, State> {
|
||||
private isActive = true;
|
||||
|
||||
public state: State = {
|
||||
nextRefresh: Date.now()
|
||||
const executeStatus = (): void => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
getStatus().catch((): void => {});
|
||||
};
|
||||
|
||||
public componentDidMount (): void {
|
||||
this.getStatus().catch((): void => {
|
||||
// ignore
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount (): void {
|
||||
const { timerId } = this.state;
|
||||
|
||||
this.isActive = false;
|
||||
|
||||
if (timerId) {
|
||||
window.clearTimeout(timerId);
|
||||
}
|
||||
}
|
||||
|
||||
public render (): React.ReactNode {
|
||||
const { t } = this.props;
|
||||
const { info = {}, nextRefresh } = this.state;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Summary
|
||||
info={info}
|
||||
nextRefresh={nextRefresh}
|
||||
/>
|
||||
<Peers peers={info.peers} />
|
||||
<Extrinsics
|
||||
blockNumber={info.blockNumber}
|
||||
label={t('pending extrinsics')}
|
||||
value={info.extrinsics}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private setInfo (info?: Info): void {
|
||||
if (!this.isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
info,
|
||||
nextRefresh: (Date.now() + POLL_TIMEOUT),
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
timerId: window.setTimeout(this.getStatus, POLL_TIMEOUT)
|
||||
});
|
||||
}
|
||||
|
||||
private getStatus = async (): Promise<void> => {
|
||||
const { api } = this.props;
|
||||
|
||||
const getStatus = async (): Promise<void> => {
|
||||
try {
|
||||
const [blockNumber, health, peers, extrinsics] = await Promise.all([
|
||||
api.derive.chain.bestNumber(),
|
||||
@ -95,15 +40,37 @@ class App extends React.PureComponent<Props, State> {
|
||||
api.rpc.author.pendingExtrinsics<Vec<Extrinsic>>()
|
||||
]);
|
||||
|
||||
this.setInfo({ blockNumber, extrinsics, health, peers });
|
||||
setInfo({ blockNumber, extrinsics, health, peers });
|
||||
} catch (error) {
|
||||
this.setInfo();
|
||||
setInfo({});
|
||||
}
|
||||
}
|
||||
|
||||
setNextRefresh(Date.now() + POLL_TIMEOUT);
|
||||
setTimerId(window.setTimeout(executeStatus, POLL_TIMEOUT));
|
||||
};
|
||||
|
||||
useEffect((): () => void => {
|
||||
executeStatus();
|
||||
|
||||
return (): void => {
|
||||
window.clearTimeout(timerId);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Summary
|
||||
info={info}
|
||||
nextRefresh={nextRefresh}
|
||||
/>
|
||||
<Peers peers={info.peers} />
|
||||
<Extrinsics
|
||||
blockNumber={info.blockNumber}
|
||||
label={t('pending extrinsics')}
|
||||
value={info.extrinsics}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
App,
|
||||
translate,
|
||||
withApi
|
||||
);
|
||||
export default translate(NodeInfo);
|
||||
|
||||
@ -2,68 +2,57 @@
|
||||
// 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 { BareProps } from '@polkadot/react-components/types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withApi } from '@polkadot/react-api/with';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import { NodeName, NodeVersion } from '@polkadot/react-query';
|
||||
|
||||
interface Props extends ApiProps, BareProps {}
|
||||
type Props = BareProps;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const pkgJson = require('../../package.json');
|
||||
|
||||
const uiInfo = `apps v${pkgJson.version}`;
|
||||
|
||||
function renderNode ({ isApiReady }: Props): React.ReactNode {
|
||||
if (!isApiReady) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<NodeName />
|
||||
<NodeVersion label='v' />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NodeInfo (props: Props): React.ReactElement<Props> {
|
||||
const { api, className } = props;
|
||||
function NodeInfo ({ className }: Props): React.ReactElement<Props> {
|
||||
const { api, isApiReady } = useContext(ApiContext);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{renderNode(props)}
|
||||
{isApiReady && (
|
||||
<div>
|
||||
<NodeName />
|
||||
<NodeVersion label='v' />
|
||||
</div>
|
||||
)}
|
||||
<div>{api.libraryInfo.replace('@polkadot/', '')}</div>
|
||||
<div>{uiInfo}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default withApi(
|
||||
styled(NodeInfo)`
|
||||
background: transparent;
|
||||
color: white;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.5;
|
||||
padding: 0 1.5rem 0 1.5rem;
|
||||
text-align: right;
|
||||
export default styled(NodeInfo)`
|
||||
background: transparent;
|
||||
color: white;
|
||||
font-size: 0.75rem;
|
||||
opacity: 0.5;
|
||||
padding: 0 1.5rem 0 1.5rem;
|
||||
text-align: right;
|
||||
|
||||
> div {
|
||||
margin-bottom: -0.125em;
|
||||
> div {
|
||||
margin-bottom: -0.125em;
|
||||
> div {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&.spacer {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.rx--updated {
|
||||
background: inherit !important;
|
||||
&.spacer {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
.rx--updated {
|
||||
background: inherit !important;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -2,18 +2,18 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
import { ApiProps } from '@polkadot/react-api/types';
|
||||
import { I18nProps } from '@polkadot/react-components/types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
import settings from '@polkadot/ui-settings';
|
||||
|
||||
import translate from '../translate';
|
||||
import BaseOverlay from './Base';
|
||||
|
||||
type Props = I18nProps & ApiProps;
|
||||
type Props = I18nProps;
|
||||
|
||||
const isFirefox = typeof (window as any).InstallTrigger !== 'undefined';
|
||||
const wsUrl = settings.apiUrl;
|
||||
@ -21,7 +21,7 @@ const isWs = wsUrl.startsWith('ws://');
|
||||
const isWsRemote = wsUrl.includes('127.0.0.1');
|
||||
const isHttps = window.location.protocol.startsWith('https:');
|
||||
|
||||
function renderExtension ({ className, isWaitingInjected, t }: Props): React.ReactNode {
|
||||
function ExtensionOverlay ({ className, isWaitingInjected, t }: ApiProps & Props): React.ReactElement<Props> | null {
|
||||
if (!isWaitingInjected) {
|
||||
return null;
|
||||
}
|
||||
@ -36,7 +36,7 @@ function renderExtension ({ className, isWaitingInjected, t }: Props): React.Rea
|
||||
);
|
||||
}
|
||||
|
||||
function renderConnecting ({ className, isApiConnected, t }: Props): React.ReactNode {
|
||||
function ConnectOverlay ({ className, isApiConnected, t }: ApiProps & Props): React.ReactElement<Props> | null {
|
||||
if (isApiConnected) {
|
||||
return null;
|
||||
}
|
||||
@ -61,20 +61,16 @@ function renderConnecting ({ className, isApiConnected, t }: Props): React.React
|
||||
);
|
||||
}
|
||||
|
||||
function Connecting (props: Props): React.ReactElement<Props> {
|
||||
return (
|
||||
<>
|
||||
{renderExtension(props) || renderConnecting(props)}
|
||||
</>
|
||||
);
|
||||
function Connecting (props: Props): React.ReactElement<Props> | null {
|
||||
const api = useContext(ApiContext);
|
||||
|
||||
return <ExtensionOverlay {...props} {...api} /> || <ConnectOverlay {...props} {...api} />;
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
export default translate(
|
||||
styled(Connecting)`
|
||||
background: #ffe6e6;
|
||||
border-color: #c00;
|
||||
color: #4d0000;
|
||||
`,
|
||||
translate,
|
||||
withApi
|
||||
`
|
||||
);
|
||||
|
||||
@ -28,11 +28,12 @@ function AddressCard (props: Props): React.ReactElement<Props> {
|
||||
{...props}
|
||||
className='ui--AddressCard-AddressRow'
|
||||
/>
|
||||
{withExplorer && (
|
||||
{withExplorer && value && (
|
||||
<div className='ui--AddressCard-explorer'>
|
||||
<LinkPolkascan
|
||||
className='ui--AddressCard-exporer-link'
|
||||
data={value}
|
||||
data={value.toString()}
|
||||
type='address'
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -2,22 +2,21 @@
|
||||
// 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 './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { withApi, withMulti } from '@polkadot/react-api';
|
||||
import { ApiContext } from '@polkadot/react-api';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
export type LinkTypes = 'address' | 'block' | 'extrinsic';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
interface Props extends I18nProps {
|
||||
className?: string;
|
||||
data: string;
|
||||
type: LinkTypes;
|
||||
};
|
||||
}
|
||||
|
||||
const BASE = 'https://polkascan.io/pre/';
|
||||
|
||||
@ -33,7 +32,8 @@ const TYPES: Record<string, string> = {
|
||||
extrinsic: '/system/extrinsic/'
|
||||
};
|
||||
|
||||
function LinkPolkascan ({ className, currentChain, data, t, type }: Props): React.ReactElement<Props> | null {
|
||||
function LinkPolkascan ({ className, data, t, type }: Props): React.ReactElement<Props> | null {
|
||||
const { currentChain } = useContext(ApiContext);
|
||||
const extChain = CHAINS[currentChain];
|
||||
const extType = TYPES[type];
|
||||
|
||||
@ -54,11 +54,9 @@ function LinkPolkascan ({ className, currentChain, data, t, type }: Props): Reac
|
||||
);
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
export default translate(
|
||||
styled(LinkPolkascan)`
|
||||
margin-top: 1rem;
|
||||
text-align: right;
|
||||
`,
|
||||
translate,
|
||||
withApi
|
||||
`
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user