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:
@@ -12,7 +12,9 @@ const useStyles = makeStyles(() =>
|
|||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
marginTop: '20px',
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-around',
|
||||||
|
flexWrap: 'wrap',
|
||||||
},
|
},
|
||||||
details: {
|
details: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@@ -21,10 +23,6 @@ const useStyles = makeStyles(() =>
|
|||||||
content: {
|
content: {
|
||||||
flex: '1 0 auto',
|
flex: '1 0 auto',
|
||||||
},
|
},
|
||||||
status: {
|
|
||||||
color: '#fff',
|
|
||||||
backgroundColor: '#76a9fa',
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,7 +37,6 @@ function EthereumAddressCard(props: Props): ReactElement {
|
|||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<Card className={classes.root}>
|
<Card className={classes.root}>
|
||||||
{props.isLoadingNodeAddresses ? (
|
{props.isLoadingNodeAddresses ? (
|
||||||
<div style={{ padding: '16px' }}>
|
<div style={{ padding: '16px' }}>
|
||||||
@@ -72,7 +69,6 @@ function EthereumAddressCard(props: Props): ReactElement {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
} from '@ethersphere/bee-js'
|
} from '@ethersphere/bee-js'
|
||||||
|
|
||||||
import { beeDebugApi, beeApi } from '../services/bee'
|
import { beeDebugApi, beeApi } from '../services/bee'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
export interface HealthHook {
|
export interface HealthHook {
|
||||||
health: boolean
|
health: boolean
|
||||||
@@ -361,3 +362,31 @@ export const useApiPeerLastCashout = (peerId: string): PeerLastCashoutHook => {
|
|||||||
|
|
||||||
return { peerCashout, isLoadingPeerCashout, error }
|
return { peerCashout, isLoadingPeerCashout, error }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LatestBeeReleaseHook {
|
||||||
|
latestBeeRelease: LatestBeeRelease | null
|
||||||
|
isLoadingLatestBeeRelease: boolean
|
||||||
|
error: Error | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLatestBeeRelease = (): LatestBeeReleaseHook => {
|
||||||
|
const [latestBeeRelease, setLatestBeeRelease] = useState<LatestBeeRelease | null>(null)
|
||||||
|
const [isLoadingLatestBeeRelease, setLoading] = useState<boolean>(false)
|
||||||
|
const [error, setError] = useState<Error | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
axios
|
||||||
|
.get(`${process.env.REACT_APP_BEE_GITHUB_REPO_URL}/releases/latest`)
|
||||||
|
.then(res => {
|
||||||
|
setLatestBeeRelease(res.data)
|
||||||
|
})
|
||||||
|
.catch((error: Error) => {
|
||||||
|
setError(error)
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
setLoading(false)
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return { latestBeeRelease, isLoadingLatestBeeRelease, error }
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import {
|
||||||
|
useApiChequebookAddress,
|
||||||
|
useApiChequebookBalance,
|
||||||
|
useApiHealth,
|
||||||
|
useApiNodeAddresses,
|
||||||
|
useApiNodeTopology,
|
||||||
|
useDebugApiHealth,
|
||||||
|
useLatestBeeRelease,
|
||||||
|
} from './apiHooks'
|
||||||
|
|
||||||
|
export const useStatusNodeVersion = (): StatusNodeVersionHook => {
|
||||||
|
const { latestBeeRelease, isLoadingLatestBeeRelease } = useLatestBeeRelease()
|
||||||
|
const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading: isLoadingNodeHealth || isLoadingLatestBeeRelease,
|
||||||
|
isOk: Boolean(latestBeeRelease && latestBeeRelease.name === `v${nodeHealth?.version?.split('-')[0]}`),
|
||||||
|
userVersion: nodeHealth?.version?.split('-')[0] || '-',
|
||||||
|
latestVersion: latestBeeRelease?.name.substring(1) || '-',
|
||||||
|
latestUrl: latestBeeRelease?.html_url || 'https://github.com/ethersphere/bee/releases/latest',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStatusEthereumConnection = (): StatusEthereumConnectionHook => {
|
||||||
|
const { isLoadingNodeAddresses, nodeAddresses } = useApiNodeAddresses()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading: isLoadingNodeAddresses,
|
||||||
|
isOk: Boolean(nodeAddresses?.ethereum),
|
||||||
|
nodeAddresses,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStatusDebugConnection = (): StatusHookCommon => {
|
||||||
|
const { isLoadingNodeHealth, nodeHealth } = useDebugApiHealth()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading: isLoadingNodeHealth,
|
||||||
|
isOk: Boolean(nodeHealth?.status === 'ok'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStatusConnection = (): StatusHookCommon => {
|
||||||
|
const { isLoadingHealth, health } = useApiHealth()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading: isLoadingHealth,
|
||||||
|
isOk: health,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStatusTopology = (): StatusTopologyHook => {
|
||||||
|
const { topology, isLoading } = useApiNodeTopology()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading,
|
||||||
|
isOk: Boolean(topology?.connected && topology?.connected > 0),
|
||||||
|
topology,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useStatusChequebook = (): StatusChequebookHook => {
|
||||||
|
const { chequebookAddress, isLoadingChequebookAddress } = useApiChequebookAddress()
|
||||||
|
const { chequebookBalance, isLoadingChequebookBalance } = useApiChequebookBalance()
|
||||||
|
|
||||||
|
return {
|
||||||
|
isLoading: isLoadingChequebookAddress || isLoadingChequebookBalance,
|
||||||
|
isOk:
|
||||||
|
Boolean(chequebookAddress?.chequebookaddress) && chequebookBalance !== null && chequebookBalance.totalBalance > 0,
|
||||||
|
chequebookBalance,
|
||||||
|
chequebookAddress,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ReactElement, useState, ChangeEvent, ReactChild } from 'react'
|
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 { Tabs, Tab, Box, Typography, Container, CircularProgress } from '@material-ui/core'
|
||||||
|
|
||||||
import AccountCard from '../accounting/AccountCard'
|
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 {
|
export default function Accounting(): ReactElement {
|
||||||
const [value, setValue] = useState(0)
|
const [value, setValue] = useState(0)
|
||||||
|
const classes = useStyles()
|
||||||
|
|
||||||
const handleChange = (event: ChangeEvent<unknown>, newValue: number) => {
|
const handleChange = (event: ChangeEvent<unknown>, newValue: number) => {
|
||||||
setValue(newValue)
|
setValue(newValue)
|
||||||
@@ -115,7 +126,6 @@ export default function Accounting(): ReactElement {
|
|||||||
color: '#3f51b5',
|
color: '#3f51b5',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selected: {},
|
|
||||||
}),
|
}),
|
||||||
)((props: StyledTabProps) => <Tab disableRipple {...props} />)
|
)((props: StyledTabProps) => <Tab disableRipple {...props} />)
|
||||||
|
|
||||||
@@ -125,7 +135,7 @@ export default function Accounting(): ReactElement {
|
|||||||
// FIXME: this should be broken up
|
// FIXME: this should be broken up
|
||||||
/* eslint-disable no-nested-ternary */
|
/* eslint-disable no-nested-ternary */
|
||||||
nodeHealth?.status === 'ok' && health ? (
|
nodeHealth?.status === 'ok' && health ? (
|
||||||
<div>
|
<div className={classes.root}>
|
||||||
<AccountCard
|
<AccountCard
|
||||||
chequebookAddress={chequebookAddress}
|
chequebookAddress={chequebookAddress}
|
||||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||||
@@ -140,6 +150,7 @@ export default function Accounting(): ReactElement {
|
|||||||
chequebookAddress={chequebookAddress}
|
chequebookAddress={chequebookAddress}
|
||||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
||||||
/>
|
/>
|
||||||
|
<div>
|
||||||
<AntTabs style={{ marginTop: '12px' }} value={value} onChange={handleChange} aria-label="ant example">
|
<AntTabs style={{ marginTop: '12px' }} value={value} onChange={handleChange} aria-label="ant example">
|
||||||
<AntTab label="Balances" {...a11yProps(0)} />
|
<AntTab label="Balances" {...a11yProps(0)} />
|
||||||
<AntTab label="Chequebook" {...a11yProps(1)} />
|
<AntTab label="Chequebook" {...a11yProps(1)} />
|
||||||
@@ -155,6 +166,7 @@ export default function Accounting(): ReactElement {
|
|||||||
<SettlementsTable nodeSettlements={settlements} loading={isLoadingSettlements} />
|
<SettlementsTable nodeSettlements={settlements} loading={isLoadingSettlements} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
) : isLoadingHealth || isLoadingNodeHealth ? (
|
) : isLoadingHealth || isLoadingNodeHealth ? (
|
||||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ReactElement, useEffect, useState } from 'react'
|
import { ReactElement, useEffect, useState } from 'react'
|
||||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
||||||
import { Typography, Paper, Button, Step, StepLabel, StepContent, Stepper, StepButton } from '@material-ui/core/'
|
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 DebugConnectionCheck from './SetupSteps/DebugConnectionCheck'
|
||||||
import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
|
import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
|
||||||
@@ -9,17 +9,11 @@ import VersionCheck from './SetupSteps/VersionCheck'
|
|||||||
import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
|
import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
|
||||||
import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund'
|
import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund'
|
||||||
import PeerConnection from './SetupSteps/PeerConnection'
|
import PeerConnection from './SetupSteps/PeerConnection'
|
||||||
import type {
|
|
||||||
ChequebookAddressResponse,
|
|
||||||
ChequebookBalanceResponse,
|
|
||||||
Health,
|
|
||||||
NodeAddresses,
|
|
||||||
Topology,
|
|
||||||
} from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
|
padding: theme.spacing(2),
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
@@ -29,147 +23,88 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
actionsContainer: {
|
actionsContainer: {
|
||||||
margin: theme.spacing(2),
|
margin: theme.spacing(2),
|
||||||
},
|
},
|
||||||
resetContainer: {
|
|
||||||
padding: theme.spacing(5),
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
function getSteps() {
|
interface Step {
|
||||||
return [
|
label: string
|
||||||
'Debug Connection Check',
|
condition: boolean
|
||||||
'Version Check',
|
isLoading: boolean
|
||||||
'Connect to Ethereum Blockchain',
|
component: ReactElement
|
||||||
'Deploy and Fund Chequebook',
|
|
||||||
'Node Connection Check',
|
|
||||||
'Connect to Peers',
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
nodeHealth: Health | null
|
nodeVersion: StatusNodeVersionHook
|
||||||
nodeApiHealth: boolean
|
ethereumConnection: StatusEthereumConnectionHook
|
||||||
nodeAddresses: NodeAddresses | null
|
debugApiConnection: StatusHookCommon
|
||||||
chequebookAddress: ChequebookAddressResponse | null
|
apiConnection: StatusHookCommon
|
||||||
chequebookBalance: ChequebookBalanceResponse | null
|
topology: StatusTopologyHook
|
||||||
beeRelease: LatestBeeRelease | null
|
chequebook: StatusChequebookHook
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStepContent(step: number, props: Props) {
|
export default function NodeSetupWorkflow({
|
||||||
const {
|
nodeVersion,
|
||||||
nodeHealth,
|
ethereumConnection,
|
||||||
debugApiHost,
|
debugApiConnection,
|
||||||
beeRelease,
|
apiConnection,
|
||||||
isLoadingBeeRelease,
|
topology,
|
||||||
nodeAddresses,
|
chequebook,
|
||||||
isLoadingNodeAddresses,
|
}: Props): ReactElement {
|
||||||
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
|
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const [activeStep, setActiveStep] = useState(0)
|
const [activeStep, setActiveStep] = useState(-1)
|
||||||
const [completed, setCompleted] = useState<{ [k: number]: boolean }>({})
|
|
||||||
const steps = getSteps()
|
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(() => {
|
useEffect(() => {
|
||||||
const handleComplete = (index: number) => {
|
// If the user already changed the active step we don't want to overwrite it
|
||||||
const newCompleted = completed
|
if (activeStep > 0 && activeStep < steps.length) return
|
||||||
newCompleted[index] = true
|
|
||||||
setCompleted(newCompleted)
|
|
||||||
}
|
|
||||||
|
|
||||||
const evaluateNodeStatus = () => {
|
// Select first step that is not OK
|
||||||
if (nodeHealth?.status === 'ok') {
|
for (let i = 0; i < steps.length; ++i) {
|
||||||
handleComplete(0)
|
if (!steps[i].condition) {
|
||||||
setActiveStep(1)
|
setActiveStep(i)
|
||||||
}
|
|
||||||
|
|
||||||
if (beeRelease && beeRelease.name === `v${nodeHealth?.version?.split('-')[0]}`) {
|
return
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evaluateNodeStatus()
|
}, [steps])
|
||||||
}, [
|
|
||||||
nodeHealth,
|
|
||||||
nodeApiHealth,
|
|
||||||
nodeAddresses,
|
|
||||||
chequebookAddress,
|
|
||||||
beeRelease,
|
|
||||||
chequebookBalance,
|
|
||||||
nodeTopology,
|
|
||||||
completed,
|
|
||||||
])
|
|
||||||
|
|
||||||
const handleNext = () => {
|
const handleNext = () => {
|
||||||
setActiveStep(prevActiveStep => prevActiveStep + 1)
|
setActiveStep(prevActiveStep => prevActiveStep + 1)
|
||||||
@@ -179,13 +114,9 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
|||||||
setActiveStep(prevActiveStep => prevActiveStep - 1)
|
setActiveStep(prevActiveStep => prevActiveStep - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSetupComplete = () => {
|
|
||||||
setStatusChecksVisible(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<Paper className={classes.root}>
|
||||||
<Typography variant="h4" gutterBottom>
|
<Typography variant="h5" gutterBottom>
|
||||||
Node Setup
|
Node Setup
|
||||||
<span style={{ marginLeft: '25px' }}>
|
<span style={{ marginLeft: '25px' }}>
|
||||||
<Button variant="outlined" size="small" onClick={() => window.location.reload()}>
|
<Button variant="outlined" size="small" onClick={() => window.location.reload()}>
|
||||||
@@ -195,20 +126,22 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
|||||||
</span>
|
</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
|
<Stepper nonLinear activeStep={activeStep} orientation="vertical">
|
||||||
{steps.map((label, index) => (
|
{steps.map(({ label, condition, component, isLoading }, index) => (
|
||||||
<Step key={label}>
|
<Step key={label}>
|
||||||
<StepLabel
|
<StepLabel
|
||||||
onClick={() => setActiveStep(index === activeStep ? 6 : index)}
|
disabled={isLoading}
|
||||||
|
onClick={() => setActiveStep(index === activeStep ? steps.length : index)}
|
||||||
StepIconComponent={() => {
|
StepIconComponent={() => {
|
||||||
if (completed[index]) {
|
if (isLoading) return <Autorenew style={{ height: '25px', cursor: 'pointer' }} />
|
||||||
return <CheckCircle style={{ color: '#32c48d', height: '25px', cursor: 'pointer' }} />
|
|
||||||
} else {
|
if (condition) return <CheckCircle style={{ color: '#32c48d', height: '25px', cursor: 'pointer' }} />
|
||||||
|
|
||||||
return <Error style={{ color: '#c9201f', height: '25px', cursor: 'pointer' }} />
|
return <Error style={{ color: '#c9201f', height: '25px', cursor: 'pointer' }} />
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<StepButton
|
<StepButton
|
||||||
onClick={() => setActiveStep(index === activeStep ? 6 : index)}
|
disabled={isLoading}
|
||||||
|
onClick={() => setActiveStep(index === activeStep ? steps.length : index)}
|
||||||
style={{ justifyContent: 'space-between' }}
|
style={{ justifyContent: 'space-between' }}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
@@ -220,14 +153,14 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
|||||||
</StepButton>
|
</StepButton>
|
||||||
</StepLabel>
|
</StepLabel>
|
||||||
<StepContent>
|
<StepContent>
|
||||||
<Typography component="div">{getStepContent(index, props)}</Typography>
|
<Typography component="div">{component}</Typography>
|
||||||
<div className={classes.actionsContainer}>
|
<div className={classes.actionsContainer}>
|
||||||
<div>
|
<div>
|
||||||
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
|
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="contained" color="primary" onClick={handleNext} className={classes.button}>
|
<Button variant="contained" color="primary" onClick={handleNext} className={classes.button}>
|
||||||
Next
|
{index < steps.length - 1 ? 'Next' : 'Finish'}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -235,17 +168,6 @@ export default function NodeSetupWorkflow(props: Props): ReactElement {
|
|||||||
</Step>
|
</Step>
|
||||||
))}
|
))}
|
||||||
</Stepper>
|
</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>
|
</Paper>
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,22 @@
|
|||||||
import { Typography } from '@material-ui/core/'
|
import { Typography } from '@material-ui/core/'
|
||||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
|
||||||
import EthereumAddress from '../../../components/EthereumAddress'
|
import EthereumAddress from '../../../components/EthereumAddress'
|
||||||
import DepositModal from '../../../components/DepositModal'
|
import DepositModal from '../../../components/DepositModal'
|
||||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||||
import type { ChequebookAddressResponse, ChequebookBalanceResponse } from '@ethersphere/bee-js'
|
|
||||||
import type { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusChequebookHook
|
||||||
chequebookAddress: ChequebookAddressResponse | null
|
|
||||||
chequebookBalance: ChequebookBalanceResponse | null
|
|
||||||
isLoadingChequebookAddress: boolean
|
|
||||||
isLoadingChequebookBalance: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const ChequebookDeployFund = (props: Props): ReactElement => (
|
const ChequebookDeployFund = ({ isLoading, chequebookAddress, chequebookBalance }: Props): ReactElement | null => {
|
||||||
|
if (isLoading) return null
|
||||||
|
|
||||||
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p style={{ marginBottom: '20px', display: 'flex' }}>
|
<p style={{ marginBottom: '20px', display: 'flex' }}>
|
||||||
<span style={{ marginRight: '40px' }}>Deploy chequebook and fund with BZZ</span>
|
{chequebookAddress?.chequebookaddress && <DepositModal />}
|
||||||
{props.chequebookAddress?.chequebookaddress ? <DepositModal /> : null}
|
|
||||||
</p>
|
</p>
|
||||||
<div style={{ marginBottom: '10px' }}>
|
<div style={{ marginBottom: '10px' }}>
|
||||||
{
|
{!(chequebookAddress?.chequebookaddress && chequebookBalance && chequebookBalance?.totalBalance > 0) && (
|
||||||
// FIXME: this should be broken up
|
|
||||||
/* eslint-disable no-nested-ternary */
|
|
||||||
props.chequebookAddress?.chequebookaddress &&
|
|
||||||
props.chequebookBalance &&
|
|
||||||
props.chequebookBalance?.totalBalance > 0 ? (
|
|
||||||
<div>
|
<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>
|
<span>
|
||||||
Your chequebook is either not deployed or funded. Run the below commands to get your address and deposit
|
Your chequebook is either not deployed or funded. Run the below commands to get your address and deposit
|
||||||
ETH. Then visit the BZZaar here{' '}
|
ETH. Then visit the BZZaar here{' '}
|
||||||
@@ -43,15 +27,14 @@ const ChequebookDeployFund = (props: Props): ReactElement => (
|
|||||||
</span>
|
</span>
|
||||||
<CodeBlockTabs showLineNumbers linux={`bee-get-addr`} mac={`bee-get-addr`} />
|
<CodeBlockTabs showLineNumbers linux={`bee-get-addr`} mac={`bee-get-addr`} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
/* eslint-enable no-nested-ternary */
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="subtitle1" gutterBottom>
|
<Typography variant="subtitle1" gutterBottom>
|
||||||
Chequebook Address
|
Chequebook Address
|
||||||
</Typography>
|
</Typography>
|
||||||
<EthereumAddress address={props.chequebookAddress?.chequebookaddress} network={'goerli'} />
|
<EthereumAddress address={chequebookAddress?.chequebookaddress} network={'goerli'} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
export default ChequebookDeployFund
|
export default ChequebookDeployFund
|
||||||
|
|||||||
@@ -1,39 +1,38 @@
|
|||||||
import type { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
|
import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
|
||||||
import MuiAlert from '@material-ui/lab/Alert'
|
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 ConnectToHost from '../../../components/ConnectToHost'
|
||||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||||
import type { Health } from '@ethersphere/bee-js'
|
import { debugApiHost } from '../../../constants'
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusHookCommon
|
||||||
nodeHealth: Health | null
|
|
||||||
debugApiHost: string
|
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 (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Connect to Bee Node Debug API</p>
|
{changeDebugApiUrl}
|
||||||
|
|
||||||
<div>
|
<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' }}>
|
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
||||||
We cannot connect to your nodes debug API at{' '}
|
We cannot connect to your nodes debug API at <Typography variant="button">{debugApiHost}</Typography>. Please
|
||||||
<Typography variant="button">{props.debugApiHost}</Typography>. Please check the following to troubleshoot
|
check the following to troubleshoot your issue.
|
||||||
your issue.
|
|
||||||
<Accordion style={{ marginTop: '20px' }}>
|
<Accordion style={{ marginTop: '20px' }}>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
||||||
<Typography>Troubleshoot</Typography>
|
<Typography>Troubleshoot</Typography>
|
||||||
@@ -41,18 +40,16 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
|||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Typography component="div">
|
<Typography component="div">
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>Check the status of your node by running the below command to see if your node is running.</li>
|
||||||
Check the status of your node by running the below command to see if your node is running.
|
|
||||||
</li>
|
|
||||||
<CodeBlockTabs
|
<CodeBlockTabs
|
||||||
showLineNumbers
|
showLineNumbers
|
||||||
linux={`sudo systemctl status bee`}
|
linux={`sudo systemctl status bee`}
|
||||||
mac={`brew services status swarm-bee`}
|
mac={`brew services status swarm-bee`}
|
||||||
/>
|
/>
|
||||||
<li>
|
<li>
|
||||||
If your node is running, check your firewall settings to make sure that port 1635 (or your
|
If your node is running, check your firewall settings to make sure that port 1635 (or your custom
|
||||||
custom specified port) is bound to localhost. If your node is not running try executing the
|
specified port) is bound to localhost. If your node is not running try executing the below command
|
||||||
below command to start your bee node
|
to start your bee node
|
||||||
</li>
|
</li>
|
||||||
<MuiAlert
|
<MuiAlert
|
||||||
style={{ marginTop: '10px', marginBottom: '10px' }}
|
style={{ marginTop: '10px', marginBottom: '10px' }}
|
||||||
@@ -61,9 +58,9 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
|||||||
severity="error"
|
severity="error"
|
||||||
>
|
>
|
||||||
Your debug node API should never be completely open to the internet. If you want to connect
|
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
|
remotely, make sure your firewall settings are set to only allow specific trusted IP addresses and
|
||||||
and block all other ports. A simple google search for "what is my ip" will show you
|
block all other ports. A simple google search for "what is my ip" will show you your
|
||||||
your computers public IP address to allow.
|
computers public IP address to allow.
|
||||||
</MuiAlert>
|
</MuiAlert>
|
||||||
<CodeBlockTabs
|
<CodeBlockTabs
|
||||||
showLineNumbers
|
showLineNumbers
|
||||||
@@ -77,11 +74,11 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
|||||||
mac={`brew services status swarm-bee \ntail -f /usr/local/var/log/swarm-bee/bee.log`}
|
mac={`brew services status swarm-bee \ntail -f /usr/local/var/log/swarm-bee/bee.log`}
|
||||||
/>
|
/>
|
||||||
<li>
|
<li>
|
||||||
Lastly, check your nodes configuration settings to validate the debug API is enabled and the
|
Lastly, check your nodes configuration settings to validate the debug API is enabled and the Cross
|
||||||
Cross Origin Resource Sharing (CORS) setting is configured to allow your host. Config parameter{' '}
|
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>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
|
<strong>cors-allowed-origins</strong> must be set to your host domain or IP. If edits are made to
|
||||||
to the configuration run the restart command below for changes to take effect.
|
the configuration run the restart command below for changes to take effect.
|
||||||
</li>
|
</li>
|
||||||
<CodeBlockTabs
|
<CodeBlockTabs
|
||||||
showLineNumbers
|
showLineNumbers
|
||||||
@@ -93,8 +90,6 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
|||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,34 +1,27 @@
|
|||||||
import type { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
import { Typography } from '@material-ui/core/'
|
import { Typography } from '@material-ui/core/'
|
||||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
|
||||||
import EthereumAddress from '../../../components/EthereumAddress'
|
import EthereumAddress from '../../../components/EthereumAddress'
|
||||||
import type { NodeAddresses } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusEthereumConnectionHook
|
||||||
nodeAddresses: NodeAddresses | null
|
|
||||||
isLoadingNodeAddresses: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function EthereumConnectionCheck(props: Props): ReactElement {
|
export default function EthereumConnectionCheck({ isLoading, isOk, nodeAddresses }: Props): ReactElement | null {
|
||||||
|
if (isLoading) return null
|
||||||
|
|
||||||
|
if (isOk) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Connect to the ethereum blockchain.</p>
|
<Typography variant="subtitle1" gutterBottom>
|
||||||
<div style={{ marginBottom: '10px' }}>
|
Node Address
|
||||||
{
|
</Typography>
|
||||||
// FIXME: this should be broken up
|
<EthereumAddress address={nodeAddresses?.ethereum} network={'goerli'} />
|
||||||
/* 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>
|
</div>
|
||||||
) : props.isLoadingNodeAddresses ? null : (
|
)
|
||||||
<div>
|
}
|
||||||
<Warning style={{ color: '#ff9800', marginRight: '7px', height: '18px' }} />
|
|
||||||
<span>Your not connected to the Ethereum network. </span>
|
return (
|
||||||
<p>
|
<p>
|
||||||
Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your
|
Your Bee node must have access to the Ethereum blockchain, so that it can interact and deploy your chequebook
|
||||||
chequebook contract. You can run{' '}
|
contract. You can run{' '}
|
||||||
<a href="https://github.com/goerli/testnet" rel="noreferrer" target="_blank">
|
<a href="https://github.com/goerli/testnet" rel="noreferrer" target="_blank">
|
||||||
your own Goerli node
|
your own Goerli node
|
||||||
</a>
|
</a>
|
||||||
@@ -40,17 +33,8 @@ export default function EthereumConnectionCheck(props: Props): ReactElement {
|
|||||||
<a href="https://infura.io/" rel="noreferrer" target="_blank">
|
<a href="https://infura.io/" rel="noreferrer" target="_blank">
|
||||||
Infura
|
Infura
|
||||||
</a>
|
</a>
|
||||||
. By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead,
|
. By default, Bee expects a local Goerli node at http://localhost:8545. To use a provider instead, simply change
|
||||||
simply change your <strong>--swap-endpoint</strong> in your configuration file.
|
your <strong>--swap-endpoint</strong> in your configuration file.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
|
||||||
) /* eslint-enable no-nested-ternary */
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<Typography variant="subtitle1" gutterBottom>
|
|
||||||
Node Address
|
|
||||||
</Typography>
|
|
||||||
<EthereumAddress address={props.nodeAddresses?.ethereum} network={'goerli'} />
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,29 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/'
|
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 ConnectToHost from '../../../components/ConnectToHost'
|
||||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||||
|
import { apiHost } from '../../../constants'
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusHookCommon
|
||||||
nodeApiHealth: boolean
|
|
||||||
apiHost: string
|
export default function NodeConnectionCheck({ isLoading, isOk }: Props): ReactElement | null {
|
||||||
}
|
if (isLoading) return null
|
||||||
|
|
||||||
export default function NodeConnectionCheck(props: Props): ReactElement {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<p>Connect to Bee Node API</p>
|
|
||||||
<div style={{ display: 'flex', marginBottom: '25px' }}>
|
<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' }}>
|
<span style={{ marginRight: '15px' }}>
|
||||||
Node API (<Typography variant="button">{props.apiHost}</Typography>)
|
Node API (<Typography variant="button">{apiHost}</Typography>)
|
||||||
</span>
|
</span>
|
||||||
<ConnectToHost hostName="api_host" defaultHost={props.apiHost} />
|
<ConnectToHost hostName="api_host" defaultHost={apiHost} />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{!props.nodeApiHealth ? (
|
{!isOk && (
|
||||||
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
|
||||||
We cannot connect to your nodes API at <Typography variant="button">{props.apiHost}</Typography>. Please
|
We cannot connect to your nodes API at <Typography variant="button">{apiHost}</Typography>. Please check the
|
||||||
check the following to troubleshoot your issue.
|
following to troubleshoot your issue.
|
||||||
<Accordion style={{ marginTop: '20px' }}>
|
<Accordion style={{ marginTop: '20px' }}>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
<AccordionSummary expandIcon={<ExpandMoreSharp />} aria-controls="panel1a-content" id="panel1a-header">
|
||||||
<Typography>Troubleshoot</Typography>
|
<Typography>Troubleshoot</Typography>
|
||||||
@@ -64,7 +58,7 @@ export default function NodeConnectionCheck(props: Props): ReactElement {
|
|||||||
</AccordionDetails>
|
</AccordionDetails>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,42 +1,19 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
import { Typography } from '@material-ui/core/'
|
import { Typography } from '@material-ui/core/'
|
||||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
|
||||||
import { Topology } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusTopologyHook
|
||||||
nodeTopology: Topology | null
|
|
||||||
isLoadingNodeTopology: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function PeerConnection(props: Props): ReactElement {
|
export default function PeerConnection({ isLoading, isOk, topology }: Props): ReactElement | null {
|
||||||
return (
|
if (isLoading) return null
|
||||||
<div>
|
|
||||||
<p>Connect to Peers</p>
|
const peers = (
|
||||||
<div style={{ marginBottom: '10px' }}>
|
<div style={{ display: 'flex', marginTop: '15px' }}>
|
||||||
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 */
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div style={{ display: 'flex' }}>
|
|
||||||
<div style={{ marginRight: '30px' }}>
|
<div style={{ marginRight: '30px' }}>
|
||||||
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
<Typography component="div" variant="subtitle1" gutterBottom color="textSecondary">
|
||||||
<span>Connected Peers</span>
|
<span>Connected Peers</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="h2" variant="h5">
|
<Typography component="h2" variant="h5">
|
||||||
{props.nodeTopology?.connected}
|
{topology?.connected ? topology.connected : '-'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -44,10 +21,25 @@ export default function PeerConnection(props: Props): ReactElement {
|
|||||||
<span>Discovered Nodes</span>
|
<span>Discovered Nodes</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="h2" variant="h5">
|
<Typography component="h2" variant="h5">
|
||||||
{props.nodeTopology?.population}
|
{topology?.population ? topology.population : '-'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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,70 +1,26 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import type { ReactElement } from 'react'
|
||||||
import { Typography } from '@material-ui/core/'
|
import { Typography } from '@material-ui/core/'
|
||||||
import { CheckCircle, Warning } from '@material-ui/icons/'
|
|
||||||
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
import CodeBlockTabs from '../../../components/CodeBlockTabs'
|
||||||
import { Health } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
interface Props {
|
type Props = StatusNodeVersionHook
|
||||||
beeRelease: LatestBeeRelease | null
|
|
||||||
isLoadingBeeRelease: boolean
|
|
||||||
nodeHealth: Health | null
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function VersionCheck(props: Props): ReactElement {
|
export default function VersionCheck({
|
||||||
return (
|
isLoading,
|
||||||
<div>
|
isOk,
|
||||||
<p>
|
userVersion,
|
||||||
Check to make sure the latest version of{' '}
|
latestVersion,
|
||||||
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
latestUrl,
|
||||||
Bee
|
}: Props): ReactElement | null {
|
||||||
</a>{' '}
|
if (isLoading) return null
|
||||||
is running
|
|
||||||
</p>
|
const version = (
|
||||||
{
|
|
||||||
// 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={{ display: 'flex' }}>
|
||||||
<div style={{ marginRight: '30px' }}>
|
<div style={{ marginRight: '30px' }}>
|
||||||
<p>
|
<p>
|
||||||
<span>Current Version</span>
|
<span>User Version</span>
|
||||||
</p>
|
</p>
|
||||||
<Typography component="h5" variant="h5">
|
<Typography component="h5" variant="h5">
|
||||||
<span>{props.nodeHealth?.version ? ` v${props.nodeHealth?.version?.split('-')[0]}` : '-'}</span>
|
<span>{userVersion}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -72,10 +28,41 @@ export default function VersionCheck(props: Props): ReactElement {
|
|||||||
<span>Latest Version</span>
|
<span>Latest Version</span>
|
||||||
</p>
|
</p>
|
||||||
<Typography component="h5" variant="h5">
|
<Typography component="h5" variant="h5">
|
||||||
<span>{props.beeRelease && props.beeRelease.name ? props.beeRelease.name : '-'}</span>
|
<span>{latestVersion}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,15 @@ import { Link } from 'react-router-dom'
|
|||||||
import { createStyles, makeStyles } from '@material-ui/core/styles'
|
import { createStyles, makeStyles } from '@material-ui/core/styles'
|
||||||
import { Card, CardContent, Typography, Chip, Button } from '@material-ui/core/'
|
import { Card, CardContent, Typography, Chip, Button } from '@material-ui/core/'
|
||||||
import { CheckCircle, Error, ArrowRight, ArrowDropUp } from '@material-ui/icons/'
|
import { CheckCircle, Error, ArrowRight, ArrowDropUp } from '@material-ui/icons/'
|
||||||
import { Skeleton } from '@material-ui/lab'
|
import { NodeAddresses, Topology } from '@ethersphere/bee-js'
|
||||||
import type { Health, NodeAddresses, Topology } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() =>
|
const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
},
|
flex: '1 1 auto',
|
||||||
details: {
|
|
||||||
display: 'flex',
|
|
||||||
flex: '1 0 auto',
|
|
||||||
|
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
},
|
},
|
||||||
content: {
|
|
||||||
flex: '1 0 auto',
|
|
||||||
},
|
|
||||||
status: {
|
status: {
|
||||||
color: '#2145a0',
|
color: '#2145a0',
|
||||||
backgroundColor: '#e1effe',
|
backgroundColor: '#e1effe',
|
||||||
@@ -29,54 +21,48 @@ const useStyles = makeStyles(() =>
|
|||||||
)
|
)
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
nodeHealth: Health | null
|
nodeAddresses: NodeAddresses | null
|
||||||
loadingNodeHealth: boolean
|
nodeTopology: Topology | null
|
||||||
beeRelease: LatestBeeRelease | null
|
userBeeVersion: string | null
|
||||||
loadingBeeRelease: boolean
|
latestBeeVersion: string | null
|
||||||
nodeAddresses: NodeAddresses
|
isOk: boolean
|
||||||
nodeTopology: Topology
|
|
||||||
loadingNodeTopology: boolean
|
|
||||||
setStatusChecksVisible: (value: boolean) => void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function StatusCard(props: Props): ReactElement {
|
function StatusCard({
|
||||||
|
userBeeVersion,
|
||||||
|
nodeAddresses,
|
||||||
|
nodeTopology,
|
||||||
|
latestBeeVersion,
|
||||||
|
isOk,
|
||||||
|
}: Props): ReactElement | null {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
const [underlayAddressesVisible, setUnderlayAddresessVisible] = useState<boolean>(false)
|
const [underlayAddressesVisible, setUnderlayAddresessVisible] = useState<boolean>(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Card>
|
||||||
<Card className={classes.root}>
|
<CardContent 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' }}>
|
<Typography component="h5" variant="h5" style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||||
{props.nodeHealth.status === 'ok' ? (
|
{isOk && (
|
||||||
<div>
|
<div>
|
||||||
<CheckCircle style={{ color: '#32c48d', marginRight: '7px' }} />
|
<CheckCircle style={{ color: '#32c48d', marginRight: '7px' }} />
|
||||||
<span>Connected to Bee Node</span>
|
<span>Your Bee node is running as expected</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
|
{!isOk && (
|
||||||
<div>
|
<div>
|
||||||
<Error style={{ color: '#c9201f', marginRight: '7px' }} />
|
<Error style={{ color: '#c9201f', marginRight: '7px' }} />
|
||||||
<span>Could not connect to Bee Node</span>
|
<span>Could not connect to Bee Node</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
color="primary"
|
|
||||||
size="small"
|
|
||||||
style={{ marginLeft: '12px' }}
|
|
||||||
onClick={() => props.setStatusChecksVisible(true)}
|
|
||||||
>
|
|
||||||
View Status Checks
|
|
||||||
</Button>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{isOk && (
|
||||||
|
<>
|
||||||
<div style={{ marginBottom: '20px' }}>
|
<div style={{ marginBottom: '20px' }}>
|
||||||
<span style={{ marginRight: '20px' }}>Discovered Nodes: {props.nodeTopology.population}</span>
|
<span style={{ marginRight: '20px' }}>Discovered Nodes: {nodeTopology?.population}</span>
|
||||||
<span style={{ marginRight: '20px' }}>
|
<span style={{ marginRight: '20px' }}>
|
||||||
<span>Connected Peers: </span>
|
<span>Connected Peers: </span>
|
||||||
<Link to="/peers/">{props.nodeTopology.connected}</Link>
|
<Link to="/peers/">{nodeTopology?.connected}</Link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -84,39 +70,32 @@ function StatusCard(props: Props): ReactElement {
|
|||||||
<span>AGENT: </span>
|
<span>AGENT: </span>
|
||||||
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
<a href="https://github.com/ethersphere/bee" rel="noreferrer" target="_blank">
|
||||||
Bee
|
Bee
|
||||||
</a>
|
</a>{' '}
|
||||||
<span>{props.nodeHealth?.version ? ` v${props.nodeHealth.version}` : '-'}</span>
|
<span>{userBeeVersion || '-'}</span>
|
||||||
{
|
{userBeeVersion && latestBeeVersion && userBeeVersion === latestBeeVersion ? (
|
||||||
// FIXME: this should be broken up
|
|
||||||
/* eslint-disable no-nested-ternary */
|
|
||||||
props.beeRelease && props.beeRelease.name === `v${props.nodeHealth?.version?.split('-')[0]}` ? (
|
|
||||||
<Chip
|
<Chip
|
||||||
style={{ marginLeft: '7px', color: '#2145a0' }}
|
style={{ marginLeft: '7px', color: '#2145a0' }}
|
||||||
size="small"
|
size="small"
|
||||||
label="latest"
|
label="latest"
|
||||||
className={classes.status}
|
className={classes.status}
|
||||||
/>
|
/>
|
||||||
) : props.loadingBeeRelease ? (
|
|
||||||
''
|
|
||||||
) : (
|
) : (
|
||||||
<Typography variant="button">update</Typography>
|
<Typography variant="button">update</Typography>
|
||||||
)
|
)}
|
||||||
/* eslint-enable no-nested-ternary */
|
|
||||||
}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||||
<span>PUBLIC KEY: </span>
|
<span>PUBLIC KEY: </span>
|
||||||
<span>{props.nodeAddresses.public_key ? props.nodeAddresses.public_key : '-'}</span>
|
<span>{nodeAddresses?.public_key ? nodeAddresses.public_key : '-'}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||||
<span>PSS PUBLIC KEY: </span>
|
<span>PSS PUBLIC KEY: </span>
|
||||||
<span>{props.nodeAddresses.pss_public_key ? props.nodeAddresses.pss_public_key : '-'}</span>
|
<span>{nodeAddresses?.pss_public_key ? nodeAddresses.pss_public_key : '-'}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography component="div" variant="subtitle2" gutterBottom>
|
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||||
<Typography component="div" style={{ marginTop: '20px' }}>
|
|
||||||
<span>OVERLAY ADDRESS (PEER ID): </span>
|
<span>OVERLAY ADDRESS (PEER ID): </span>
|
||||||
<span>{props.nodeAddresses.overlay ? props.nodeAddresses.overlay : '-'}</span>
|
<span>{nodeAddresses?.overlay ? nodeAddresses.overlay : '-'}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
|
<Typography component="div" variant="subtitle2" gutterBottom>
|
||||||
<Typography component="div" onClick={() => setUnderlayAddresessVisible(!underlayAddressesVisible)}>
|
<Typography component="div" onClick={() => setUnderlayAddresessVisible(!underlayAddressesVisible)}>
|
||||||
<Button color="primary" style={{ padding: 0, marginTop: '6px' }}>
|
<Button color="primary" style={{ padding: 0, marginTop: '6px' }}>
|
||||||
{underlayAddressesVisible ? (
|
{underlayAddressesVisible ? (
|
||||||
@@ -127,26 +106,19 @@ function StatusCard(props: Props): ReactElement {
|
|||||||
<span>Underlay Addresses</span>
|
<span>Underlay Addresses</span>
|
||||||
</Button>
|
</Button>
|
||||||
</Typography>
|
</Typography>
|
||||||
{underlayAddressesVisible ? (
|
{underlayAddressesVisible && (
|
||||||
<div>
|
<div>
|
||||||
{props.nodeAddresses.underlay
|
{nodeAddresses?.underlay.map(item => (
|
||||||
? props.nodeAddresses.underlay.map(item => <li key={item}>{item}</li>)
|
<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>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+55
-123
@@ -1,143 +1,75 @@
|
|||||||
import { useState, useEffect, ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import axios from 'axios'
|
|
||||||
import { Container, CircularProgress } from '@material-ui/core'
|
import { Container, CircularProgress } from '@material-ui/core'
|
||||||
|
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
||||||
|
|
||||||
import NodeSetupWorkflow from './NodeSetupWorkflow'
|
import NodeSetupWorkflow from './NodeSetupWorkflow'
|
||||||
import StatusCard from './StatusCard'
|
import StatusCard from './StatusCard'
|
||||||
import EthereumAddressCard from '../../components/EthereumAddressCard'
|
import EthereumAddressCard from '../../components/EthereumAddressCard'
|
||||||
import {
|
import {
|
||||||
useApiHealth,
|
useStatusEthereumConnection,
|
||||||
useDebugApiHealth,
|
useStatusNodeVersion,
|
||||||
useApiNodeAddresses,
|
useStatusDebugConnection,
|
||||||
useApiChequebookAddress,
|
useStatusConnection,
|
||||||
useApiNodeTopology,
|
useStatusTopology,
|
||||||
useApiChequebookBalance,
|
useStatusChequebook,
|
||||||
} from '../../hooks/apiHooks'
|
} from '../../hooks/status'
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
root: {
|
||||||
|
width: '100%',
|
||||||
|
display: 'grid',
|
||||||
|
rowGap: theme.spacing(3),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
export default function Status(): ReactElement {
|
export default function Status(): ReactElement {
|
||||||
const [beeRelease, setBeeRelease] = useState<LatestBeeRelease | null>(null)
|
const classes = useStyles()
|
||||||
const [isLoadingBeeRelease, setIsLoadingBeeRelease] = useState<boolean>(false)
|
|
||||||
|
|
||||||
const [apiHost, setApiHost] = useState('')
|
const nodeVersion = useStatusNodeVersion()
|
||||||
const [debugApiHost, setDebugApiHost] = useState('')
|
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()
|
// If any check data are still loading
|
||||||
const { nodeHealth, isLoadingNodeHealth } = useDebugApiHealth()
|
if (!checks.every(c => !c.isLoading)) {
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (
|
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' }}>
|
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
||||||
<CircularProgress />
|
<CircularProgress />
|
||||||
</Container>
|
</Container>
|
||||||
) : (
|
)
|
||||||
<NodeSetupWorkflow
|
}
|
||||||
beeRelease={beeRelease}
|
|
||||||
isLoadingBeeRelease={isLoadingBeeRelease}
|
return (
|
||||||
nodeHealth={nodeHealth}
|
<div className={classes.root}>
|
||||||
isLoadingNodeHealth={isLoadingNodeHealth}
|
<StatusCard
|
||||||
nodeAddresses={nodeAddresses}
|
userBeeVersion={nodeVersion.userVersion}
|
||||||
isLoadingNodeAddresses={isLoadingNodeAddresses}
|
latestBeeVersion={nodeVersion.latestVersion}
|
||||||
nodeTopology={nodeTopology}
|
isOk={checks.every(c => c.isOk)}
|
||||||
isLoadingNodeTopology={isLoadingNodeTopology}
|
nodeTopology={topology.topology}
|
||||||
nodeApiHealth={health}
|
nodeAddresses={ethereumConnection.nodeAddresses}
|
||||||
isLoadingHealth={isLoadingHealth}
|
/>
|
||||||
chequebookAddress={chequebookAddress}
|
{ethereumConnection.nodeAddresses && chequebook.chequebookAddress && (
|
||||||
isLoadingChequebookAddress={isLoadingChequebookAddress}
|
<EthereumAddressCard
|
||||||
chequebookBalance={chequebookBalance}
|
nodeAddresses={ethereumConnection.nodeAddresses}
|
||||||
isLoadingChequebookBalance={isLoadingChequebookBalance}
|
isLoadingNodeAddresses={ethereumConnection.isLoading}
|
||||||
apiHost={apiHost}
|
chequebookAddress={chequebook.chequebookAddress}
|
||||||
debugApiHost={debugApiHost}
|
isLoadingChequebookAddress={chequebook.isLoading}
|
||||||
setStatusChecksVisible={setStatusChecksVisible}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<NodeSetupWorkflow
|
||||||
|
nodeVersion={nodeVersion}
|
||||||
|
ethereumConnection={ethereumConnection}
|
||||||
|
debugApiConnection={debugApiConnection}
|
||||||
|
apiConnection={apiConnection}
|
||||||
|
topology={topology}
|
||||||
|
chequebook={chequebook}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+21
@@ -4,3 +4,24 @@ interface LatestBeeRelease {
|
|||||||
name: string
|
name: string
|
||||||
html_url: string
|
html_url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface StatusHookCommon {
|
||||||
|
isLoading: boolean
|
||||||
|
isOk: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatusNodeVersionHook extends StatusHookCommon {
|
||||||
|
userVersion: string
|
||||||
|
latestVersion: string
|
||||||
|
latestUrl: string
|
||||||
|
}
|
||||||
|
interface StatusEthereumConnectionHook extends StatusHookCommon {
|
||||||
|
nodeAddresses: NodeAddresses | null
|
||||||
|
}
|
||||||
|
interface StatusTopologyHook extends StatusHookCommon {
|
||||||
|
topology: Topology | null
|
||||||
|
}
|
||||||
|
interface StatusChequebookHook extends StatusHookCommon {
|
||||||
|
chequebookBalance: ChequebookBalanceResponse | null
|
||||||
|
chequebookAddress: ChequebookAddressResponse | null
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user