feat: changing API urls does not need the app refresh (#173)

* feat: changing API urls does not need the app refresh

* fix: propagate beeDebugApi and beeApi change to the refresh interval

* fix: any failed request on the Bee provider does not stop the execution of other requests

* fix: error handling for incorrect bee and bee debug urls

* fix: change debug API in the settings tab
This commit is contained in:
Vojtech Simetka
2021-08-20 15:14:14 +02:00
committed by GitHub
parent 2624cf04c9
commit d6d03bf7c6
21 changed files with 336 additions and 380 deletions
+8 -10
View File
@@ -1,12 +1,12 @@
import { ReactElement, useContext } from 'react'
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles'
import { Container } from '@material-ui/core'
import AccountCard from '../accounting/AccountCard'
import BalancesTable from './BalancesTable'
import EthereumAddressCard from '../../components/EthereumAddressCard'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import { Context } from '../../providers/Bee'
import { Context as BeeContext } from '../../providers/Bee'
import { Context as SettingsContext } from '../../providers/Settings'
import { useAccounting } from '../../hooks/accounting'
const useStyles = makeStyles((theme: Theme) =>
@@ -22,9 +22,12 @@ const useStyles = makeStyles((theme: Theme) =>
export default function Accounting(): ReactElement {
const classes = useStyles()
const { status, nodeAddresses, chequebookAddress, chequebookBalance, settlements } = useContext(Context)
const { status, nodeAddresses, chequebookAddress, chequebookBalance, settlements, peerBalances } = useContext(
BeeContext,
)
const { beeDebugApi } = useContext(SettingsContext)
const { accounting, isLoadingUncashed, error } = useAccounting()
const { accounting, isLoadingUncashed } = useAccounting(beeDebugApi, settlements, peerBalances)
if (!status.all) return <TroubleshootConnectionCard />
@@ -37,12 +40,7 @@ export default function Accounting(): ReactElement {
totalreceived={settlements?.totalReceived}
/>
<EthereumAddressCard nodeAddresses={nodeAddresses} chequebookAddress={chequebookAddress} />
{error && (
<Container style={{ textAlign: 'center', padding: '50px' }}>
Error loading accounting details: {error.message}
</Container>
)}
{!error && <BalancesTable accounting={accounting} isLoadingUncashed={isLoadingUncashed} />}
<BalancesTable accounting={accounting} isLoadingUncashed={isLoadingUncashed} />
</div>
)
}
+4 -3
View File
@@ -1,8 +1,8 @@
import { ReactElement, useState } from 'react'
import { ReactElement, useState, useContext } from 'react'
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import { Paper, InputBase, IconButton, FormHelperText } from '@material-ui/core'
import { Search } from '@material-ui/icons'
import { apiHost } from '../../constants'
import { Context as SettingsContext } from '../../providers/Settings'
import { Utils } from '@ethersphere/bee-js'
const useStyles = makeStyles((theme: Theme) =>
@@ -28,6 +28,7 @@ const useStyles = makeStyles((theme: Theme) =>
export default function Files(): ReactElement {
const classes = useStyles()
const { apiUrl } = useContext(SettingsContext)
const [referenceInput, setReferenceInput] = useState('')
const [referenceError, setReferenceError] = useState<Error | null>(null)
@@ -50,7 +51,7 @@ export default function Files(): ReactElement {
onChange={handleReferenceChange}
/>
<IconButton
href={`${apiHost}/bzz/${referenceInput}`}
href={`${apiUrl}/bzz/${referenceInput}`}
target="_blank"
disabled={referenceError !== null || !referenceInput}
className={classes.iconButton}
+6 -2
View File
@@ -8,7 +8,7 @@ import UploadSizeAlert from '../../components/AlertUploadSize'
import ClipboardCopy from '../../components/ClipboardCopy'
import PeerDetailDrawer from '../../components/PeerDetail'
import { Context, EnrichedPostageBatch } from '../../providers/Stamps'
import { beeApi } from '../../services/bee'
import { Context as SettingsContext } from '../../providers/Settings'
import CreatePostageStamp from '../stamps/CreatePostageStampModal'
import SelectStamp from './SelectStamp'
@@ -23,6 +23,7 @@ export default function Files(): ReactElement {
const [selectedStamp, setSelectedStamp] = useState<EnrichedPostageBatch | null>(null)
const { isLoading, error, stamps } = useContext(Context)
const { beeApi } = useContext(SettingsContext)
const { enqueueSnackbar } = useSnackbar()
// Choose a postage stamp that has the lowest usage
@@ -40,8 +41,11 @@ export default function Files(): ReactElement {
const uploadFile = () => {
if (file === null || selectedStamp === null) return
if (!beeApi) return
setIsUploadingFile(true)
beeApi.files
beeApi
.uploadFile(selectedStamp.batchID, file)
.then(hash => {
window.setTimeout(() => {
+5 -4
View File
@@ -1,4 +1,4 @@
import React, { ReactElement, useState } from 'react'
import { ReactElement, useState, useContext } from 'react'
import { makeStyles } from '@material-ui/core/styles'
import {
Table,
@@ -14,7 +14,7 @@ import {
} from '@material-ui/core'
import { Autorenew } from '@material-ui/icons'
import { beeDebugApi } from '../../services/bee'
import { Context as SettingsContext } from '../../providers/Settings'
import type { Peer } from '@ethersphere/bee-js'
const useStyles = makeStyles({
@@ -29,13 +29,14 @@ interface Props {
function PeerTable(props: Props): ReactElement {
const classes = useStyles()
const { beeDebugApi } = useContext(SettingsContext)
const [peerLatency, setPeerLatency] = useState([{ peerId: '', rtt: '', loading: false }])
const PingPeer = (peerId: string) => {
setPeerLatency([...peerLatency, { peerId: peerId, rtt: '', loading: true }])
beeDebugApi.connectivity
.ping(peerId)
beeDebugApi
?.pingPeer(peerId)
.then(res => {
setPeerLatency([...peerLatency, { peerId: peerId, rtt: res.rtt, loading: false }])
})
+14 -28
View File
@@ -1,26 +1,20 @@
import React, { ReactElement, useState } from 'react'
import React, { ReactElement, useState, useContext } from 'react'
import { Paper, Container, TextField, Typography, Button } from '@material-ui/core'
import { Context as SettingsContext } from '../../providers/Settings'
export default function Settings(): ReactElement {
const [refreshVisibility, toggleRefreshVisibility] = useState(false)
const [host, setHost] = useState('')
const [debugHost, setDebugHost] = useState('')
const { apiUrl, apiDebugUrl, setApiUrl, setDebugApiUrl } = useContext(SettingsContext)
const [host, setHost] = useState(apiUrl)
const [debugHost, setDebugHost] = useState(apiDebugUrl)
const handleNewHostConnection = () => {
if (host) {
sessionStorage.setItem('api_host', host)
}
const submit = () => {
if (host !== apiUrl) setApiUrl(host)
if (debugHost) {
sessionStorage.setItem('debug_api_host', debugHost)
}
if (host || debugHost) {
toggleRefreshVisibility(!refreshVisibility)
window.location.reload()
}
if (debugHost !== apiDebugUrl) setDebugApiUrl(debugHost)
}
const touched = host !== apiUrl || debugHost !== apiDebugUrl
return (
<div>
<Container>
@@ -34,16 +28,13 @@ export default function Settings(): ReactElement {
placeholder="ex: 127.0.0.0.1:1633"
helperText="Enter node host override / port"
fullWidth
defaultValue={
sessionStorage.getItem('api_host') ? sessionStorage.getItem('api_host') : process.env.REACT_APP_BEE_HOST
}
defaultValue={apiUrl}
margin="normal"
InputLabelProps={{
shrink: true,
}}
onChange={e => {
setHost(e.target.value)
toggleRefreshVisibility(true)
}}
variant="filled"
/>
@@ -55,14 +46,9 @@ export default function Settings(): ReactElement {
placeholder="ex: 127.0.0.0.1:1635"
helperText="Enter node debug host override / port"
fullWidth
defaultValue={
sessionStorage.getItem('debug_api_host')
? sessionStorage.getItem('debug_api_host')
: process.env.REACT_APP_BEE_DEBUG_HOST
}
defaultValue={apiDebugUrl}
onChange={e => {
setDebugHost(e.target.value)
toggleRefreshVisibility(true)
}}
margin="normal"
InputLabelProps={{
@@ -71,9 +57,9 @@ export default function Settings(): ReactElement {
variant="filled"
/>
</Paper>
{refreshVisibility ? (
{touched ? (
<div style={{ marginTop: '20px' }}>
<Button variant="outlined" color="primary" onClick={() => handleNewHostConnection()}>
<Button variant="outlined" color="primary" onClick={submit}>
Save
</Button>
</div>
+5 -2
View File
@@ -9,7 +9,7 @@ import DialogTitle from '@material-ui/core/DialogTitle'
import BigNumber from 'bignumber.js'
import { FormikHelpers, Form, Field, Formik } from 'formik'
import { TextField } from 'formik-material-ui'
import { beeApi } from '../../services/bee'
import { Context as SettingsContext } from '../../providers/Settings'
import { Context } from '../../providers/Stamps'
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import { useSnackbar } from 'notistack'
@@ -54,6 +54,7 @@ export default function FormDialog({ label }: Props): ReactElement {
const classes = useStyles()
const [open, setOpen] = React.useState(false)
const { refresh } = useContext(Context)
const { beeApi } = useContext(SettingsContext)
const handleClickOpen = () => setOpen(true)
const handleClose = () => setOpen(false)
const { enqueueSnackbar } = useSnackbar()
@@ -66,10 +67,12 @@ export default function FormDialog({ label }: Props): ReactElement {
// This is really just a typeguard, the validation pretty much guarantees these will have the right values
if (!values.depth || !values.amount) return
if (!beeApi) return
const amount = BigInt(values.amount)
const depth = Number.parseInt(values.depth)
const options = values.label ? { label: values.label } : undefined
await beeApi.stamps.buyPostageStamp(amount, depth, options)
await beeApi.createPostageBatch(amount.toString(), depth, options)
actions.resetForm()
await refresh()
handleClose()
@@ -1,21 +1,29 @@
import type { ReactElement } from 'react'
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 { debugApiHost } from '../../../constants'
import { Context as SettingsContext } from '../../../providers/Settings'
type Props = StatusHookCommon
export default function NodeConnectionCheck({ isOk }: Props): ReactElement | null {
const { setDebugApiUrl, apiDebugUrl } = useContext(SettingsContext)
const changeDebugApiUrl = (
<div style={{ display: 'flex', marginTop: '25px', marginBottom: '25px' }}>
<span style={{ marginRight: '15px' }}>
Debug API (<Typography variant="button">{debugApiHost}</Typography>)
Debug API (<Typography variant="button">{apiDebugUrl}</Typography>)
</span>
<ConnectToHost hostName={'debug_api_host'} defaultHost={debugApiHost} />
<ConnectToHost
setHost={(host: string) => {
console.log(host) // eslint-disable-line
setDebugApiUrl(host)
}}
defaultHost={apiDebugUrl}
/>
</div>
)
@@ -29,7 +37,7 @@ export default function NodeConnectionCheck({ isOk }: Props): ReactElement | nul
<div>
<Typography component="div" variant="body2" gutterBottom style={{ margin: '15px' }}>
We cannot connect to your nodes debug API at <Typography variant="button">{debugApiHost}</Typography>. Please
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">
@@ -1,26 +1,28 @@
import React, { ReactElement } from 'react'
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 { apiHost } from '../../../constants'
import { Context as SettingsContext } from '../../../providers/Settings'
type Props = StatusHookCommon
export default function NodeConnectionCheck({ isOk }: Props): ReactElement | null {
const { setApiUrl, apiUrl } = useContext(SettingsContext)
return (
<div>
<div style={{ display: 'flex', marginBottom: '25px' }}>
<span style={{ marginRight: '15px' }}>
Node API (<Typography variant="button">{apiHost}</Typography>)
Node API (<Typography variant="button">{apiUrl}</Typography>)
</span>
<ConnectToHost hostName="api_host" defaultHost={apiHost} />
<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">{apiHost}</Typography>. Please check the
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">
+2 -2
View File
@@ -4,7 +4,7 @@ import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
import NodeSetupWorkflow from './NodeSetupWorkflow'
import StatusCard from './StatusCard'
import EthereumAddressCard from '../../components/EthereumAddressCard'
import { Context } from '../../providers/Bee'
import { Context as BeeContext } from '../../providers/Bee'
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -27,7 +27,7 @@ export default function Status(): ReactElement {
topology,
nodeAddresses,
chequebookAddress,
} = useContext(Context)
} = useContext(BeeContext)
return (
<div className={classes.root}>