feat: reviewed and simplified the node status check (#63)
* refactor: status page nested ternary logic * refactor: move the fetch latest bee release to a hook * refactor: solved node status rerendering, improved performance and clarity * refactor: step components now use unified hooks interface * style: removed component margins, layout should be handled by pages
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { ReactElement, useState, ChangeEvent, ReactChild } from 'react'
|
||||
import { withStyles, Theme, createStyles } from '@material-ui/core/styles'
|
||||
import { withStyles, Theme, createStyles, makeStyles } from '@material-ui/core/styles'
|
||||
import { Tabs, Tab, Box, Typography, Container, CircularProgress } from '@material-ui/core'
|
||||
|
||||
import AccountCard from '../accounting/AccountCard'
|
||||
@@ -33,8 +33,19 @@ function a11yProps(index: number) {
|
||||
}
|
||||
}
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
width: '100%',
|
||||
display: 'grid',
|
||||
rowGap: theme.spacing(3),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export default function Accounting(): ReactElement {
|
||||
const [value, setValue] = useState(0)
|
||||
const classes = useStyles()
|
||||
|
||||
const handleChange = (event: ChangeEvent<unknown>, newValue: number) => {
|
||||
setValue(newValue)
|
||||
@@ -115,7 +126,6 @@ export default function Accounting(): ReactElement {
|
||||
color: '#3f51b5',
|
||||
},
|
||||
},
|
||||
selected: {},
|
||||
}),
|
||||
)((props: StyledTabProps) => <Tab disableRipple {...props} />)
|
||||
|
||||
@@ -125,7 +135,7 @@ export default function Accounting(): ReactElement {
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
nodeHealth?.status === 'ok' && health ? (
|
||||
<div>
|
||||
<div className={classes.root}>
|
||||
<AccountCard
|
||||
chequebookAddress={chequebookAddress}
|
||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||
@@ -140,20 +150,22 @@ export default function Accounting(): ReactElement {
|
||||
chequebookAddress={chequebookAddress}
|
||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||
/>
|
||||
<AntTabs style={{ marginTop: '12px' }} value={value} onChange={handleChange} aria-label="ant example">
|
||||
<AntTab label="Balances" {...a11yProps(0)} />
|
||||
<AntTab label="Chequebook" {...a11yProps(1)} />
|
||||
<AntTab label="Settlements" {...a11yProps(2)} />
|
||||
</AntTabs>
|
||||
<TabPanel value={value} index={0}>
|
||||
<BalancesTable peerBalances={peerBalances} loading={isLoadingPeerBalances} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<ChequebookTable peerCheques={peerCheques} loading={isLoadingPeerCheques} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={2}>
|
||||
<SettlementsTable nodeSettlements={settlements} loading={isLoadingSettlements} />
|
||||
</TabPanel>
|
||||
<div>
|
||||
<AntTabs style={{ marginTop: '12px' }} value={value} onChange={handleChange} aria-label="ant example">
|
||||
<AntTab label="Balances" {...a11yProps(0)} />
|
||||
<AntTab label="Chequebook" {...a11yProps(1)} />
|
||||
<AntTab label="Settlements" {...a11yProps(2)} />
|
||||
</AntTabs>
|
||||
<TabPanel value={value} index={0}>
|
||||
<BalancesTable peerBalances={peerBalances} loading={isLoadingPeerBalances} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={1}>
|
||||
<ChequebookTable peerCheques={peerCheques} loading={isLoadingPeerCheques} />
|
||||
</TabPanel>
|
||||
<TabPanel value={value} index={2}>
|
||||
<SettlementsTable nodeSettlements={settlements} loading={isLoadingSettlements} />
|
||||
</TabPanel>
|
||||
</div>
|
||||
</div>
|
||||
) : isLoadingHealth || isLoadingNodeHealth ? (
|
||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ReactElement, useEffect, useState } from 'react'
|
||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
||||
import { Typography, Paper, Button, Step, StepLabel, StepContent, Stepper, StepButton } from '@material-ui/core/'
|
||||
import { CheckCircle, Error, Sync, ExpandLessSharp, ExpandMoreSharp } from '@material-ui/icons/'
|
||||
import { CheckCircle, Error, Sync, ExpandLessSharp, ExpandMoreSharp, Autorenew } from '@material-ui/icons/'
|
||||
|
||||
import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck'
|
||||
import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
|
||||
@@ -9,17 +9,11 @@ import VersionCheck from './SetupSteps/VersionCheck'
|
||||
import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
|
||||
import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund'
|
||||
import PeerConnection from './SetupSteps/PeerConnection'
|
||||
import type {
|
||||
ChequebookAddressResponse,
|
||||
ChequebookBalanceResponse,
|
||||
Health,
|
||||
NodeAddresses,
|
||||
Topology,
|
||||
} from '@ethersphere/bee-js'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
padding: theme.spacing(2),
|
||||
width: '100%',
|
||||
},
|
||||
button: {
|
||||
@@ -29,147 +23,88 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
actionsContainer: {
|
||||
margin: theme.spacing(2),
|
||||
},
|
||||
resetContainer: {
|
||||
padding: theme.spacing(5),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
function getSteps() {
|
||||
return [
|
||||
'Debug Connection Check',
|
||||
'Version Check',
|
||||
'Connect to Ethereum Blockchain',
|
||||
'Deploy and Fund Chequebook',
|
||||
'Node Connection Check',
|
||||
'Connect to Peers',
|
||||
]
|
||||
interface Step {
|
||||
label: string
|
||||
condition: boolean
|
||||
isLoading: boolean
|
||||
component: ReactElement
|
||||
}
|
||||
|
||||
interface Props {
|
||||
nodeHealth: Health | null
|
||||
nodeApiHealth: boolean
|
||||
nodeAddresses: NodeAddresses | null
|
||||
chequebookAddress: ChequebookAddressResponse | null
|
||||
chequebookBalance: ChequebookBalanceResponse | null
|
||||
beeRelease: LatestBeeRelease | null
|
||||
nodeTopology: Topology | null
|
||||
isLoadingBeeRelease: boolean
|
||||
isLoadingNodeHealth: boolean
|
||||
isLoadingNodeAddresses: boolean
|
||||
isLoadingNodeTopology: boolean
|
||||
isLoadingHealth: boolean
|
||||
isLoadingChequebookAddress: boolean
|
||||
isLoadingChequebookBalance: boolean
|
||||
setStatusChecksVisible: (value: boolean) => void
|
||||
apiHost: string
|
||||
debugApiHost: string
|
||||
nodeVersion: StatusNodeVersionHook
|
||||
ethereumConnection: StatusEthereumConnectionHook
|
||||
debugApiConnection: StatusHookCommon
|
||||
apiConnection: StatusHookCommon
|
||||
topology: StatusTopologyHook
|
||||
chequebook: StatusChequebookHook
|
||||
}
|
||||
|
||||
function getStepContent(step: number, props: Props) {
|
||||
const {
|
||||
nodeHealth,
|
||||
debugApiHost,
|
||||
beeRelease,
|
||||
isLoadingBeeRelease,
|
||||
nodeAddresses,
|
||||
isLoadingNodeAddresses,
|
||||
isLoadingChequebookBalance,
|
||||
chequebookAddress,
|
||||
chequebookBalance,
|
||||
isLoadingChequebookAddress,
|
||||
nodeApiHealth,
|
||||
apiHost,
|
||||
isLoadingNodeTopology,
|
||||
nodeTopology,
|
||||
} = props
|
||||
switch (step) {
|
||||
case 0:
|
||||
return <DebugConnectionCheck nodeHealth={nodeHealth} debugApiHost={debugApiHost} />
|
||||
case 1:
|
||||
return <VersionCheck nodeHealth={nodeHealth} beeRelease={beeRelease} isLoadingBeeRelease={isLoadingBeeRelease} />
|
||||
case 2:
|
||||
return <EthereumConnectionCheck nodeAddresses={nodeAddresses} isLoadingNodeAddresses={isLoadingNodeAddresses} />
|
||||
case 3:
|
||||
return (
|
||||
<ChequebookDeployFund
|
||||
chequebookAddress={chequebookAddress}
|
||||
chequebookBalance={chequebookBalance}
|
||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||
isLoadingChequebookBalance={isLoadingChequebookBalance}
|
||||
/>
|
||||
)
|
||||
case 4:
|
||||
return <NodeConnectionCheck nodeApiHealth={nodeApiHealth} apiHost={apiHost} />
|
||||
default:
|
||||
return <PeerConnection nodeTopology={nodeTopology} isLoadingNodeTopology={isLoadingNodeTopology} />
|
||||
}
|
||||
}
|
||||
|
||||
export default function NodeSetupWorkflow(props: Props): ReactElement {
|
||||
const {
|
||||
nodeHealth,
|
||||
nodeApiHealth,
|
||||
nodeAddresses,
|
||||
chequebookAddress,
|
||||
chequebookBalance,
|
||||
beeRelease,
|
||||
nodeTopology,
|
||||
setStatusChecksVisible,
|
||||
} = props
|
||||
export default function NodeSetupWorkflow({
|
||||
nodeVersion,
|
||||
ethereumConnection,
|
||||
debugApiConnection,
|
||||
apiConnection,
|
||||
topology,
|
||||
chequebook,
|
||||
}: Props): ReactElement {
|
||||
const classes = useStyles()
|
||||
const [activeStep, setActiveStep] = useState(0)
|
||||
const [completed, setCompleted] = useState<{ [k: number]: boolean }>({})
|
||||
const steps = getSteps()
|
||||
const [activeStep, setActiveStep] = useState(-1)
|
||||
|
||||
const steps: Step[] = [
|
||||
{
|
||||
label: 'Connected to Node DebugAPI',
|
||||
condition: debugApiConnection.isOk,
|
||||
isLoading: debugApiConnection.isLoading,
|
||||
component: <DebugConnectionCheck {...debugApiConnection} />,
|
||||
},
|
||||
{
|
||||
label: 'Running latest Bee version',
|
||||
condition: nodeVersion.isOk,
|
||||
isLoading: nodeVersion.isLoading,
|
||||
component: <VersionCheck {...nodeVersion} />,
|
||||
},
|
||||
{
|
||||
label: 'Connected to Ethereum Blockchain',
|
||||
condition: ethereumConnection.isOk,
|
||||
isLoading: ethereumConnection.isLoading,
|
||||
component: <EthereumConnectionCheck {...ethereumConnection} />,
|
||||
},
|
||||
{
|
||||
label: 'Deployed and Funded Chequebook',
|
||||
condition: chequebook.isOk,
|
||||
isLoading: chequebook.isLoading,
|
||||
component: <ChequebookDeployFund {...chequebook} />,
|
||||
},
|
||||
{
|
||||
label: 'Connected to Node API',
|
||||
condition: apiConnection.isOk,
|
||||
isLoading: apiConnection.isLoading,
|
||||
component: <NodeConnectionCheck {...apiConnection} />,
|
||||
},
|
||||
{
|
||||
label: 'Connected to Peers',
|
||||
condition: topology.isOk,
|
||||
isLoading: topology.isLoading,
|
||||
component: <PeerConnection {...topology} />,
|
||||
},
|
||||
]
|
||||
|
||||
useEffect(() => {
|
||||
const handleComplete = (index: number) => {
|
||||
const newCompleted = completed
|
||||
newCompleted[index] = true
|
||||
setCompleted(newCompleted)
|
||||
}
|
||||
// If the user already changed the active step we don't want to overwrite it
|
||||
if (activeStep > 0 && activeStep < steps.length) return
|
||||
|
||||
const evaluateNodeStatus = () => {
|
||||
if (nodeHealth?.status === 'ok') {
|
||||
handleComplete(0)
|
||||
setActiveStep(1)
|
||||
}
|
||||
// Select first step that is not OK
|
||||
for (let i = 0; i < steps.length; ++i) {
|
||||
if (!steps[i].condition) {
|
||||
setActiveStep(i)
|
||||
|
||||
if (beeRelease && beeRelease.name === `v${nodeHealth?.version?.split('-')[0]}`) {
|
||||
handleComplete(1)
|
||||
setActiveStep(2)
|
||||
}
|
||||
|
||||
if (nodeAddresses?.ethereum) {
|
||||
handleComplete(2)
|
||||
setActiveStep(3)
|
||||
}
|
||||
|
||||
if (chequebookAddress?.chequebookaddress && chequebookBalance && chequebookBalance.totalBalance > 0) {
|
||||
handleComplete(3)
|
||||
setActiveStep(4)
|
||||
}
|
||||
|
||||
if (nodeApiHealth) {
|
||||
handleComplete(4)
|
||||
setActiveStep(5)
|
||||
}
|
||||
|
||||
if (nodeTopology?.connected && nodeTopology?.connected > 0) {
|
||||
handleComplete(5)
|
||||
setActiveStep(6)
|
||||
return
|
||||
}
|
||||
}
|
||||
evaluateNodeStatus()
|
||||
}, [
|
||||
nodeHealth,
|
||||
nodeApiHealth,
|
||||
nodeAddresses,
|
||||
chequebookAddress,
|
||||
beeRelease,
|
||||
chequebookBalance,
|
||||
nodeTopology,
|
||||
completed,
|
||||
])
|
||||
}, [steps])
|
||||
|
||||
const handleNext = () => {
|
||||
setActiveStep(prevActiveStep => prevActiveStep + 1)
|
||||
@@ -179,13 +114,9 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
||||
setActiveStep(prevActiveStep => prevActiveStep - 1)
|
||||
}
|
||||
|
||||
const handleSetupComplete = () => {
|
||||
setStatusChecksVisible(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<Typography variant="h4" gutterBottom>
|
||||
<Paper className={classes.root}>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Node Setup
|
||||
<span style={{ marginLeft: '25px' }}>
|
||||
<Button variant="outlined" size="small" onClick={() => window.location.reload()}>
|
||||
@@ -195,20 +126,22 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
||||
</span>
|
||||
</Typography>
|
||||
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
|
||||
{steps.map((label, index) => (
|
||||
{steps.map(({ label, condition, component, isLoading }, index) => (
|
||||
<Step key={label}>
|
||||
<StepLabel
|
||||
onClick={() => setActiveStep(index === activeStep ? 6 : index)}
|
||||
disabled={isLoading}
|
||||
onClick={() => setActiveStep(index === activeStep ? steps.length : index)}
|
||||
StepIconComponent={() => {
|
||||
if (completed[index]) {
|
||||
return <CheckCircle style={{ color: '#32c48d', height: '25px', cursor: 'pointer' }} />
|
||||
} else {
|
||||
return <Error style={{ color: '#c9201f', height: '25px', cursor: 'pointer' }} />
|
||||
}
|
||||
if (isLoading) return <Autorenew style={{ height: '25px', cursor: 'pointer' }} />
|
||||
|
||||
if (condition) return <CheckCircle style={{ color: '#32c48d', height: '25px', cursor: 'pointer' }} />
|
||||
|
||||
return <Error style={{ color: '#c9201f', height: '25px', cursor: 'pointer' }} />
|
||||
}}
|
||||
>
|
||||
<StepButton
|
||||
onClick={() => setActiveStep(index === activeStep ? 6 : index)}
|
||||
disabled={isLoading}
|
||||
onClick={() => setActiveStep(index === activeStep ? steps.length : index)}
|
||||
style={{ justifyContent: 'space-between' }}
|
||||
>
|
||||
<div style={{ display: 'flex' }}>
|
||||
@@ -220,14 +153,14 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
||||
</StepButton>
|
||||
</StepLabel>
|
||||
<StepContent>
|
||||
<Typography component="div">{getStepContent(index, props)}</Typography>
|
||||
<Typography component="div">{component}</Typography>
|
||||
<div className={classes.actionsContainer}>
|
||||
<div>
|
||||
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
|
||||
Back
|
||||
</Button>
|
||||
<Button variant="contained" color="primary" onClick={handleNext} className={classes.button}>
|
||||
Next
|
||||
{index < steps.length - 1 ? 'Next' : 'Finish'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -235,17 +168,6 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
{Object.values(completed).filter(value => value).length === 6 ? (
|
||||
<Paper square elevation={0} className={classes.resetContainer}>
|
||||
<Typography>Bee setup complete! Welcome to the swarm and the internet of decentralized storage</Typography>
|
||||
<Button onClick={handleBack} className={classes.button}>
|
||||
Back
|
||||
</Button>
|
||||
<Button onClick={handleSetupComplete} variant="contained" color="primary" className={classes.button}>
|
||||
Complete
|
||||
</Button>
|
||||
</Paper>
|
||||
) : null}
|
||||
</div>
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
import { Typography } from '@material-ui/core/'
|
||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
||||
import EthereumAddress from '../../../components/EthereumAddress'
|
||||
import DepositModal from '../../../components/DepositModal'
|
||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||
import type { ChequebookAddressResponse, ChequebookBalanceResponse } from '@ethersphere/bee-js'
|
||||
import type { ReactElement } from 'react'
|
||||
|
||||
interface Props {
|
||||
chequebookAddress: ChequebookAddressResponse | null
|
||||
chequebookBalance: ChequebookBalanceResponse | null
|
||||
isLoadingChequebookAddress: boolean
|
||||
isLoadingChequebookBalance: boolean
|
||||
}
|
||||
type Props = StatusChequebookHook
|
||||
|
||||
const ChequebookDeployFund = (props: Props): ReactElement => (
|
||||
<div>
|
||||
<p style={{ marginBottom: '20px', display: 'flex' }}>
|
||||
<span style={{ marginRight: '40px' }}>Deploy chequebook and fund with BZZ</span>
|
||||
{props.chequebookAddress?.chequebookaddress ? <DepositModal /> : null}
|
||||
</p>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
{
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
props.chequebookAddress?.chequebookaddress &&
|
||||
props.chequebookBalance &&
|
||||
props.chequebookBalance?.totalBalance > 0 ? (
|
||||
const ChequebookDeployFund = ({ isLoading, chequebookAddress, chequebookBalance }: Props): ReactElement | null => {
|
||||
if (isLoading) return null
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p style={{ marginBottom: '20px', display: 'flex' }}>
|
||||
{chequebookAddress?.chequebookaddress && <DepositModal />}
|
||||
</p>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
{!(chequebookAddress?.chequebookaddress && chequebookBalance && chequebookBalance?.totalBalance > 0) && (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your chequebook is deployed and funded!</span>
|
||||
</div>
|
||||
) : props.isLoadingChequebookAddress || props.isLoadingChequebookBalance ? null : (
|
||||
<div>
|
||||
<Warning style={{ color: '#ff9800', marginRight: '7px', height: '18px' }} />
|
||||
<span>
|
||||
Your chequebook is either not deployed or funded. Run the below commands to get your address and deposit
|
||||
ETH. Then visit the BZZaar here{' '}
|
||||
@@ -43,15 +27,14 @@ const ChequebookDeployFund = (props: Props): ReactElement => (
|
||||
</span>
|
||||
<CodeBlockTabs showLineNumbers linux={`bee-get-addr`} mac={`bee-get-addr`} />
|
||||
</div>
|
||||
)
|
||||
/* eslint-enable no-nested-ternary */
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Chequebook Address
|
||||
</Typography>
|
||||
<EthereumAddress address={chequebookAddress?.chequebookaddress} network={'goerli'} />
|
||||
</div>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Chequebook Address
|
||||
</Typography>
|
||||
<EthereumAddress address={props.chequebookAddress?.chequebookaddress} network={'goerli'} />
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export default ChequebookDeployFund
|
||||
|
||||
@@ -1,100 +1,95 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
|
||||
import MuiAlert from '@material-ui/lab/Alert'
|
||||
import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/'
|
||||
import { ExpandMoreSharp } from '@material-ui/icons/'
|
||||
|
||||
import ConnectToHost from '../../../components/ConnectToHost'
|
||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||
import type { Health } from '@ethersphere/bee-js'
|
||||
import { debugApiHost } from '../../../constants'
|
||||
|
||||
interface Props {
|
||||
nodeHealth: Health | null
|
||||
debugApiHost: string
|
||||
}
|
||||
type Props = StatusHookCommon
|
||||
|
||||
export default function NodeConnectionCheck({ isLoading, isOk }: Props): ReactElement | null {
|
||||
if (isLoading) return null
|
||||
|
||||
const changeDebugApiUrl = (
|
||||
<div style={{ display: 'flex', marginTop: '25px', marginBottom: '25px' }}>
|
||||
<span style={{ marginRight: '15px' }}>
|
||||
Debug API (<Typography variant="button">{debugApiHost}</Typography>)
|
||||
</span>
|
||||
<ConnectToHost hostName={'debug_api_host'} defaultHost={debugApiHost} />
|
||||
</div>
|
||||
)
|
||||
|
||||
if (isOk) {
|
||||
return changeDebugApiUrl
|
||||
}
|
||||
|
||||
export default function NodeConnectionCheck(props: Props): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<p>Connect to Bee Node Debug API</p>
|
||||
{changeDebugApiUrl}
|
||||
|
||||
<div>
|
||||
<div style={{ display: 'flex', marginBottom: '25px' }}>
|
||||
{props.nodeHealth?.status === 'ok' ? (
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
) : (
|
||||
<Error style={{ color: '#c9201f', marginRight: '7px', height: '18px' }} />
|
||||
)}
|
||||
<span style={{ marginRight: '15px' }}>
|
||||
Debug API (<Typography variant="button">{props.debugApiHost}</Typography>)
|
||||
</span>
|
||||
<ConnectToHost hostName={'debug_api_host'} defaultHost={props.debugApiHost} />
|
||||
</div>
|
||||
<div>
|
||||
{props.nodeHealth?.status !== 'ok' ? (
|
||||
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
||||
We cannot connect to your nodes debug API at{' '}
|
||||
<Typography variant="button">{props.debugApiHost}</Typography>. Please check the following to troubleshoot
|
||||
your issue.
|
||||
<Accordion style={{ marginTop: '20px' }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
||||
<Typography>Troubleshoot</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography component="div">
|
||||
<ol>
|
||||
<li>
|
||||
Check the status of your node by running the below command to see if your node is running.
|
||||
</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl status bee`}
|
||||
mac={`brew services status swarm-bee`}
|
||||
/>
|
||||
<li>
|
||||
If your node is running, check your firewall settings to make sure that port 1635 (or your
|
||||
custom specified port) is bound to localhost. If your node is not running try executing the
|
||||
below command to start your bee node
|
||||
</li>
|
||||
<MuiAlert
|
||||
style={{ marginTop: '10px', marginBottom: '10px' }}
|
||||
elevation={6}
|
||||
variant="filled"
|
||||
severity="error"
|
||||
>
|
||||
Your debug node API should never be completely open to the internet. If you want to connect
|
||||
remotely, make sure your firewall settings are set to only allow specific trusted IP addresses
|
||||
and block all other ports. A simple google search for "what is my ip" will show you
|
||||
your computers public IP address to allow.
|
||||
</MuiAlert>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl start bee`}
|
||||
mac={`brew services start swarm-bee`}
|
||||
/>
|
||||
<li>Run the commands to validate your node is running and see the log output.</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl status bee \njournalctl --lines=100 --follow --unit bee`}
|
||||
mac={`brew services status swarm-bee \ntail -f /usr/local/var/log/swarm-bee/bee.log`}
|
||||
/>
|
||||
<li>
|
||||
Lastly, check your nodes configuration settings to validate the debug API is enabled and the
|
||||
Cross Origin Resource Sharing (CORS) setting is configured to allow your host. Config parameter{' '}
|
||||
<strong>debug-api-enable</strong> must be set to <strong>true</strong> and{' '}
|
||||
<strong>cors-allowed-origins</strong> must be set to your host domain or IP. If edits are made
|
||||
to the configuration run the restart command below for changes to take effect.
|
||||
</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo vi /etc/bee/bee.yaml\nsudo systemctl restart bee`}
|
||||
mac={`sudo vi /etc/bee/bee.yaml \nbrew services restart swarm-bee`}
|
||||
/>
|
||||
</ol>
|
||||
</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Typography>
|
||||
) : null}
|
||||
</div>
|
||||
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
||||
We cannot connect to your nodes debug API at <Typography variant="button">{debugApiHost}</Typography>. Please
|
||||
check the following to troubleshoot your issue.
|
||||
<Accordion style={{ marginTop: '20px' }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
||||
<Typography>Troubleshoot</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<Typography component="div">
|
||||
<ol>
|
||||
<li>Check the status of your node by running the below command to see if your node is running.</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl status bee`}
|
||||
mac={`brew services status swarm-bee`}
|
||||
/>
|
||||
<li>
|
||||
If your node is running, check your firewall settings to make sure that port 1635 (or your custom
|
||||
specified port) is bound to localhost. If your node is not running try executing the below command
|
||||
to start your bee node
|
||||
</li>
|
||||
<MuiAlert
|
||||
style={{ marginTop: '10px', marginBottom: '10px' }}
|
||||
elevation={6}
|
||||
variant="filled"
|
||||
severity="error"
|
||||
>
|
||||
Your debug node API should never be completely open to the internet. If you want to connect
|
||||
remotely, make sure your firewall settings are set to only allow specific trusted IP addresses and
|
||||
block all other ports. A simple google search for "what is my ip" will show you your
|
||||
computers public IP address to allow.
|
||||
</MuiAlert>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl start bee`}
|
||||
mac={`brew services start swarm-bee`}
|
||||
/>
|
||||
<li>Run the commands to validate your node is running and see the log output.</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo systemctl status bee \njournalctl --lines=100 --follow --unit bee`}
|
||||
mac={`brew services status swarm-bee \ntail -f /usr/local/var/log/swarm-bee/bee.log`}
|
||||
/>
|
||||
<li>
|
||||
Lastly, check your nodes configuration settings to validate the debug API is enabled and the Cross
|
||||
Origin Resource Sharing (CORS) setting is configured to allow your host. Config parameter{' '}
|
||||
<strong>debug-api-enable</strong> must be set to <strong>true</strong> and{' '}
|
||||
<strong>cors-allowed-origins</strong> must be set to your host domain or IP. If edits are made to
|
||||
the configuration run the restart command below for changes to take effect.
|
||||
</li>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`sudo vi /etc/bee/bee.yaml\nsudo systemctl restart bee`}
|
||||
mac={`sudo vi /etc/bee/bee.yaml \nbrew services restart swarm-bee`}
|
||||
/>
|
||||
</ol>
|
||||
</Typography>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,56 +1,40 @@
|
||||
import type { ReactElement } from 'react'
|
||||
import { Typography } from '@material-ui/core/'
|
||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
||||
import EthereumAddress from '../../../components/EthereumAddress'
|
||||
import type { NodeAddresses } from '@ethersphere/bee-js'
|
||||
|
||||
interface Props {
|
||||
nodeAddresses: NodeAddresses | null
|
||||
isLoadingNodeAddresses: boolean
|
||||
}
|
||||
type Props = StatusEthereumConnectionHook
|
||||
|
||||
export default function EthereumConnectionCheck(props: Props): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<p>Connect to the ethereum blockchain.</p>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
{
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
props.nodeAddresses?.ethereum ? (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your connected to the Ethereum network</span>
|
||||
</div>
|
||||
) : props.isLoadingNodeAddresses ? null : (
|
||||
<div>
|
||||
<Warning style={{ color: '#ff9800', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your not connected to the Ethereum network. </span>
|
||||
<p>
|
||||
Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your
|
||||
chequebook contract. You can run{' '}
|
||||
<a href="https://github.com/goerli/testnet" rel="noreferrer" target="_blank">
|
||||
your own Goerli node
|
||||
</a>
|
||||
, or use a provider such as{' '}
|
||||
<a href="https://rpc.slock.it/goerli" rel="noreferrer" target="_blank">
|
||||
rpc.slock.it/goerli
|
||||
</a>{' '}
|
||||
or{' '}
|
||||
<a href="https://infura.io/" rel="noreferrer" target="_blank">
|
||||
Infura
|
||||
</a>
|
||||
. By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead,
|
||||
simply change your <strong>--swap-endpoint</strong> in your configuration file.
|
||||
</p>
|
||||
</div>
|
||||
) /* eslint-enable no-nested-ternary */
|
||||
}
|
||||
export default function EthereumConnectionCheck({ isLoading, isOk, nodeAddresses }: Props): ReactElement | null {
|
||||
if (isLoading) return null
|
||||
|
||||
if (isOk) {
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Node Address
|
||||
</Typography>
|
||||
<EthereumAddress address={nodeAddresses?.ethereum} network={'goerli'} />
|
||||
</div>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Node Address
|
||||
</Typography>
|
||||
<EthereumAddress address={props.nodeAddresses?.ethereum} network={'goerli'} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<p>
|
||||
Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your chequebook
|
||||
contract. You can run{' '}
|
||||
<a href="https://github.com/goerli/testnet" rel="noreferrer" target="_blank">
|
||||
your own Goerli node
|
||||
</a>
|
||||
, or use a provider such as{' '}
|
||||
<a href="https://rpc.slock.it/goerli" rel="noreferrer" target="_blank">
|
||||
rpc.slock.it/goerli
|
||||
</a>{' '}
|
||||
or{' '}
|
||||
<a href="https://infura.io/" rel="noreferrer" target="_blank">
|
||||
Infura
|
||||
</a>
|
||||
. By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead, simply change
|
||||
your <strong>--swap-endpoint</strong> in your configuration file.
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,29 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
|
||||
import { CheckCircle, Error, ExpandMoreSharp } from '@material-ui/icons/'
|
||||
import { ExpandMoreSharp } from '@material-ui/icons/'
|
||||
|
||||
import ConnectToHost from '../../../components/ConnectToHost'
|
||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||
import { apiHost } from '../../../constants'
|
||||
|
||||
interface Props {
|
||||
nodeApiHealth: boolean
|
||||
apiHost: string
|
||||
}
|
||||
type Props = StatusHookCommon
|
||||
|
||||
export default function NodeConnectionCheck({ isLoading, isOk }: Props): ReactElement | null {
|
||||
if (isLoading) return null
|
||||
|
||||
export default function NodeConnectionCheck(props: Props): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<p>Connect to Bee Node API</p>
|
||||
<div style={{ display: 'flex', marginBottom: '25px' }}>
|
||||
{props.nodeApiHealth ? (
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
) : (
|
||||
<Error style={{ color: '#c9201f', marginRight: '7px', height: '18px' }} />
|
||||
)}
|
||||
<span style={{ marginRight: '15px' }}>
|
||||
Node API (<Typography variant="button">{props.apiHost}</Typography>)
|
||||
Node API (<Typography variant="button">{apiHost}</Typography>)
|
||||
</span>
|
||||
<ConnectToHost hostName="api_host" defaultHost={props.apiHost} />
|
||||
<ConnectToHost hostName="api_host" defaultHost={apiHost} />
|
||||
</div>
|
||||
<div>
|
||||
{!props.nodeApiHealth ? (
|
||||
{!isOk && (
|
||||
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
||||
We cannot connect to your nodes API at <Typography variant="button">{props.apiHost}</Typography>. Please
|
||||
check the following to troubleshoot your issue.
|
||||
We cannot connect to your nodes API at <Typography variant="button">{apiHost}</Typography>. Please check the
|
||||
following to troubleshoot your issue.
|
||||
<Accordion style={{ marginTop: '20px' }}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
||||
<Typography>Troubleshoot</Typography>
|
||||
@@ -64,7 +58,7 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
</Typography>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,53 +1,45 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import type { ReactElement } from 'react'
|
||||
import { Typography } from '@material-ui/core/'
|
||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
||||
import { Topology } from '@ethersphere/bee-js'
|
||||
|
||||
interface Props {
|
||||
nodeTopology: Topology | null
|
||||
isLoadingNodeTopology: boolean
|
||||
}
|
||||
type Props = StatusTopologyHook
|
||||
|
||||
export default function PeerConnection(props: Props): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<p>Connect to Peers</p>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
html_url
|
||||
{
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
props.nodeTopology?.connected && props.nodeTopology?.connected > 0 ? (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your connected to {props.nodeTopology.connected} peers!</span>
|
||||
</div>
|
||||
) : props.isLoadingNodeTopology ? null : (
|
||||
<div>
|
||||
<Warning style={{ color: '#ff9800', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your node is not connected to any peers</span>
|
||||
</div>
|
||||
) /* eslint-enable no-nested-ternary */
|
||||
}
|
||||
export default function PeerConnection({ isLoading, isOk, topology }: Props): ReactElement | null {
|
||||
if (isLoading) return null
|
||||
|
||||
const peers = (
|
||||
<div style={{ display: 'flex', marginTop: '15px' }}>
|
||||
<div style={{ marginRight: '30px' }}>
|
||||
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
||||
<span>Connected Peers</span>
|
||||
</Typography>
|
||||
<Typography component="h2" variant="h5">
|
||||
{topology?.connected ? topology.connected : '-'}
|
||||
</Typography>
|
||||
</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div style={{ marginRight: '30px' }}>
|
||||
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
||||
<span>Connected Peers</span>
|
||||
</Typography>
|
||||
<Typography component="h2" variant="h5">
|
||||
{props.nodeTopology?.connected}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
||||
<span>Discovered Nodes</span>
|
||||
</Typography>
|
||||
<Typography component="h2" variant="h5">
|
||||
{props.nodeTopology?.population}
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
||||
<span>Discovered Nodes</span>
|
||||
</Typography>
|
||||
<Typography component="h2" variant="h5">
|
||||
{topology?.population ? topology.population : '-'}
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (isOk) {
|
||||
return (
|
||||
<>
|
||||
<span>You are connected to peers!</span>
|
||||
{peers}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>Your node is not connected to any peers</span>
|
||||
{peers}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,81 +1,68 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import type { ReactElement } from 'react'
|
||||
import { Typography } from '@material-ui/core/'
|
||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||
import { Health } from '@ethersphere/bee-js'
|
||||
|
||||
interface Props {
|
||||
beeRelease: LatestBeeRelease | null
|
||||
isLoadingBeeRelease: boolean
|
||||
nodeHealth: Health | null
|
||||
}
|
||||
type Props = StatusNodeVersionHook
|
||||
|
||||
export default function VersionCheck(props: Props): ReactElement {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
Check to make sure the latest version of{' '}
|
||||
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
||||
Bee
|
||||
</a>{' '}
|
||||
is running
|
||||
</p>
|
||||
{
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ? (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px', height: '18px' }} />
|
||||
<span>Your running the latest version of Bee</span>
|
||||
</div>
|
||||
) : props.isLoadingBeeRelease ? null : (
|
||||
<div>
|
||||
<Warning style={{ color: '#ff9800', marginRight: '7px', height: '18px' }} />
|
||||
<span>
|
||||
Your Bee version is out of date. Please update to the{' '}
|
||||
<a href={props.beeRelease?.html_url} rel="noreferrer" target="_blank">
|
||||
latest
|
||||
</a>{' '}
|
||||
before continuing. Rerun the installation script below to upgrade. Reference the docs for help with
|
||||
updating.{' '}
|
||||
<a
|
||||
href="https://docs.ethswarm.org/docs/installation/manual#upgrading-bee"
|
||||
rel="noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
Docs
|
||||
</a>
|
||||
</span>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`bee version\nwget https://github.com/ethersphere/bee/releases/download/${
|
||||
props.beeRelease?.name
|
||||
}/bee_${props.nodeHealth?.version?.split('-')[0]}_amd64.deb\nsudo dpkg -i bee_${
|
||||
props.nodeHealth?.version?.split('-')[0]
|
||||
}_amd64.deb`}
|
||||
mac={`bee version\nbrew tap ethersphere/tap\nbrew install swarm-bee\nbrew services start swarm-bee`}
|
||||
/>
|
||||
</div>
|
||||
) /* eslint-enable no-nested-ternary */
|
||||
}
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div style={{ marginRight: '30px' }}>
|
||||
<p>
|
||||
<span>Current Version</span>
|
||||
</p>
|
||||
<Typography component="h5" variant="h5">
|
||||
<span>{props.nodeHealth?.version ? ` v${props.nodeHealth?.version?.split('-')[0]}` : '-'}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<span>Latest Version</span>
|
||||
</p>
|
||||
<Typography component="h5" variant="h5">
|
||||
<span>{props.beeRelease && props.beeRelease.name ? props.beeRelease.name : '-'}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
export default function VersionCheck({
|
||||
isLoading,
|
||||
isOk,
|
||||
userVersion,
|
||||
latestVersion,
|
||||
latestUrl,
|
||||
}: Props): ReactElement | null {
|
||||
if (isLoading) return null
|
||||
|
||||
const version = (
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div style={{ marginRight: '30px' }}>
|
||||
<p>
|
||||
<span>User Version</span>
|
||||
</p>
|
||||
<Typography component="h5" variant="h5">
|
||||
<span>{userVersion}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
<span>Latest Version</span>
|
||||
</p>
|
||||
<Typography component="h5" variant="h5">
|
||||
<span>{latestVersion}</span>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
// Running latest bee version
|
||||
if (isOk) {
|
||||
return (
|
||||
<>
|
||||
<span>You are running the latest version of Bee</span>
|
||||
{version}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
// Old version or not connected to bee debug API
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
Your Bee version is out of date. Please update to the{' '}
|
||||
<a href={latestUrl} rel="noreferrer" target="_blank">
|
||||
latest
|
||||
</a>{' '}
|
||||
before continuing. Rerun the installation script below to upgrade. Reference the docs for help with updating.{' '}
|
||||
<a href="https://docs.ethswarm.org/docs/installation/manual#upgrading-bee" rel="noreferrer" target="_blank">
|
||||
Docs
|
||||
</a>
|
||||
</span>
|
||||
<CodeBlockTabs
|
||||
showLineNumbers
|
||||
linux={`bee version\nwget https://github.com/ethersphere/bee/releases/download/${latestVersion}/bee_${latestVersion}_amd64.deb\nsudo dpkg -i bee_${latestVersion}_amd64.deb`}
|
||||
mac={`bee version\nbrew tap ethersphere/tap\nbrew install swarm-bee\nbrew services start swarm-bee`}
|
||||
/>
|
||||
{version}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
+87
-115
@@ -4,23 +4,15 @@ import { Link } from 'react-router-dom'
|
||||
import { createStyles, makeStyles } from '@material-ui/core/styles'
|
||||
import { Card, CardContent, Typography, Chip, Button } from '@material-ui/core/'
|
||||
import { CheckCircle, Error, ArrowRight, ArrowDropUp } from '@material-ui/icons/'
|
||||
import { Skeleton } from '@material-ui/lab'
|
||||
import type { Health, NodeAddresses, Topology } from '@ethersphere/bee-js'
|
||||
import { NodeAddresses, Topology } from '@ethersphere/bee-js'
|
||||
|
||||
const useStyles = makeStyles(() =>
|
||||
createStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
details: {
|
||||
display: 'flex',
|
||||
flex: '1 0 auto',
|
||||
|
||||
flex: '1 1 auto',
|
||||
flexDirection: 'column',
|
||||
},
|
||||
content: {
|
||||
flex: '1 0 auto',
|
||||
},
|
||||
status: {
|
||||
color: '#2145a0',
|
||||
backgroundColor: '#e1effe',
|
||||
@@ -29,124 +21,104 @@ const useStyles = makeStyles(() =>
|
||||
)
|
||||
|
||||
interface Props {
|
||||
nodeHealth: Health | null
|
||||
loadingNodeHealth: boolean
|
||||
beeRelease: LatestBeeRelease | null
|
||||
loadingBeeRelease: boolean
|
||||
nodeAddresses: NodeAddresses
|
||||
nodeTopology: Topology
|
||||
loadingNodeTopology: boolean
|
||||
setStatusChecksVisible: (value: boolean) => void
|
||||
nodeAddresses: NodeAddresses | null
|
||||
nodeTopology: Topology | null
|
||||
userBeeVersion: string | null
|
||||
latestBeeVersion: string | null
|
||||
isOk: boolean
|
||||
}
|
||||
|
||||
function StatusCard(props: Props): ReactElement {
|
||||
function StatusCard({
|
||||
userBeeVersion,
|
||||
nodeAddresses,
|
||||
nodeTopology,
|
||||
latestBeeVersion,
|
||||
isOk,
|
||||
}: Props): ReactElement | null {
|
||||
const classes = useStyles()
|
||||
|
||||
const [underlayAddressesVisible, setUnderlayAddresessVisible] = useState<boolean>(false)
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Card className={classes.root}>
|
||||
{!props.loadingNodeHealth && props.nodeHealth ? (
|
||||
<div className={classes.details}>
|
||||
<CardContent className={classes.content}>
|
||||
<Typography component="h5" variant="h5" style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
{props.nodeHealth.status === 'ok' ? (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px' }} />
|
||||
<span>Connected to Bee Node</span>
|
||||
</div>
|
||||
<Card>
|
||||
<CardContent className={classes.root}>
|
||||
<Typography component="h5" variant="h5" style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
{isOk && (
|
||||
<div>
|
||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px' }} />
|
||||
<span>Your Bee node is running as expected</span>
|
||||
</div>
|
||||
)}
|
||||
{!isOk && (
|
||||
<div>
|
||||
<Error style={{ color: '#c9201f', marginRight: '7px' }} />
|
||||
<span>Could not connect to Bee Node</span>
|
||||
</div>
|
||||
)}
|
||||
</Typography>
|
||||
{isOk && (
|
||||
<>
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<span style={{ marginRight: '20px' }}>Discovered Nodes: {nodeTopology?.population}</span>
|
||||
<span style={{ marginRight: '20px' }}>
|
||||
<span>Connected Peers: </span>
|
||||
<Link to="/peers/">{nodeTopology?.connected}</Link>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>AGENT: </span>
|
||||
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
||||
Bee
|
||||
</a>{' '}
|
||||
<span>{userBeeVersion || '-'}</span>
|
||||
{userBeeVersion && latestBeeVersion && userBeeVersion === latestBeeVersion ? (
|
||||
<Chip
|
||||
style={{ marginLeft: '7px', color: '#2145a0' }}
|
||||
size="small"
|
||||
label="latest"
|
||||
className={classes.status}
|
||||
/>
|
||||
) : (
|
||||
<Typography variant="button">update</Typography>
|
||||
)}
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>PUBLIC KEY: </span>
|
||||
<span>{nodeAddresses?.public_key ? nodeAddresses.public_key : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>PSS PUBLIC KEY: </span>
|
||||
<span>{nodeAddresses?.pss_public_key ? nodeAddresses.pss_public_key : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>OVERLAY ADDRESS (PEER ID): </span>
|
||||
<span>{nodeAddresses?.overlay ? nodeAddresses.overlay : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<Typography component="div" onClick={() => setUnderlayAddresessVisible(!underlayAddressesVisible)}>
|
||||
<Button color="primary" style={{ padding: 0, marginTop: '6px' }}>
|
||||
{underlayAddressesVisible ? (
|
||||
<ArrowDropUp style={{ fontSize: '12px' }} />
|
||||
) : (
|
||||
<ArrowRight style={{ fontSize: '12px' }} />
|
||||
)}
|
||||
<span>Underlay Addresses</span>
|
||||
</Button>
|
||||
</Typography>
|
||||
{underlayAddressesVisible && (
|
||||
<div>
|
||||
<Error style={{ color: '#c9201f', marginRight: '7px' }} />
|
||||
<span>Could not connect to Bee Node</span>
|
||||
{nodeAddresses?.underlay.map(item => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
size="small"
|
||||
style={{ marginLeft: '12px' }}
|
||||
onClick={() => props.setStatusChecksVisible(true)}
|
||||
>
|
||||
View Status Checks
|
||||
</Button>
|
||||
</Typography>
|
||||
<div style={{ marginBottom: '20px' }}>
|
||||
<span style={{ marginRight: '20px' }}>Discovered Nodes: {props.nodeTopology.population}</span>
|
||||
<span style={{ marginRight: '20px' }}>
|
||||
<span>Connected Peers: </span>
|
||||
<Link to="/peers/">{props.nodeTopology.connected}</Link>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>AGENT: </span>
|
||||
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
||||
Bee
|
||||
</a>
|
||||
<span>{props.nodeHealth?.version ? ` v${props.nodeHealth.version}` : '-'}</span>
|
||||
{
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ? (
|
||||
<Chip
|
||||
style={{ marginLeft: '7px', color: '#2145a0' }}
|
||||
size="small"
|
||||
label="latest"
|
||||
className={classes.status}
|
||||
/>
|
||||
) : props.loadingBeeRelease ? (
|
||||
''
|
||||
) : (
|
||||
<Typography variant="button">update</Typography>
|
||||
)
|
||||
/* eslint-enable no-nested-ternary */
|
||||
}
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>PUBLIC KEY: </span>
|
||||
<span>{props.nodeAddresses.public_key ? props.nodeAddresses.public_key : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<span>PSS PUBLIC KEY: </span>
|
||||
<span>{props.nodeAddresses.pss_public_key ? props.nodeAddresses.pss_public_key : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||
<Typography component="div" style={{ marginTop: '20px' }}>
|
||||
<span>OVERLAY ADDRESS (PEER ID): </span>
|
||||
<span>{props.nodeAddresses.overlay ? props.nodeAddresses.overlay : '-'}</span>
|
||||
</Typography>
|
||||
<Typography component="div" onClick={() => setUnderlayAddresessVisible(!underlayAddressesVisible)}>
|
||||
<Button color="primary" style={{ padding: 0, marginTop: '6px' }}>
|
||||
{underlayAddressesVisible ? (
|
||||
<ArrowDropUp style={{ fontSize: '12px' }} />
|
||||
) : (
|
||||
<ArrowRight style={{ fontSize: '12px' }} />
|
||||
)}
|
||||
<span>Underlay Addresses</span>
|
||||
</Button>
|
||||
</Typography>
|
||||
{underlayAddressesVisible ? (
|
||||
<div>
|
||||
{props.nodeAddresses.underlay
|
||||
? props.nodeAddresses.underlay.map(item => <li key={item}>{item}</li>)
|
||||
: '-'}
|
||||
</div>
|
||||
) : null}
|
||||
</Typography>
|
||||
</div>
|
||||
</CardContent>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ padding: '16px' }}>
|
||||
<Skeleton width={650} height={32} animation="wave" />
|
||||
<Skeleton width={650} height={24} animation="wave" />
|
||||
<Skeleton width={650} height={24} animation="wave" />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+56
-124
@@ -1,143 +1,75 @@
|
||||
import { useState, useEffect, ReactElement } from 'react'
|
||||
import axios from 'axios'
|
||||
import { ReactElement } from 'react'
|
||||
import { Container, CircularProgress } from '@material-ui/core'
|
||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
||||
|
||||
import NodeSetupWorkflow from './NodeSetupWorkflow'
|
||||
import StatusCard from './StatusCard'
|
||||
import EthereumAddressCard from '../../components/EthereumAddressCard'
|
||||
import {
|
||||
useApiHealth,
|
||||
useDebugApiHealth,
|
||||
useApiNodeAddresses,
|
||||
useApiChequebookAddress,
|
||||
useApiNodeTopology,
|
||||
useApiChequebookBalance,
|
||||
} from '../../hooks/apiHooks'
|
||||
useStatusEthereumConnection,
|
||||
useStatusNodeVersion,
|
||||
useStatusDebugConnection,
|
||||
useStatusConnection,
|
||||
useStatusTopology,
|
||||
useStatusChequebook,
|
||||
} from '../../hooks/status'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
width: '100%',
|
||||
display: 'grid',
|
||||
rowGap: theme.spacing(3),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export default function Status(): ReactElement {
|
||||
const [beeRelease, setBeeRelease] = useState<LatestBeeRelease | null>(null)
|
||||
const [isLoadingBeeRelease, setIsLoadingBeeRelease] = useState<boolean>(false)
|
||||
const classes = useStyles()
|
||||
|
||||
const [apiHost, setApiHost] = useState('')
|
||||
const [debugApiHost, setDebugApiHost] = useState('')
|
||||
const nodeVersion = useStatusNodeVersion()
|
||||
const ethereumConnection = useStatusEthereumConnection()
|
||||
const debugApiConnection = useStatusDebugConnection()
|
||||
const apiConnection = useStatusConnection()
|
||||
const topology = useStatusTopology()
|
||||
const chequebook = useStatusChequebook()
|
||||
|
||||
const [statusChecksVisible, setStatusChecksVisible] = useState<boolean>(false)
|
||||
const checks = [nodeVersion, ethereumConnection, debugApiConnection, apiConnection, topology, chequebook]
|
||||
|
||||
const { health, isLoadingHealth } = useApiHealth()
|
||||
const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
|
||||
const { nodeAddresses, isLoadingNodeAddresses } = useApiNodeAddresses()
|
||||
const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
|
||||
const { topology: nodeTopology, isLoading: isLoadingNodeTopology } = useApiNodeTopology()
|
||||
const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
|
||||
|
||||
const fetchLatestBeeRelease = () => {
|
||||
setIsLoadingBeeRelease(true)
|
||||
axios
|
||||
.get(`${process.env.REACT_APP_BEE_GITHUB_REPO_URL}/releases/latest`)
|
||||
.then(res => {
|
||||
setBeeRelease(res.data)
|
||||
})
|
||||
.catch(() => {
|
||||
// FIXME: should do something about the error
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingBeeRelease(false)
|
||||
})
|
||||
// If any check data are still loading
|
||||
if (!checks.every(c => !c.isLoading)) {
|
||||
return (
|
||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||
<CircularProgress />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const fetchApiHost = () => {
|
||||
let apiHost
|
||||
|
||||
if (sessionStorage.getItem('api_host')) {
|
||||
apiHost = String(sessionStorage.getItem('api_host') || '')
|
||||
} else {
|
||||
apiHost = String(process.env.REACT_APP_BEE_HOST)
|
||||
}
|
||||
setApiHost(apiHost)
|
||||
}
|
||||
|
||||
const fetchDebugApiHost = () => {
|
||||
let debugApiHost
|
||||
|
||||
if (sessionStorage.getItem('debug_api_host')) {
|
||||
debugApiHost = String(sessionStorage.getItem('debug_api_host') || '')
|
||||
} else {
|
||||
debugApiHost = String(process.env.REACT_APP_BEE_DEBUG_HOST)
|
||||
}
|
||||
setDebugApiHost(debugApiHost)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchApiHost()
|
||||
fetchDebugApiHost()
|
||||
fetchLatestBeeRelease()
|
||||
}, [])
|
||||
|
||||
// FIXME: this should be broken up
|
||||
/* eslint-disable no-nested-ternary */
|
||||
return (
|
||||
<div>
|
||||
{nodeHealth?.status === 'ok' &&
|
||||
health &&
|
||||
beeRelease &&
|
||||
beeRelease.name === `v${nodeHealth?.version?.split('-')[0]}` &&
|
||||
nodeAddresses?.ethereum &&
|
||||
chequebookAddress?.chequebookaddress &&
|
||||
chequebookBalance &&
|
||||
chequebookBalance?.totalBalance > 0 &&
|
||||
nodeTopology?.connected &&
|
||||
nodeTopology?.connected > 0 &&
|
||||
!statusChecksVisible ? (
|
||||
<div>
|
||||
<StatusCard
|
||||
nodeHealth={nodeHealth}
|
||||
loadingNodeHealth={isLoadingNodeHealth}
|
||||
beeRelease={beeRelease}
|
||||
loadingBeeRelease={isLoadingBeeRelease}
|
||||
nodeAddresses={nodeAddresses}
|
||||
loadingNodeTopology={isLoadingNodeTopology}
|
||||
nodeTopology={nodeTopology}
|
||||
setStatusChecksVisible={setStatusChecksVisible}
|
||||
/>
|
||||
<EthereumAddressCard
|
||||
nodeAddresses={nodeAddresses}
|
||||
isLoadingNodeAddresses={isLoadingNodeAddresses}
|
||||
chequebookAddress={chequebookAddress}
|
||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||
/>
|
||||
</div>
|
||||
) : isLoadingNodeHealth ||
|
||||
isLoadingHealth ||
|
||||
isLoadingChequebookAddress ||
|
||||
isLoadingNodeTopology ||
|
||||
isLoadingBeeRelease ||
|
||||
isLoadingNodeAddresses ||
|
||||
isLoadingBeeRelease ||
|
||||
isLoadingChequebookBalance ? (
|
||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||
<CircularProgress />
|
||||
</Container>
|
||||
) : (
|
||||
<NodeSetupWorkflow
|
||||
beeRelease={beeRelease}
|
||||
isLoadingBeeRelease={isLoadingBeeRelease}
|
||||
nodeHealth={nodeHealth}
|
||||
isLoadingNodeHealth={isLoadingNodeHealth}
|
||||
nodeAddresses={nodeAddresses}
|
||||
isLoadingNodeAddresses={isLoadingNodeAddresses}
|
||||
nodeTopology={nodeTopology}
|
||||
isLoadingNodeTopology={isLoadingNodeTopology}
|
||||
nodeApiHealth={health}
|
||||
isLoadingHealth={isLoadingHealth}
|
||||
chequebookAddress={chequebookAddress}
|
||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||
chequebookBalance={chequebookBalance}
|
||||
isLoadingChequebookBalance={isLoadingChequebookBalance}
|
||||
apiHost={apiHost}
|
||||
debugApiHost={debugApiHost}
|
||||
setStatusChecksVisible={setStatusChecksVisible}
|
||||
<div className={classes.root}>
|
||||
<StatusCard
|
||||
userBeeVersion={nodeVersion.userVersion}
|
||||
latestBeeVersion={nodeVersion.latestVersion}
|
||||
isOk={checks.every(c => c.isOk)}
|
||||
nodeTopology={topology.topology}
|
||||
nodeAddresses={ethereumConnection.nodeAddresses}
|
||||
/>
|
||||
{ethereumConnection.nodeAddresses && chequebook.chequebookAddress && (
|
||||
<EthereumAddressCard
|
||||
nodeAddresses={ethereumConnection.nodeAddresses}
|
||||
isLoadingNodeAddresses={ethereumConnection.isLoading}
|
||||
chequebookAddress={chequebook.chequebookAddress}
|
||||
isLoadingChequebookAddress={chequebook.isLoading}
|
||||
/>
|
||||
)}
|
||||
<NodeSetupWorkflow
|
||||
nodeVersion={nodeVersion}
|
||||
ethereumConnection={ethereumConnection}
|
||||
debugApiConnection={debugApiConnection}
|
||||
apiConnection={apiConnection}
|
||||
topology={topology}
|
||||
chequebook={chequebook}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user