diff --git a/src/components/ConnectToHost.tsx b/src/components/ConnectToHost.tsx deleted file mode 100644 index 4c5b084..0000000 --- a/src/components/ConnectToHost.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React, { ReactElement, useState } from 'react' -import { TextField, Button } from '@material-ui/core' - -interface Props { - defaultHost?: string - setHost: (host: string) => void -} - -export default function ConnectToHost(props: Props): ReactElement { - const [hostInputVisible, toggleHostInputVisibility] = useState(false) - const [host, setHost] = useState('') - - const handleNewHostConnection = () => { - if (host) { - props.setHost(host) - toggleHostInputVisibility(!hostInputVisible) - } - } - - return ( -
- {hostInputVisible ? ( -
- setHost(e.target.value)} - style={{ marginRight: '15px', minWidth: '300px' }} - /> - - -
- ) : ( - - )} -
- ) -} diff --git a/src/components/EthereumAddressCard.tsx b/src/components/EthereumAddressCard.tsx deleted file mode 100644 index 1759ca8..0000000 --- a/src/components/EthereumAddressCard.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { ReactElement } from 'react' - -import { createStyles, makeStyles } from '@material-ui/core/styles' -import { Card, CardContent, Typography } from '@material-ui/core/' - -import EthereumAddress from '../components/EthereumAddress' - -import type { ChequebookAddressResponse, NodeAddresses } from '@ethersphere/bee-js' - -const useStyles = makeStyles(() => - createStyles({ - root: { - display: 'flex', - alignItems: 'center', - justifyContent: 'space-around', - flexWrap: 'wrap', - }, - details: { - display: 'flex', - flexDirection: 'column', - }, - content: { - flex: '1 0 auto', - }, - }), -) - -interface Props { - nodeAddresses: NodeAddresses | null - chequebookAddress: ChequebookAddressResponse | null -} - -function EthereumAddressCard(props: Props): ReactElement { - const classes = useStyles() - - return ( - -
- - - Ethereum Address - - - -
- -
- - - Chequebook Contract Address - - - -
-
- ) -} - -export default EthereumAddressCard diff --git a/src/components/ExpandableListItem.tsx b/src/components/ExpandableListItem.tsx index 3ce97ec..0161f07 100644 --- a/src/components/ExpandableListItem.tsx +++ b/src/components/ExpandableListItem.tsx @@ -24,7 +24,7 @@ const useStyles = makeStyles((theme: Theme) => ) interface Props { - label?: string + label?: ReactNode value?: ReactNode tooltip?: string } diff --git a/src/components/ExpandableListItemInput.tsx b/src/components/ExpandableListItemInput.tsx new file mode 100644 index 0000000..3e0bf95 --- /dev/null +++ b/src/components/ExpandableListItemInput.tsx @@ -0,0 +1,103 @@ +import { ReactElement, useState } from 'react' +import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import Collapse from '@material-ui/core/Collapse' +import { ListItem, Typography, Grid, IconButton, InputBase, Button } from '@material-ui/core' +import { Edit, Minus, RotateCcw, Check } from 'react-feather' + +import ExpandableListItemActions from './ExpandableListItemActions' + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + header: { + backgroundColor: theme.palette.background.paper, + marginBottom: theme.spacing(0.25), + borderLeft: `${theme.spacing(0.25)}px solid rgba(0,0,0,0)`, + wordBreak: 'break-word', + }, + headerOpen: { + borderLeft: `${theme.spacing(0.25)}px solid ${theme.palette.primary.main}`, + }, + copyValue: { + cursor: 'pointer', + padding: theme.spacing(1), + borderRadius: 0, + '&:hover': { + backgroundColor: '#fcf2e8', + color: theme.palette.primary.main, + }, + }, + content: { + marginTop: theme.spacing(1), + marginBottom: theme.spacing(1), + }, + keyMargin: { + marginRight: theme.spacing(1), + }, + }), +) + +interface Props { + label: string + value: string + onConfirm: (value: string) => void +} + +export default function ExpandableListItemKey({ label, value, onConfirm }: Props): ReactElement | null { + const classes = useStyles() + const [open, setOpen] = useState(false) + const [inputValue, setInputValue] = useState(value) + const toggleOpen = () => setOpen(!open) + + return ( + <> + + + + {label && {label}} + +
+ {!open && value} + + {open ? ( + + ) : ( + + )} + +
+
+
+ + setInputValue(e.target.value)} + fullWidth + className={classes.content} + autoFocus + /> + +
+
+ + + + + + + + ) +} diff --git a/src/components/ExpandableListItemNote.tsx b/src/components/ExpandableListItemNote.tsx new file mode 100644 index 0000000..ee2168e --- /dev/null +++ b/src/components/ExpandableListItemNote.tsx @@ -0,0 +1,32 @@ +import { ReactElement, ReactNode } from 'react' +import { makeStyles, Theme, createStyles } from '@material-ui/core/styles' +import { Typography } from '@material-ui/core' +import ListItem from '@material-ui/core/ListItem' + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + header: { + backgroundColor: '#F7F7F7', + marginBottom: theme.spacing(0.25), + }, + typography: { + color: '#242424', + }, + }), +) + +interface Props { + children?: ReactNode | ReactNode[] +} + +export default function ExpandableListItemNote({ children }: Props): ReactElement | null { + const classes = useStyles() + + return ( + + + {children} + + + ) +} diff --git a/src/components/SideBarStatus.tsx b/src/components/SideBarStatus.tsx index b2c8c4f..2279e4b 100644 --- a/src/components/SideBarStatus.tsx +++ b/src/components/SideBarStatus.tsx @@ -5,6 +5,7 @@ import { ArrowRight } from 'react-feather' import { createStyles, Theme, makeStyles } from '@material-ui/core/styles' import { ListItemText, ListItemIcon, ListItem, Typography } from '@material-ui/core' import { Context } from '../providers/Bee' +import StatusIcon from './StatusIcon' const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -50,7 +51,7 @@ interface Props { } export default function SideBarItem({ path }: Props): ReactElement { - const { status } = useContext(Context) + const { status, isLoading } = useContext(Context) const classes = useStyles() const location = useLocation() const isSelected = Boolean(matchPath(location.pathname, { path, exact: true })) @@ -62,17 +63,8 @@ export default function SideBarItem({ path }: Props): ReactElement { selected={isSelected} disableRipple > - - + + {`Node ${status.all ? 'OK' : 'Error'}`}} diff --git a/src/components/StatCard.tsx b/src/components/StatCard.tsx deleted file mode 100644 index e581c97..0000000 --- a/src/components/StatCard.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Card, CardContent, Typography } from '@material-ui/core/' -import { makeStyles } from '@material-ui/core/styles' -import { Skeleton } from '@material-ui/lab' -import type { ReactElement } from 'react' -import { Title } from './Title' - -const useStyles = makeStyles({ - root: { - minWidth: 275, - }, -}) - -interface Props { - label: string - statistic?: string - loading?: boolean - tooltip?: string -} - -export default function StatCard({ loading, label, statistic, tooltip }: Props): ReactElement { - const classes = useStyles() - - return ( - - - {loading && ( - <> - - - - )} - {!loading && ( - <> - - <Typography variant="h5" component="h2"> - {statistic} - </Typography> - </> - )} - </CardContent> - </Card> - ) -} diff --git a/src/components/StatusIcon.tsx b/src/components/StatusIcon.tsx new file mode 100644 index 0000000..bab8969 --- /dev/null +++ b/src/components/StatusIcon.tsx @@ -0,0 +1,28 @@ +import type { ReactElement } from 'react' +import { CircularProgress } from '@material-ui/core' + +interface Props { + isOk: boolean + isLoading?: boolean + size?: number | string + className?: string +} + +export default function StatusIcon({ isOk, size, className, isLoading }: Props): ReactElement { + const s = size || '1rem' + + if (isLoading) return <CircularProgress size={s} className={className} /> + + return ( + <span + className={className} + style={{ + backgroundColor: isOk ? '#1de600' : '#ff3a52', + height: s, + width: s, + borderRadius: '50%', + display: 'inline-block', + }} + /> + ) +} diff --git a/src/components/Title.tsx b/src/components/Title.tsx deleted file mode 100644 index 9819d70..0000000 --- a/src/components/Title.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { Grid, Tooltip, Typography } from '@material-ui/core/' -import { makeStyles } from '@material-ui/core/styles' -import { Info } from '@material-ui/icons' -import type { ReactElement } from 'react' - -interface TitleProps { - label: string - tooltip?: string -} - -const useStyles = makeStyles({ - title: { - fontSize: 16, - }, -}) - -export function Title({ label, tooltip }: TitleProps): ReactElement { - const classes = useStyles() - - if (!tooltip) { - return ( - <Typography className={classes.title} color="textSecondary" gutterBottom> - {label} - </Typography> - ) - } - - // span is needed as Tooltip expects a non-functional element! - return ( - <Tooltip title={tooltip}> - <span> - <Grid container direction="row" justify="space-between"> - <Typography className={classes.title} color="textSecondary" gutterBottom> - {label} - </Typography> - <Info /> - </Grid> - </span> - </Tooltip> - ) -} diff --git a/src/components/TopologyStats.tsx b/src/components/TopologyStats.tsx index 65ec8ad..c383b60 100644 --- a/src/components/TopologyStats.tsx +++ b/src/components/TopologyStats.tsx @@ -1,7 +1,6 @@ import type { Topology } from '@ethersphere/bee-js' import type { ReactElement } from 'react' import { pickThreshold, ThresholdValues } from '../utils/threshold' -import ExpandableList from './ExpandableList' import ExpandableListItem from './ExpandableListItem' interface Props { @@ -20,7 +19,7 @@ const TopologyStats = (props: Props): ReactElement => { const percentageText = Math.round((actualTotalScore / maximumTotalScore) * 100) + '%' return ( - <ExpandableList label="Connectivity" defaultOpen> + <> <ExpandableListItem label="Overall Health Indicator" value={percentageText} /> <ExpandableListItem label="Connected Peers" @@ -37,7 +36,7 @@ const TopologyStats = (props: Props): ReactElement => { value={props.topology?.depth.toString()} tooltip={thresholds.depth.explanation} /> - </ExpandableList> + </> ) } diff --git a/src/containers/DepositModal.tsx b/src/containers/DepositModal.tsx index 2ec5694..e76bdd8 100644 --- a/src/containers/DepositModal.tsx +++ b/src/containers/DepositModal.tsx @@ -12,7 +12,7 @@ export default function DepositModal(): ReactElement { <WithdrawDepositModal successMessage="Successful deposit." errorMessage="Error with depositing" - dialogMessage="Specify the amount of BZZ you would like to withdraw from your node." + dialogMessage="Specify the amount of BZZ you would like to deposit to your node." label="Deposit" icon={<Download size="1rem" />} min={new BigNumber(0)} diff --git a/src/pages/info/index.tsx b/src/pages/info/index.tsx index 9643fea..38f4a3d 100644 --- a/src/pages/info/index.tsx +++ b/src/pages/info/index.tsx @@ -56,7 +56,9 @@ export default function Status(): ReactElement { <ExpandableListItemKey label="Ethereum address" value={nodeAddresses?.ethereum || ''} /> <ExpandableListItemKey label="Chequebook contract address" value={chequebookAddress?.chequebookAddress || ''} /> </ExpandableList> - <TopologyStats topology={topology} /> + <ExpandableList label="Connectivity" defaultOpen> + <TopologyStats topology={topology} /> + </ExpandableList> </div> ) } diff --git a/src/pages/status/SetupSteps/ChequebookDeployFund.tsx b/src/pages/status/SetupSteps/ChequebookDeployFund.tsx index 6a926a1..fc745fe 100644 --- a/src/pages/status/SetupSteps/ChequebookDeployFund.tsx +++ b/src/pages/status/SetupSteps/ChequebookDeployFund.tsx @@ -1,35 +1,48 @@ -import { Typography } from '@material-ui/core/' -import EthereumAddress from '../../../components/EthereumAddress' +import { useContext } from 'react' import DepositModal from '../../../containers/DepositModal' import type { ReactElement } from 'react' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItemKey from '../../../components/ExpandableListItemKey' +import ExpandableListItemActions from '../../../components/ExpandableListItemActions' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import StatusIcon from '../../../components/StatusIcon' +import { Context } from '../../../providers/Bee' -interface Props extends StatusHookCommon { - chequebookAddress?: string -} +const ChequebookDeployFund = (): ReactElement | null => { + const { status, isLoading, chequebookAddress } = useContext(Context) + const isOk = status.chequebook -const ChequebookDeployFund = ({ chequebookAddress, isOk }: Props): ReactElement | null => { return ( - <div> - <p style={{ marginBottom: '20px', display: 'flex' }}>{chequebookAddress && <DepositModal />}</p> - <div style={{ marginBottom: '10px' }}> - {!isOk && ( - <div> - <span> - Your chequebook is either not deployed or funded. To run the node you will need xDAI and xBZZ on the xDai - network. You may need to aquire BZZ (e.g. <a href="https://bzz.exchange/">bzz.exchange</a>) and bridge it - to the xDai network through the <a href="https://omni.xdaichain.com/bridge">omni bridge</a>. To pay the - transaction fees, you will also need xDAI token. You can purchase DAI on the network and bridge it to xDai - network through the <a href="https://bridge.xdaichain.com/">xDai Bridge</a>. See the{' '} - <a href="https://www.xdaichain.com/#xdai-stable-chain">official xDai website</a> for more information. - </span> - </div> + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Chequebook Deployment & Funding + </> + } + > + <ExpandableListItemNote> + {isOk ? ( + 'Your chequebook is deployed and funded' + ) : ( + <> + Your chequebook is either not deployed or funded. To run the node you will need xDAI and xBZZ on the xDai + network. You may need to aquire BZZ (e.g. <a href="https://bzz.exchange/">bzz.exchange</a>) and bridge it to + the xDai network through the <a href="https://omni.xdaichain.com/bridge">omni bridge</a>. To pay the + transaction fees, you will also need xDAI token. You can purchase DAI on the network and bridge it to xDai + network through the <a href="https://bridge.xdaichain.com/">xDai Bridge</a>. See the{' '} + <a href="https://www.xdaichain.com/#xdai-stable-chain">official xDai website</a> for more information. + </> )} - </div> - <Typography variant="subtitle1" gutterBottom> - Chequebook Address - </Typography> - <EthereumAddress address={chequebookAddress} /> - </div> + </ExpandableListItemNote> + {chequebookAddress && ( + <> + <ExpandableListItemKey label="Chequebook Address" value={chequebookAddress.chequebookAddress} /> + <ExpandableListItemActions> + <DepositModal /> + </ExpandableListItemActions> + </> + )} + </ExpandableList> ) } diff --git a/src/pages/status/SetupSteps/DebugConnectionCheck.tsx b/src/pages/status/SetupSteps/DebugConnectionCheck.tsx index dc2fb95..4fbb64d 100644 --- a/src/pages/status/SetupSteps/DebugConnectionCheck.tsx +++ b/src/pages/status/SetupSteps/DebugConnectionCheck.tsx @@ -1,99 +1,87 @@ import { ReactElement, useContext } from 'react' -import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/' import MuiAlert from '@material-ui/lab/Alert' -import { ExpandMoreSharp } from '@material-ui/icons/' -import ConnectToHost from '../../../components/ConnectToHost' import CodeBlockTabs from '../../../components/CodeBlockTabs' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItem from '../../../components/ExpandableListItem' +import ExpandableListItemInput from '../../../components/ExpandableListItemInput' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import StatusIcon from '../../../components/StatusIcon' import { Context as SettingsContext } from '../../../providers/Settings' +import { Context } from '../../../providers/Bee' -type Props = StatusHookCommon - -export default function NodeConnectionCheck({ isOk }: Props): ReactElement | null { +export default function NodeConnectionCheck(): ReactElement | null { + const { status, isLoading } = useContext(Context) const { setDebugApiUrl, apiDebugUrl } = useContext(SettingsContext) - - const changeDebugApiUrl = ( - <div style={{ display: 'flex', marginTop: '25px', marginBottom: '25px' }}> - <span style={{ marginRight: '15px' }}> - Debug API (<Typography variant="button">{apiDebugUrl}</Typography>) - </span> - <ConnectToHost - setHost={(host: string) => { - console.log(host) // eslint-disable-line - setDebugApiUrl(host) - }} - defaultHost={apiDebugUrl} - /> - </div> - ) - - if (isOk) { - return changeDebugApiUrl - } + const isOk = status.debugApiConnection return ( - <div> - {changeDebugApiUrl} + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Connection to Bee Debug API + </> + } + > + <ExpandableListItemNote> + {isOk + ? 'The connection to the Bee nodes deug API has been successful' + : 'We cannot connect to your nodes debug API. Please check the following to troubleshoot your issue.'} + </ExpandableListItemNote> + <ExpandableListItemInput label="Bee Debug API" value={apiDebugUrl} onConfirm={setDebugApiUrl} /> - <div> - <Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}> - We cannot connect to your nodes debug API at <Typography variant="button">{apiDebugUrl}</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 list`} /> - <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 list \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 (you can also use the - wildcard <code>{"cors-allowed-origins: ['*']"}</code>). 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 /usr/local/etc/swarm-bee/bee.yaml \nbrew services restart swarm-bee`} - /> - </ol> - </Typography> - </AccordionDetails> - </Accordion> - </Typography> - </div> - </div> + {!isOk && ( + <ExpandableList level={1} label="Troubleshoot"> + <ExpandableListItem + label={ + <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 list`} /> + <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 list \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 (you can also use the + wildcard <code>{"cors-allowed-origins: ['*']"}</code>). 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 /usr/local/etc/swarm-bee/bee.yaml \nbrew services restart swarm-bee`} + /> + </ol> + } + /> + </ExpandableList> + )} + </ExpandableList> ) } diff --git a/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx b/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx index 2c72ca2..6526d8c 100644 --- a/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx +++ b/src/pages/status/SetupSteps/EthereumConnectionCheck.tsx @@ -1,34 +1,42 @@ -import type { ReactElement } from 'react' -import { Typography } from '@material-ui/core/' -import EthereumAddress from '../../../components/EthereumAddress' +import { ReactElement, useContext } from 'react' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItemKey from '../../../components/ExpandableListItemKey' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import StatusIcon from '../../../components/StatusIcon' +import { Context } from '../../../providers/Bee' -type Props = StatusEthereumConnectionHook - -export default function EthereumConnectionCheck({ isOk, nodeAddresses }: Props): ReactElement | null { - if (isOk) { - return ( - <div> - <Typography variant="subtitle1" gutterBottom> - Node Address - </Typography> - <EthereumAddress address={nodeAddresses?.ethereum} /> - </div> - ) - } +export default function EthereumConnectionCheck(): ReactElement | null { + const { status, isLoading, nodeAddresses } = useContext(Context) + const isOk = status.blockchainConnection return ( - <p> - Your Bee node must have access to the xDai blockchain, so that it can interact and deploy your chequebook - contract. You can run{' '} - <a href="https://www.xdaichain.com/" rel="noreferrer" target="_blank"> - your own xDai node - </a> - , or use a provider instead - we recommend{' '} - <a href="https://getblock.io/" rel="noreferrer" target="_blank"> - Getblock - </a> - . By default, Bee expects a local node at http://localhost:8545. To use a provider instead, simply change the{' '} - <strong>swap-endpoint</strong> in your configuration file. - </p> + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Connection to Blockchain + </> + } + > + <ExpandableListItemNote> + {isOk ? ( + 'Your node is connected to the xDai blockchain' + ) : ( + <> + Your Bee node must have access to the xDai blockchain, so that it can interact and deploy your chequebook + contract. You can run{' '} + <a href="https://www.xdaichain.com/" rel="noreferrer" target="_blank"> + your own xDai node + </a> + , or use a provider instead - we recommend{' '} + <a href="https://getblock.io/" rel="noreferrer" target="_blank"> + Getblock + </a> + . By default, Bee expects a local node at http://localhost:8545. To use a provider instead, simply change + the <strong>swap-endpoint</strong> in your configuration file. + </> + )} + </ExpandableListItemNote> + {nodeAddresses?.ethereum && <ExpandableListItemKey label="Ethereum Address" value={nodeAddresses?.ethereum} />} + </ExpandableList> ) } diff --git a/src/pages/status/SetupSteps/NodeConnectionCheck.tsx b/src/pages/status/SetupSteps/NodeConnectionCheck.tsx index 91f4a1d..0cef8c8 100644 --- a/src/pages/status/SetupSteps/NodeConnectionCheck.tsx +++ b/src/pages/status/SetupSteps/NodeConnectionCheck.tsx @@ -1,61 +1,61 @@ import { ReactElement, useContext } from 'react' -import { Typography, Accordion, AccordionSummary, AccordionDetails } from '@material-ui/core/' -import { ExpandMoreSharp } from '@material-ui/icons/' -import ConnectToHost from '../../../components/ConnectToHost' import CodeBlockTabs from '../../../components/CodeBlockTabs' import { Context as SettingsContext } from '../../../providers/Settings' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItem from '../../../components/ExpandableListItem' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import ExpandableListItemInput from '../../../components/ExpandableListItemInput' +import StatusIcon from '../../../components/StatusIcon' +import { Context } from '../../../providers/Bee' -type Props = StatusHookCommon - -export default function NodeConnectionCheck({ isOk }: Props): ReactElement | null { +export default function NodeConnectionCheck(): ReactElement | null { const { setApiUrl, apiUrl } = useContext(SettingsContext) + const { status, isLoading } = useContext(Context) + const isOk = status.apiConnection return ( - <div> - <div style={{ display: 'flex', marginBottom: '25px' }}> - <span style={{ marginRight: '15px' }}> - Node API (<Typography variant="button">{apiUrl}</Typography>) - </span> - <ConnectToHost setHost={setApiUrl} defaultHost={apiUrl} /> - </div> - <div> - {!isOk && ( - <Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}> - We cannot connect to your nodes API at <Typography variant="button">{apiUrl}</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 list`} /> - <li> - If your node is running, check your firewall settings to make sure that port 1633 (or your custom - specified port) is exposed to the internet. If your node is not running try executing the below - command to start your bee node - </li> - <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 list \ntail -f /usr/local/var/log/swarm-bee/bee.log`} - /> - </ol> - </Typography> - </AccordionDetails> - </Accordion> - </Typography> - )} - </div> - </div> + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Connection to Bee API + </> + } + > + <ExpandableListItemNote> + {isOk + ? 'The connection to the Bee nodes API has been successful' + : 'Could not connect to your Bee nodes API. Please check the troubleshoot below on how you may resolve it.'} + </ExpandableListItemNote> + <ExpandableListItemInput label="Bee API" value={apiUrl} onConfirm={setApiUrl} /> + {!isOk && ( + <ExpandableList level={1} label="Troubleshoot"> + <ExpandableListItem + label={ + <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 list`} /> + <li> + If your node is running, check your firewall settings to make sure that port 1633 (or your custom + specified port) is exposed to the internet. If your node is not running try executing the below + command to start your bee node + </li> + <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 list \ntail -f /usr/local/var/log/swarm-bee/bee.log`} + /> + </ol> + } + /> + </ExpandableList> + )} + </ExpandableList> ) } diff --git a/src/pages/status/SetupSteps/PeerConnection.tsx b/src/pages/status/SetupSteps/PeerConnection.tsx index 72c21a2..8701c2e 100644 --- a/src/pages/status/SetupSteps/PeerConnection.tsx +++ b/src/pages/status/SetupSteps/PeerConnection.tsx @@ -1,43 +1,29 @@ -import type { ReactElement } from 'react' -import { Typography } from '@material-ui/core/' +import { ReactElement, useContext } from 'react' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import TopologyStats from '../../../components/TopologyStats' +import StatusIcon from '../../../components/StatusIcon' +import { Context } from '../../../providers/Bee' -type Props = StatusTopologyHook - -export default function PeerConnection({ isOk, topology }: Props): ReactElement | 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> - <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} - </> - ) - } +export default function PeerConnection(): ReactElement | null { + const { status, isLoading, topology } = useContext(Context) + const isOk = status.topology return ( - <> - <span>Your node is not connected to any peers</span> - {peers} - </> + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Connection to Peers + </> + } + > + <ExpandableListItemNote> + {isOk + ? 'You are connected to other Bee nodes' + : 'Your node is not connected to any peers. Please wait a bit if you just started the node, otherwise review your configuration file.'} + </ExpandableListItemNote> + + <TopologyStats topology={topology} /> + </ExpandableList> ) } diff --git a/src/pages/status/SetupSteps/VersionCheck.tsx b/src/pages/status/SetupSteps/VersionCheck.tsx index 01bbd62..f83f1c1 100644 --- a/src/pages/status/SetupSteps/VersionCheck.tsx +++ b/src/pages/status/SetupSteps/VersionCheck.tsx @@ -1,60 +1,47 @@ -import type { ReactElement } from 'react' -import { Typography } from '@material-ui/core/' +import { ReactElement, useContext } from 'react' import CodeBlockTabs from '../../../components/CodeBlockTabs' +import ExpandableList from '../../../components/ExpandableList' +import ExpandableListItem from '../../../components/ExpandableListItem' +import ExpandableListItemNote from '../../../components/ExpandableListItemNote' +import StatusIcon from '../../../components/StatusIcon' +import { Context } from '../../../providers/Bee' -type Props = StatusNodeVersionHook +export default function VersionCheck(): ReactElement | null { + const { status, isLoading, latestUserVersion, latestPublishedVersion, latestBeeVersionUrl } = useContext(Context) + const isOk = status.version -export default function VersionCheck({ isOk, userVersion, latestVersion, latestUrl }: Props): ReactElement | 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} - </> + <ExpandableList + label={ + <> + <StatusIcon isOk={isOk} isLoading={isLoading} /> Bee Version + </> + } + > + <ExpandableListItemNote> + {isOk ? ( + 'You are running the latest version of Bee.' + ) : ( + <> + Your Bee version is out of date. Please update to the{' '} + <a href={latestBeeVersionUrl} rel="noreferrer" target="_blank"> + latest + </a>{' '} + before continuing. Rerun the installation script below to upgrade. For more information please see the{' '} + <a href="https://docs.ethswarm.org/docs/installation/manual#upgrading-bee" rel="noreferrer" target="_blank"> + Docs + </a> + . + <CodeBlockTabs + showLineNumbers + linux={`bee version\nwget https://github.com/ethersphere/bee/releases/download/${latestPublishedVersion}/bee_${latestPublishedVersion}_amd64.deb\nsudo dpkg -i bee_${latestPublishedVersion}_amd64.deb`} + mac={`bee version\nbrew tap ethersphere/tap\nbrew install swarm-bee\nbrew services start swarm-bee`} + /> + </> + )} + </ExpandableListItemNote> + <ExpandableListItem label="Your Version" value={latestUserVersion || '-'} /> + <ExpandableListItem label="Latest Version" value={latestPublishedVersion || '-'} /> + </ExpandableList> ) } diff --git a/src/pages/status/index.tsx b/src/pages/status/index.tsx index 8386d4f..16aec29 100644 --- a/src/pages/status/index.tsx +++ b/src/pages/status/index.tsx @@ -1,7 +1,4 @@ -import { ReactElement, useState, useContext } 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, ExpandLessSharp, ExpandMoreSharp, Autorenew } from '@material-ui/icons/' +import type { ReactElement } from 'react' import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck' import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck' @@ -9,144 +6,16 @@ import VersionCheck from './SetupSteps/VersionCheck' import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck' import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund' import PeerConnection from './SetupSteps/PeerConnection' -import { Context } from '../../providers/Bee' - -const useStyles = makeStyles((theme: Theme) => - createStyles({ - root: { - padding: theme.spacing(2), - width: '100%', - }, - button: { - marginTop: theme.spacing(1), - marginRight: theme.spacing(1), - }, - actionsContainer: { - margin: theme.spacing(2), - }, - }), -) - -interface Step { - label: string - isOk: boolean - component: ReactElement -} export default function NodeSetupWorkflow(): ReactElement { - const classes = useStyles() - const [activeStep, setActiveStep] = useState(-1) - - const { - status, - isLoading, - latestUserVersion, - latestPublishedVersion, - isLatestBeeVersion, - latestBeeVersionUrl, - topology, - nodeAddresses, - chequebookAddress, - } = useContext(Context) - - const steps: Step[] = [ - { - label: 'Connected to Node DebugAPI', - isOk: status.debugApiConnection, - component: <DebugConnectionCheck isOk={status.debugApiConnection} />, - }, - { - label: 'Running latest Bee version', - isOk: status.version, - component: ( - <VersionCheck - isOk={status.version} - isLatestBeeVersion={isLatestBeeVersion} - userVersion={latestUserVersion} - latestVersion={latestPublishedVersion} - latestUrl={latestBeeVersionUrl} - /> - ), - }, - { - label: 'Connected to xDai Blockchain', - isOk: status.blockchainConnection, - component: <EthereumConnectionCheck isOk={status.blockchainConnection} nodeAddresses={nodeAddresses} />, - }, - { - label: 'Deployed and Funded Chequebook', - isOk: status.chequebook, - component: ( - <ChequebookDeployFund chequebookAddress={chequebookAddress?.chequebookAddress} isOk={status.chequebook} /> - ), - }, - { - label: 'Connected to Node API', - isOk: status.apiConnection, - component: <NodeConnectionCheck isOk={status.apiConnection} />, - }, - { - label: 'Connected to Peers', - isOk: status.topology, - component: <PeerConnection isOk={status.topology} topology={topology} />, - }, - ] - - const handleNext = () => { - setActiveStep(prevActiveStep => prevActiveStep + 1) - } - - const handleBack = () => { - setActiveStep(prevActiveStep => prevActiveStep - 1) - } - return ( - <Paper className={classes.root}> - <Typography variant="h5" gutterBottom> - Node Setup - </Typography> - <Stepper nonLinear activeStep={activeStep} orientation="vertical"> - {steps.map(({ label, isOk, component }, index) => ( - <Step key={label}> - <StepLabel - onClick={() => setActiveStep(index === activeStep ? steps.length : index)} - StepIconComponent={() => { - if (isLoading) return <Autorenew style={{ height: '25px', cursor: 'pointer' }} /> - - if (isOk) return <CheckCircle style={{ color: '#32c48d', height: '25px', cursor: 'pointer' }} /> - - return <Error style={{ color: '#c9201f', height: '25px', cursor: 'pointer' }} /> - }} - > - <StepButton - disabled={isLoading} - onClick={() => setActiveStep(index === activeStep ? steps.length : index)} - style={{ justifyContent: 'space-between' }} - > - <div style={{ display: 'flex' }}> - <div style={{ marginTop: '5px' }}>{label}</div> - <div style={{ marginLeft: '12px' }}> - {index === activeStep ? <ExpandLessSharp /> : <ExpandMoreSharp />} - </div> - </div> - </StepButton> - </StepLabel> - <StepContent> - <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}> - {index < steps.length - 1 ? 'Next' : 'Finish'} - </Button> - </div> - </div> - </StepContent> - </Step> - ))} - </Stepper> - </Paper> + <div> + <DebugConnectionCheck /> + <VersionCheck /> + <EthereumConnectionCheck /> + <ChequebookDeployFund /> + <NodeConnectionCheck /> + <PeerConnection /> + </div> ) } diff --git a/src/theme.tsx b/src/theme.tsx index f47fe08..8578b81 100644 --- a/src/theme.tsx +++ b/src/theme.tsx @@ -61,6 +61,9 @@ const componentsOverrides = (theme: Theme) => ({ backgroundColor: theme.palette.primary.main, color: 'white', }, + '&:disabled': { + backgroundColor: 'white', + }, }, }, MuiTab: {