diff --git a/packages/app-explorer/src/NodeInfo/Peers.tsx b/packages/app-explorer/src/NodeInfo/Peers.tsx index 21a7bba92c..abb0b317fa 100644 --- a/packages/app-explorer/src/NodeInfo/Peers.tsx +++ b/packages/app-explorer/src/NodeInfo/Peers.tsx @@ -27,42 +27,37 @@ const renderPeer = (peer: PeerInfo): React.ReactNode => { ); }; -const renderPeers = ({ peers, t }: Props): React.ReactNode => { - if (!peers || !peers.length) { - return ( -
- {t('no peers connected')} -
- ); - } - - return ( -
- - - - - - - - - - - {peers - .sort((a, b): number => b.bestNumber.cmp(a.bestNumber)) - .map(renderPeer) - } - -
{t('role')}{t('peer id')}{t('best #')}{t('best hash')}
-
- ); -}; - -function Peers (props: Props): React.ReactElement { +function Peers ({ peers, t }: Props): React.ReactElement { return (
-

{props.t('connected peers')}

- {renderPeers(props)} +

{t('connected peers')}

+ {peers && peers.length + ? ( +
+ + + + + + + + + + + {peers + .sort((a, b): number => b.bestNumber.cmp(a.bestNumber)) + .map(renderPeer) + } + +
{t('role')}{t('peer id')}{t('best #')}{t('best hash')}
+
+ ) + : ( +
+ {t('no peers connected')} +
+ ) + }
); } diff --git a/packages/app-explorer/src/NodeInfo/Summary.tsx b/packages/app-explorer/src/NodeInfo/Summary.tsx index 6b3cd751cd..3fd8f1396c 100644 --- a/packages/app-explorer/src/NodeInfo/Summary.tsx +++ b/packages/app-explorer/src/NodeInfo/Summary.tsx @@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/react-components/types'; import { Info } from './types'; import BN from 'bn.js'; -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { SummaryBox, CardSummary } from '@polkadot/react-components'; import { formatNumber } from '@polkadot/util'; import { BestNumber, Elapsed } from '@polkadot/react-query'; @@ -18,82 +18,76 @@ interface Props extends I18nProps { info: Info; } -interface State { - peerBest?: BN; -} +const ZERO = new BN(0); +const EMPTY_INFO = { extrinsics: null, health: null, peers: null }; -class Summary extends React.PureComponent { - public state: State = {}; +function Summary ({ info: { extrinsics, health, peers } = EMPTY_INFO, nextRefresh, t }: Props): React.ReactElement { + const [peerBest, setPeerBest] = useState(ZERO); - public static getDerivedStateFromProps ({ info = {} }: Props): State | null { - if (!info.peers) { - return null; + useEffect((): void => { + if (!peers) { + return; } - const bestPeer = info.peers.sort((a, b): number => b.bestNumber.cmp(a.bestNumber))[0]; + const bestPeer = peers.sort((a, b): number => b.bestNumber.cmp(a.bestNumber))[0]; - return { - peerBest: bestPeer + setPeerBest( + bestPeer ? bestPeer.bestNumber : new BN(0) - }; - } - - public render (): React.ReactNode { - const { info = {}, nextRefresh, t } = this.props; - const { peerBest } = this.state; - - return ( - -
- - - - - { - info.health - ? `${info.health.peers.toNumber()}` - : '-' - } - - - { - info.health - ? ( - info.health.isSyncing.valueOf() - ? t('yes') - : t('no') - ) - : '-' - } - -
-
- - { - info.extrinsics - ? `${info.extrinsics.length}` - : '-' - } - -
-
- - {formatNumber(peerBest)} - - - - -
-
); - } + }, [peers]); + + return ( + +
+ + + + + { + health + ? `${health.peers.toNumber()}` + : '-' + } + + + { + health + ? ( + health.isSyncing.valueOf() + ? t('yes') + : t('no') + ) + : '-' + } + +
+
+ + { + extrinsics + ? `${extrinsics.length}` + : '-' + } + +
+
+ + {formatNumber(peerBest)} + + + + +
+
+ ); } export default translate(Summary); diff --git a/packages/app-explorer/src/NodeInfo/index.tsx b/packages/app-explorer/src/NodeInfo/index.tsx index e3c16c768d..8478e0a89a 100644 --- a/packages/app-explorer/src/NodeInfo/index.tsx +++ b/packages/app-explorer/src/NodeInfo/index.tsx @@ -37,26 +37,21 @@ function NodeInfo ({ t }: Props): React.ReactElement { const { api } = useContext(ApiContext); const [info, setInfo] = useState>({}); const [nextRefresh, setNextRefresh] = useState(Date.now()); - const [timerId, setTimerId] = useState(0); - - const executeStatus = (isFirstRun = false): void => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - getStatus(isFirstRun).catch((): void => {}); - }; - const getStatus = async (isFirstRun: boolean): Promise => { - if (isFirstRun || timerId) { - setInfo(await retrieveInfo(api)); - setNextRefresh(Date.now() + POLL_TIMEOUT); - setTimerId(window.setTimeout(executeStatus, POLL_TIMEOUT)); - } - }; useEffect((): () => void => { - executeStatus(true); + const _getStatus = (): void => { + retrieveInfo(api).then(setInfo); + }; + + _getStatus(); + + const timerId = window.setInterval((): void => { + setNextRefresh(Date.now() + POLL_TIMEOUT); + _getStatus(); + }, POLL_TIMEOUT); return (): void => { - window.clearTimeout(timerId); - setTimerId(0); + window.clearInterval(timerId); }; }, []); diff --git a/packages/app-explorer/src/NodeInfo/types.ts b/packages/app-explorer/src/NodeInfo/types.ts index 11017acb33..ae3350bfdd 100644 --- a/packages/app-explorer/src/NodeInfo/types.ts +++ b/packages/app-explorer/src/NodeInfo/types.ts @@ -8,7 +8,7 @@ import { Vec } from '@polkadot/types'; export interface Info { blockNumber?: BlockNumber; + extrinsics?: Vec | null; health?: Health | null; peers?: PeerInfo[] | null; - extrinsics?: Vec | null; } diff --git a/packages/app-js/src/ActionButtons.tsx b/packages/app-js/src/ActionButtons.tsx index f26f99ccb4..47893d315f 100644 --- a/packages/app-js/src/ActionButtons.tsx +++ b/packages/app-js/src/ActionButtons.tsx @@ -4,7 +4,7 @@ import { BareProps, I18nProps } from '@polkadot/react-components/types'; -import React from 'react'; +import React, { useState } from 'react'; import styled from 'styled-components'; import { Button as SUIB, Popup } from 'semantic-ui-react'; import { Button, Input } from '@polkadot/react-components'; @@ -22,135 +22,114 @@ interface Props extends BareProps, I18nProps { stopJs: () => void; } -interface State { - isOpen: boolean; - shareText: string; - snippetName: string; -} +function ActionButtons ({ className, generateLink, isCustomExample, isRunning, removeSnippet, runJs, saveSnippet, stopJs, t }: Props): React.ReactElement { + const [isOpen, setIsOpen] = useState(false); + const [shareText, setShareText] = useState(t('Generate link to share code example')); + const [snippetName, setSnippetName] = useState(''); -class ActionButtons extends React.PureComponent { - public state: State = { - isOpen: false, - shareText: this.props.t('Generate link to share code example'), - snippetName: '' + const _generateLink = (): void => { + setShareText(t('Copied to clipboard')); + generateLink(); + }; + const _onShareClose = (): void => { + setShareText(t('Generate link to share code example')); + }; + const _onChangeName = (snippetName: string): void => { + setSnippetName(snippetName); + }; + const _onPopupOpen = (): void => { + setIsOpen(true); + }; + const _onPopupClose = (): void => { + setSnippetName(''); + setIsOpen(false); + }; + const _saveSnippet = (): void => { + saveSnippet(snippetName); + _onPopupClose(); }; - public render (): React.ReactNode { - const { className, isCustomExample, isRunning, removeSnippet, runJs, stopJs, t } = this.props; - const { isOpen, shareText, snippetName } = this.state; - - return ( -
+ return ( +
+ + } + wide='very' + /> + { + // FIXME: The event trigger on='hover' does not work together with the ui-app' + //
- ); - } - - private generateLink = (): void => { - const { generateLink, t } = this.props; - - this.setState({ shareText: t('Copied to clipboard') }); - generateLink(); - } - - private onShareClose = (): void => { - this.setState({ shareText: this.props.t('Generate link to share code example') }); - } - - private onChangeName = (snippetName: string): void => { - this.setState({ snippetName }); - } - - private saveSnippet = (): void => { - const { state: { snippetName }, props: { saveSnippet } } = this; - - saveSnippet(snippetName); - this.setState({ snippetName: '', isOpen: false }); - } - - private onPopupOpen = (): void => { - this.setState({ isOpen: true, snippetName: this.props.snippetName || '' }); - } - - private onPopupClose = (): void => { - this.setState({ snippetName: '', isOpen: false }); - } +
+ ); } export default translate( diff --git a/packages/app-parachains/src/Overview/Chain.tsx b/packages/app-parachains/src/Overview/Chain.tsx index 6973ab943c..72eea0c3b2 100644 --- a/packages/app-parachains/src/Overview/Chain.tsx +++ b/packages/app-parachains/src/Overview/Chain.tsx @@ -4,8 +4,8 @@ import React from 'react'; -export default class Chain extends React.PureComponent<{}> { - public render (): React.ReactNode { - return null; - } +type Props = {}; + +export default function Chain (): React.ReactElement | null { + return null; } diff --git a/packages/app-parachains/src/Overview/index.tsx b/packages/app-parachains/src/Overview/index.tsx index 63ec1c90e3..2b6733d91e 100644 --- a/packages/app-parachains/src/Overview/index.tsx +++ b/packages/app-parachains/src/Overview/index.tsx @@ -8,15 +8,15 @@ import { Columar } from '@polkadot/react-components'; import Parachains from './Parachains'; import Summary from './Summary'; -export default class Overview extends React.PureComponent<{}> { - public render (): React.ReactNode { - return ( - <> - - - - - - ); - } +type Props = {}; + +export default function Overview (): React.ReactElement { + return ( + <> + + + + + + ); }