Compare commits

...

5 Commits

Author SHA1 Message Date
bee-worker da0ae9cd94 chore(master): release 0.20.0 (#534) 2022-09-14 11:54:48 +02:00
Adam Uhlíř 528a810690 fix: show update notifications only on non-auto-updating Swarm Desktops (#543) 2022-09-14 11:48:24 +02:00
Adam Uhlíř 0c74dae4e8 feat: error reporting callback (#530) 2022-09-09 13:07:40 +02:00
dependabot[bot] d42d440f85 build(deps-dev): bump typescript from 4.7.3 to 4.8.2 (#528)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-09 12:03:34 +02:00
Adam Uhlíř 0c262a4811 refactor: remove env. variables from the component (#529) 2022-09-08 08:51:55 +02:00
27 changed files with 241 additions and 224 deletions
-1
View File
@@ -19,7 +19,6 @@ jobs:
env: env:
REACT_APP_BEE_HOST: https://api.test-node.staging.ethswarm.org/ REACT_APP_BEE_HOST: https://api.test-node.staging.ethswarm.org/
REACT_APP_BEE_DEBUG_HOST: https://debug.test-node.staging.ethswarm.org/ REACT_APP_BEE_DEBUG_HOST: https://debug.test-node.staging.ethswarm.org/
REACT_APP_DEV_MODE: 1
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
+12
View File
@@ -1,5 +1,17 @@
# Changelog # Changelog
## [0.20.0](https://github.com/ethersphere/bee-dashboard/compare/v0.19.3...v0.20.0) (2022-09-14)
### Features
* error reporting callback ([#530](https://github.com/ethersphere/bee-dashboard/issues/530)) ([0c74dae](https://github.com/ethersphere/bee-dashboard/commit/0c74dae4e88916cf54c3c0500b37203b865e48a7))
### Bug Fixes
* show update notifications only on non-auto-updating Swarm Desktops ([#543](https://github.com/ethersphere/bee-dashboard/issues/543)) ([528a810](https://github.com/ethersphere/bee-dashboard/commit/528a8106907ef176bcdb68b3386c2f3f9ea98a47))
## [0.19.3](https://github.com/ethersphere/bee-dashboard/compare/v0.19.2...v0.19.3) (2022-08-24) ## [0.19.3](https://github.com/ethersphere/bee-dashboard/compare/v0.19.2...v0.19.3) (2022-08-24)
+9 -1
View File
@@ -94,7 +94,15 @@ npm start
The Bee Dashboard runs in development mode on [http://localhost:3031/](http://localhost:3031/) The Bee Dashboard runs in development mode on [http://localhost:3031/](http://localhost:3031/)
> Setting the `REACT_APP_DEV_MODE=1` environment variable, or opening Bee Dashboard with the query string `?devMode=1` loosens some checks. This makes it possible to develop Bee Dashboard without having connected peers and chequebook properly set up, effectively supporting the dev mode of Bee itself. #### Environmental variables
The CRA supports to specify "environmental variables" during build time which are then hardcoded into the served static files.
We support following variables:
- `REACT_APP_BEE_DESKTOP_ENABLED` (`boolean`) that toggles if the Dashboard is in Desktop mode or not.
- `REACT_APP_BEE_DESKTOP_URL` (`string`) defines custom URL where the Desktop API is expected. By default, it is same origin under which the Dashboard is served.
- `REACT_APP_BEE_API_URL` (`string`) defines custom Bee API URL to be used as default one. By default, the `http://localhost:1633` is used.
- `REACT_APP_BEE_DEBUG_API_URL` (`string`) defines custom Bee Debug API URL to be used as default one. By default, the `http://localhost:1635` is used.
#### Swarm Desktop development #### Swarm Desktop development
+9 -9
View File
@@ -1,12 +1,12 @@
{ {
"name": "@ethersphere/bee-dashboard", "name": "@ethersphere/bee-dashboard",
"version": "0.19.3", "version": "0.20.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@ethersphere/bee-dashboard", "name": "@ethersphere/bee-dashboard",
"version": "0.19.3", "version": "0.20.0",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"@ethersphere/bee-js": "^5.0.0", "@ethersphere/bee-js": "^5.0.0",
@@ -99,7 +99,7 @@
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ts-node": "^10.8.1", "ts-node": "^10.8.1",
"typescript": "4.7.3", "typescript": "4.8.2",
"web-vitals": "2.1.2", "web-vitals": "2.1.2",
"webpack": "^5.73.0", "webpack": "^5.73.0",
"webpack-cli": "^4.10.0" "webpack-cli": "^4.10.0"
@@ -19410,9 +19410,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.7.3", "version": "4.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
@@ -34910,9 +34910,9 @@
} }
}, },
"typescript": { "typescript": {
"version": "4.7.3", "version": "4.8.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==", "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
"dev": true "dev": true
}, },
"unbox-primitive": { "unbox-primitive": {
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ethersphere/bee-dashboard", "name": "@ethersphere/bee-dashboard",
"version": "0.19.3", "version": "0.20.0",
"description": "An app which helps users to setup their Bee node and do actions like cash out cheques", "description": "An app which helps users to setup their Bee node and do actions like cash out cheques",
"keywords": [ "keywords": [
"bee", "bee",
@@ -113,7 +113,7 @@
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"ts-node": "^10.8.1", "ts-node": "^10.8.1",
"typescript": "4.7.3", "typescript": "4.8.2",
"web-vitals": "2.1.2", "web-vitals": "2.1.2",
"webpack": "^5.73.0", "webpack": "^5.73.0",
"webpack-cli": "^4.10.0" "webpack-cli": "^4.10.0"
+14 -4
View File
@@ -20,10 +20,19 @@ interface Props {
beeApiUrl?: string beeApiUrl?: string
beeDebugApiUrl?: string beeDebugApiUrl?: string
lockedApiSettings?: boolean lockedApiSettings?: boolean
isBeeDesktop?: boolean isDesktop?: boolean
desktopUrl?: string
errorReporting?: (err: Error) => void
} }
const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Props): ReactElement => { const App = ({
beeApiUrl,
beeDebugApiUrl,
lockedApiSettings,
isDesktop,
desktopUrl,
errorReporting,
}: Props): ReactElement => {
const mainApp = ( const mainApp = (
<div className="App"> <div className="App">
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
@@ -31,7 +40,8 @@ const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Pro
beeApiUrl={beeApiUrl} beeApiUrl={beeApiUrl}
beeDebugApiUrl={beeDebugApiUrl} beeDebugApiUrl={beeDebugApiUrl}
lockedApiSettings={lockedApiSettings} lockedApiSettings={lockedApiSettings}
isBeeDesktop={isBeeDesktop} isDesktop={isDesktop}
desktopUrl={desktopUrl}
> >
<TopUpProvider> <TopUpProvider>
<BeeProvider> <BeeProvider>
@@ -44,7 +54,7 @@ const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Pro
<Router> <Router>
<> <>
<CssBaseline /> <CssBaseline />
<Dashboard> <Dashboard errorReporting={errorReporting}>
<BaseRouter /> <BaseRouter />
</Dashboard> </Dashboard>
</> </>
+8 -1
View File
@@ -2,6 +2,7 @@ import { Component, ErrorInfo, ReactElement } from 'react'
interface Props { interface Props {
children: ReactElement children: ReactElement
errorReporting?: (err: Error) => void
} }
interface State { interface State {
@@ -9,8 +10,11 @@ interface State {
} }
export default class ErrorBoundary extends Component<Props, State> { export default class ErrorBoundary extends Component<Props, State> {
private errorReporting?: (err: Error) => void
constructor(props: Props) { constructor(props: Props) {
super(props) super(props)
this.errorReporting = props.errorReporting
this.state = { error: null } this.state = { error: null }
} }
@@ -20,7 +24,10 @@ export default class ErrorBoundary extends Component<Props, State> {
} }
componentDidCatch(error: Error, errorInfo: ErrorInfo): void { componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
// You can also log the error to an error reporting service if (this.errorReporting) {
this.errorReporting(error)
}
console.error({ error, errorInfo }) // eslint-disable-line console.error({ error, errorInfo }) // eslint-disable-line
} }
+2 -2
View File
@@ -1,9 +1,9 @@
import { Typography } from '@material-ui/core/' import { Typography } from '@material-ui/core/'
import { ReactElement } from 'react' import { ReactElement } from 'react'
import Identicon from 'react-identicons' import Identicon from 'react-identicons'
import { config } from '../config'
import ClipboardCopy from './ClipboardCopy' import ClipboardCopy from './ClipboardCopy'
import QRCodeModal from './QRCodeModal' import QRCodeModal from './QRCodeModal'
import { BLOCKCHAIN_EXPLORER_URL } from '../constants'
interface Props { interface Props {
address: string | undefined address: string | undefined
@@ -36,7 +36,7 @@ export default function EthereumAddress(props: Props): ReactElement {
} }
: { marginRight: '7px' } : { marginRight: '7px' }
} }
href={`${config.BLOCKCHAIN_EXPLORER_URL}/${props.transaction ? 'tx' : 'address'}/${props.address}`} href={`${BLOCKCHAIN_EXPLORER_URL}/${props.transaction ? 'tx' : 'address'}/${props.address}`}
target="_blank" target="_blank"
rel="noreferrer" rel="noreferrer"
> >
+4 -4
View File
@@ -12,11 +12,11 @@ import { Context as BeeContext } from '../providers/Bee'
import { Context as SettingsContext } from '../providers/Settings' import { Context as SettingsContext } from '../providers/Settings'
import DashboardLogo from '../assets/dashboard-logo.svg' import DashboardLogo from '../assets/dashboard-logo.svg'
import DesktopLogo from '../assets/desktop-logo.svg' import DesktopLogo from '../assets/desktop-logo.svg'
import { config } from '../config'
import { ROUTES } from '../routes' import { ROUTES } from '../routes'
import SideBarItem from './SideBarItem' import SideBarItem from './SideBarItem'
import SideBarStatus from './SideBarStatus' import SideBarStatus from './SideBarStatus'
import { BeeModes } from '@ethersphere/bee-js' import { BeeModes } from '@ethersphere/bee-js'
import { BEE_DOCS_HOST } from '../constants'
const drawerWidth = 300 const drawerWidth = 300
@@ -66,7 +66,7 @@ const useStyles = makeStyles((theme: Theme) =>
export default function SideBar(): ReactElement { export default function SideBar(): ReactElement {
const classes = useStyles() const classes = useStyles()
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop } = useContext(SettingsContext)
const { nodeInfo } = useContext(BeeContext) const { nodeInfo } = useContext(BeeContext)
const navBarItems = [ const navBarItems = [
@@ -99,7 +99,7 @@ export default function SideBar(): ReactElement {
<Grid container direction="column" justifyContent="space-between" className={classes.root}> <Grid container direction="column" justifyContent="space-between" className={classes.root}>
<Grid className={classes.logo}> <Grid className={classes.logo}>
<Link to={ROUTES.INFO}> <Link to={ROUTES.INFO}>
<img alt="swarm" src={isBeeDesktop ? DesktopLogo : DashboardLogo} /> <img alt="swarm" src={isDesktop ? DesktopLogo : DashboardLogo} />
</Link> </Link>
</Grid> </Grid>
<Grid> <Grid>
@@ -118,7 +118,7 @@ export default function SideBar(): ReactElement {
</List> </List>
<Divider className={classes.divider} /> <Divider className={classes.divider} />
<List> <List>
<MUILink href={config.BEE_DOCS_HOST} target="_blank" className={classes.link}> <MUILink href={BEE_DOCS_HOST} target="_blank" className={classes.link}>
<SideBarItem <SideBarItem
iconStart={<DocsIcon className={classes.icon} />} iconStart={<DocsIcon className={classes.icon} />}
iconEnd={<ExternalLinkIcon className={classes.icon} color="#595959" />} iconEnd={<ExternalLinkIcon className={classes.icon} color="#595959" />}
@@ -3,8 +3,8 @@ import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
import type { ReactElement } from 'react' import type { ReactElement } from 'react'
import Activity from 'remixicon-react/PulseLineIcon' import Activity from 'remixicon-react/PulseLineIcon'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { config } from '../config'
import { ROUTES } from '../routes' import { ROUTES } from '../routes'
import { BEE_DISCORD_HOST, BEE_DOCS_HOST } from '../constants'
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
@@ -37,11 +37,11 @@ export default function TroubleshootConnectionCard(): ReactElement {
<Grid item className={classes.content}> <Grid item className={classes.content}>
<Typography align="center"> <Typography align="center">
Please check your node status to fix the problem. You can also check out the{' '} Please check your node status to fix the problem. You can also check out the{' '}
<MuiLink href={config.BEE_DOCS_HOST} target="_blank" rel="noreferrer"> <MuiLink href={BEE_DOCS_HOST} target="_blank" rel="noreferrer">
Swarm Bee Docs Swarm Bee Docs
</MuiLink>{' '} </MuiLink>{' '}
or ask for support on the{' '} or ask for support on the{' '}
<MuiLink href={config.BEE_DISCORD_HOST} target="_blank" rel="noreferrer"> <MuiLink href={BEE_DISCORD_HOST} target="_blank" rel="noreferrer">
Ethereum Swarm Discord Ethereum Swarm Discord
</MuiLink> </MuiLink>
. .
-29
View File
@@ -1,29 +0,0 @@
class Config {
public readonly BEE_API_HOST: string
public readonly BEE_DEBUG_API_HOST: string
public readonly BLOCKCHAIN_EXPLORER_URL: string
public readonly BEE_DOCS_HOST: string
public readonly BEE_DISCORD_HOST: string
public readonly GITHUB_REPO_URL: string
public readonly BEE_DESKTOP_ENABLED: boolean
public readonly BEE_DESKTOP_URL: string
public readonly DEFAULT_RPC_URL: string
constructor() {
this.BEE_API_HOST = sessionStorage.getItem('api_host') ?? process.env.REACT_APP_BEE_HOST ?? 'http://localhost:1633'
this.BEE_DEBUG_API_HOST =
sessionStorage.getItem('debug_api_host') ?? process.env.REACT_APP_BEE_DEBUG_HOST ?? 'http://localhost:1635'
this.BLOCKCHAIN_EXPLORER_URL =
process.env.REACT_APP_BLOCKCHAIN_EXPLORER_URL ?? 'https://blockscout.com/xdai/mainnet'
this.BEE_DOCS_HOST = process.env.REACT_APP_BEE_DOCS_HOST ?? 'https://docs.ethswarm.org/docs/'
this.BEE_DISCORD_HOST = process.env.REACT_APP_BEE_DISCORD_HOST ?? 'https://discord.gg/eKr9XPv7'
this.GITHUB_REPO_URL = process.env.REACT_APP_BEE_GITHUB_REPO_URL ?? 'https://api.github.com/repos/ethersphere/bee'
this.BEE_DESKTOP_ENABLED = process.env.REACT_APP_BEE_DESKTOP_ENABLED === 'true'
this.BEE_DESKTOP_URL = process.env.REACT_APP_BEE_DESKTOP_URL ?? window.location.origin
this.DEFAULT_RPC_URL = process.env.REACT_APP_DEFAULT_RPC_URL ?? 'https://xdai.fairdatasociety.org'
}
}
export const config = new Config()
export default config
+11 -1
View File
@@ -1,4 +1,14 @@
export const META_FILE_NAME = '.swarmgatewaymeta.json' export const META_FILE_NAME = '.swarmgatewaymeta.json'
export const PREVIEW_FILE_NAME = '.swarmgatewaypreview.jpeg' export const PREVIEW_FILE_NAME = '.swarmgatewaypreview.jpeg'
export const PREVIEW_DIMENSIONS = { maxWidth: 250, maxHeight: 175 } export const PREVIEW_DIMENSIONS = { maxWidth: 250, maxHeight: 175 }
export const BZZ_LINK_DOMAIN = process.env.REACT_APP_BZZ_LINK_DOMAIN || 'bzz.link' export const BZZ_LINK_DOMAIN = 'bzz.link'
export const BLOCKCHAIN_EXPLORER_URL = 'https://blockscout.com/xdai/mainnet'
export const BEE_DOCS_HOST = 'https://docs.ethswarm.org/docs/'
export const BEE_DISCORD_HOST = 'https://discord.gg/eKr9XPv7'
export const GITHUB_REPO_URL = 'https://api.github.com/repos/ethersphere/bee'
export const BEE_DESKTOP_LATEST_RELEASE_PAGE = 'https://github.com/ethersphere/bee-desktop/releases/latest'
export const BEE_DESKTOP_LATEST_RELEASE_PAGE_API =
'https://api.github.com/repos/ethersphere/bee-desktop/releases/latest'
export const DEFAULT_BEE_API_HOST = 'http://localhost:1633'
export const DEFAULT_BEE_DEBUG_API_HOST = 'http://localhost:1635'
export const DEFAULT_RPC_URL = 'https://xdai.fairdatasociety.org'
+1 -1
View File
@@ -41,7 +41,7 @@ afterAll(async () => {
describe('useBeeDesktop', () => { describe('useBeeDesktop', () => {
it('should not have error when connected to bee-desktop', async () => { it('should not have error when connected to bee-desktop', async () => {
const { result, waitFor } = renderHook(() => useBeeDesktop(true, { BEE_DESKTOP_URL: serverCorrectURL })) const { result, waitFor } = renderHook(() => useBeeDesktop(true, serverCorrectURL))
await waitFor(() => { await waitFor(() => {
expect(result.current.isLoading).toBe(false) expect(result.current.isLoading).toBe(false)
+18 -18
View File
@@ -1,8 +1,8 @@
import axios from 'axios' import axios from 'axios'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { config } from '../config'
import { getLatestBeeDesktopVersion } from '../utils/desktop' import { getLatestBeeDesktopVersion } from '../utils/desktop'
import { getJson } from '../utils/net' import { getJson } from '../utils/net'
import { GITHUB_REPO_URL } from '../constants'
export interface LatestBeeReleaseHook { export interface LatestBeeReleaseHook {
latestBeeRelease: LatestBeeRelease | null latestBeeRelease: LatestBeeRelease | null
@@ -21,11 +21,7 @@ export interface NewDesktopVersionHook {
newBeeDesktopVersion: string newBeeDesktopVersion: string
} }
interface Config { export const useBeeDesktop = (isBeeDesktop = false, desktopUrl: string): BeeDesktopHook => {
BEE_DESKTOP_URL: string
}
export const useBeeDesktop = (isBeeDesktop = false, conf: Config = config): BeeDesktopHook => {
const [desktopAutoUpdateEnabled, setDesktopAutoUpdateEnabled] = useState<boolean>(true) const [desktopAutoUpdateEnabled, setDesktopAutoUpdateEnabled] = useState<boolean>(true)
const [beeDesktopVersion, setBeeDesktopVersion] = useState<string>('') const [beeDesktopVersion, setBeeDesktopVersion] = useState<string>('')
const [isLoading, setLoading] = useState<boolean>(true) const [isLoading, setLoading] = useState<boolean>(true)
@@ -37,7 +33,7 @@ export const useBeeDesktop = (isBeeDesktop = false, conf: Config = config): BeeD
setError(null) setError(null)
} else { } else {
axios axios
.get(`${conf.BEE_DESKTOP_URL}/info`) .get(`${desktopUrl}/info`)
.then(res => { .then(res => {
setBeeDesktopVersion(res.data?.version) setBeeDesktopVersion(res.data?.version)
setDesktopAutoUpdateEnabled(res.data?.autoUpdateEnabled) setDesktopAutoUpdateEnabled(res.data?.autoUpdateEnabled)
@@ -50,13 +46,13 @@ export const useBeeDesktop = (isBeeDesktop = false, conf: Config = config): BeeD
setLoading(false) setLoading(false)
}) })
} }
}, [conf, isBeeDesktop]) }, [desktopUrl, isBeeDesktop])
return { error, isLoading, beeDesktopVersion, desktopAutoUpdateEnabled } return { error, isLoading, beeDesktopVersion, desktopAutoUpdateEnabled }
} }
async function checkNewVersion(conf: Config): Promise<string> { async function checkNewVersion(desktopUrl: string): Promise<string> {
const resJson = await (await fetch(`${conf.BEE_DESKTOP_URL}/info`)).json() const resJson = await (await fetch(`${desktopUrl}/info`)).json()
const currentVersion = resJson.version const currentVersion = resJson.version
const latestVersion = await getLatestBeeDesktopVersion() const latestVersion = await getLatestBeeDesktopVersion()
@@ -67,20 +63,24 @@ async function checkNewVersion(conf: Config): Promise<string> {
return '' return ''
} }
export function useNewBeeDesktopVersion(isBeeDesktop: boolean, conf: Config = config): NewDesktopVersionHook { export function useNewBeeDesktopVersion(
isBeeDesktop: boolean,
desktopUrl: string,
desktopAutoUpdateEnabled: boolean,
): NewDesktopVersionHook {
const [newBeeDesktopVersion, setNewBeeDesktopVersion] = useState<string>('') const [newBeeDesktopVersion, setNewBeeDesktopVersion] = useState<string>('')
useEffect(() => { useEffect(() => {
if (!isBeeDesktop) { if (!isBeeDesktop || desktopAutoUpdateEnabled) {
return return
} }
checkNewVersion(conf).then(version => { checkNewVersion(desktopUrl).then(version => {
if (version !== '') { if (version !== '') {
setNewBeeDesktopVersion(version) setNewBeeDesktopVersion(version)
} }
}) })
}, [isBeeDesktop, conf]) }, [isBeeDesktop, desktopUrl, desktopAutoUpdateEnabled])
return { newBeeDesktopVersion } return { newBeeDesktopVersion }
} }
@@ -110,13 +110,13 @@ export interface GetBeeConfig {
error: Error | null error: Error | null
} }
export const useGetBeeConfig = (conf: Config = config): GetBeeConfig => { export const useGetBeeConfig = (desktopUrl: string): GetBeeConfig => {
const [beeConfig, setBeeConfig] = useState<BeeConfig | null>(null) const [beeConfig, setBeeConfig] = useState<BeeConfig | null>(null)
const [isLoading, setLoading] = useState<boolean>(true) const [isLoading, setLoading] = useState<boolean>(true)
const [error, setError] = useState<Error | null>(null) const [error, setError] = useState<Error | null>(null)
useEffect(() => { useEffect(() => {
getJson<BeeConfig>(`${conf.BEE_DESKTOP_URL}/config`) getJson<BeeConfig>(`${desktopUrl}/config`)
.then(beeConf => { .then(beeConf => {
setBeeConfig(beeConf) setBeeConfig(beeConf)
setError(null) setError(null)
@@ -128,7 +128,7 @@ export const useGetBeeConfig = (conf: Config = config): GetBeeConfig => {
.finally(() => { .finally(() => {
setLoading(false) setLoading(false)
}) })
}, [conf]) }, [desktopUrl])
return { config: beeConfig, isLoading, error } return { config: beeConfig, isLoading, error }
} }
@@ -140,7 +140,7 @@ export const useLatestBeeRelease = (): LatestBeeReleaseHook => {
useEffect(() => { useEffect(() => {
axios axios
.get(`${config.GITHUB_REPO_URL}/releases/latest`) .get(`${GITHUB_REPO_URL}/releases/latest`)
.then(res => { .then(res => {
setLatestBeeRelease(res.data) setLatestBeeRelease(res.data)
}) })
+6 -1
View File
@@ -4,9 +4,14 @@ import './index.css'
import App from './App' import App from './App'
import reportWebVitals from './reportWebVitals' import reportWebVitals from './reportWebVitals'
const desktopEnabled = Boolean(process.env.REACT_APP_BEE_DESKTOP_ENABLED)
const desktopUrl = process.env.REACT_APP_BEE_DESKTOP_URL
const beeApiUrl = process.env.REACT_APP_BEE_API_URL
const beeDebugApiUrl = process.env.REACT_APP_BEE_DEBUG_API_URL
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<App /> <App isDesktop={desktopEnabled} desktopUrl={desktopUrl} beeApiUrl={beeApiUrl} beeDebugApiUrl={beeDebugApiUrl} />
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root'), document.getElementById('root'),
) )
+15 -8
View File
@@ -7,8 +7,8 @@ import ErrorBoundary from '../components/ErrorBoundary'
import SideBar from '../components/SideBar' import SideBar from '../components/SideBar'
import { Context as BeeContext } from '../providers/Bee' import { Context as BeeContext } from '../providers/Bee'
import { Context as SettingsContext } from '../providers/Settings' import { Context as SettingsContext } from '../providers/Settings'
import { useNewBeeDesktopVersion } from '../hooks/apiHooks' import { useBeeDesktop, useNewBeeDesktopVersion } from '../hooks/apiHooks'
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../utils/desktop' import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../constants'
const useStyles = makeStyles((theme: Theme) => const useStyles = makeStyles((theme: Theme) =>
createStyles({ createStyles({
@@ -21,6 +21,7 @@ const useStyles = makeStyles((theme: Theme) =>
interface Props { interface Props {
children?: ReactElement children?: ReactElement
errorReporting?: (err: Error) => void
} }
const Dashboard = (props: Props): ReactElement => { const Dashboard = (props: Props): ReactElement => {
@@ -28,13 +29,14 @@ const Dashboard = (props: Props): ReactElement => {
const { isLoading, isLatestBeeVersion, latestBeeRelease, latestBeeVersionUrl, latestUserVersion } = const { isLoading, isLatestBeeVersion, latestBeeRelease, latestBeeVersionUrl, latestUserVersion } =
useContext(BeeContext) useContext(BeeContext)
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop, desktopUrl } = useContext(SettingsContext)
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isBeeDesktop) const { desktopAutoUpdateEnabled } = useBeeDesktop(isDesktop, desktopUrl)
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, desktopAutoUpdateEnabled)
const { enqueueSnackbar, closeSnackbar } = useSnackbar() const { enqueueSnackbar, closeSnackbar } = useSnackbar()
// New version of Bee client notification // New version of Bee client notification
useEffect(() => { useEffect(() => {
if (!isLoading && !isBeeDesktop && !isLatestBeeVersion && latestBeeRelease && latestUserVersion) { if (!isLoading && !isDesktop && !isLatestBeeVersion && latestBeeRelease && latestUserVersion) {
enqueueSnackbar(`There is new Bee version ${latestBeeRelease?.name}!`, { enqueueSnackbar(`There is new Bee version ${latestBeeRelease?.name}!`, {
variant: 'warning', variant: 'warning',
preventDuplicate: true, preventDuplicate: true,
@@ -65,7 +67,7 @@ const Dashboard = (props: Props): ReactElement => {
closeSnackbar, closeSnackbar,
enqueueSnackbar, enqueueSnackbar,
isLatestBeeVersion, isLatestBeeVersion,
isBeeDesktop, isDesktop,
latestBeeRelease, latestBeeRelease,
latestBeeVersionUrl, latestBeeVersionUrl,
isLoading, isLoading,
@@ -73,6 +75,11 @@ const Dashboard = (props: Props): ReactElement => {
]) ])
useEffect(() => { useEffect(() => {
// When autoupdate is enabled then we leave the version check for the built-in Electron update mechanism
if (desktopAutoUpdateEnabled) {
return
}
if (newBeeDesktopVersion !== '') { if (newBeeDesktopVersion !== '') {
enqueueSnackbar(`There is new Swarm Dashboard version ${newBeeDesktopVersion}!`, { enqueueSnackbar(`There is new Swarm Dashboard version ${newBeeDesktopVersion}!`, {
variant: 'warning', variant: 'warning',
@@ -100,7 +107,7 @@ const Dashboard = (props: Props): ReactElement => {
), ),
}) })
} }
}, [enqueueSnackbar, closeSnackbar, newBeeDesktopVersion]) }, [enqueueSnackbar, closeSnackbar, newBeeDesktopVersion, desktopAutoUpdateEnabled])
const content = ( const content = (
<> <>
@@ -119,7 +126,7 @@ const Dashboard = (props: Props): ReactElement => {
<SideBar /> <SideBar />
<Container className={classes.content}> <Container className={classes.content}>
{' '} {' '}
<ErrorBoundary>{content}</ErrorBoundary> <ErrorBoundary errorReporting={props.errorReporting}>{content}</ErrorBoundary>
</Container> </Container>
</div> </div>
) )
+2 -2
View File
@@ -20,7 +20,7 @@ import { Header } from '../Header'
export function AccountWallet(): ReactElement { export function AccountWallet(): ReactElement {
const { nodeAddresses, nodeInfo, status } = useContext(BeeContext) const { nodeAddresses, nodeInfo, status } = useContext(BeeContext)
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop } = useContext(SettingsContext)
const { balance } = useContext(BalanceProvider) const { balance } = useContext(BalanceProvider)
const navigate = useNavigate() const navigate = useNavigate()
@@ -72,7 +72,7 @@ export function AccountWallet(): ReactElement {
<SwarmButton onClick={onCheckTransactions} iconType={Link}> <SwarmButton onClick={onCheckTransactions} iconType={Link}>
Check transactions on Blockscout Check transactions on Blockscout
</SwarmButton> </SwarmButton>
{isBeeDesktop && ( {isDesktop && (
<SwarmButton onClick={onInvite} iconType={Gift}> <SwarmButton onClick={onInvite} iconType={Gift}>
Invite to Swarm... Invite to Swarm...
</SwarmButton> </SwarmButton>
+1 -2
View File
@@ -8,7 +8,6 @@ import { useNavigate, useParams } from 'react-router-dom'
import { HistoryHeader } from '../../components/HistoryHeader' import { HistoryHeader } from '../../components/HistoryHeader'
import { Loading } from '../../components/Loading' import { Loading } from '../../components/Loading'
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard' import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
import config from '../../config'
import { META_FILE_NAME, PREVIEW_FILE_NAME } from '../../constants' import { META_FILE_NAME, PREVIEW_FILE_NAME } from '../../constants'
import { Context as BeeContext } from '../../providers/Bee' import { Context as BeeContext } from '../../providers/Bee'
import { Context as SettingsContext } from '../../providers/Settings' import { Context as SettingsContext } from '../../providers/Settings'
@@ -78,7 +77,7 @@ export function Share(): ReactElement {
} catch (e) {} // eslint-disable-line no-empty } catch (e) {} // eslint-disable-line no-empty
if (previewFile) { if (previewFile) {
setPreview(`${config.BEE_API_HOST}/bzz/${reference}/${PREVIEW_FILE_NAME}`) setPreview(`${apiUrl}/bzz/${reference}/${PREVIEW_FILE_NAME}`)
} }
setMetadata(metadata) setMetadata(metadata)
+2 -2
View File
@@ -23,7 +23,7 @@ const GIFT_WALLET_FUND_BZZ_AMOUNT = Token.fromDecimal('0.5', 16)
export default function Index(): ReactElement { export default function Index(): ReactElement {
const { giftWallets, addGiftWallet } = useContext(TopUpContext) const { giftWallets, addGiftWallet } = useContext(TopUpContext)
const { provider } = useContext(SettingsContext) const { provider, desktopUrl } = useContext(SettingsContext)
const { balance } = useContext(BalanceProvider) const { balance } = useContext(BalanceProvider)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
@@ -50,7 +50,7 @@ export default function Index(): ReactElement {
try { try {
const wallet = Wallet.createRandom() const wallet = Wallet.createRandom()
addGiftWallet(wallet) addGiftWallet(wallet)
await createGiftWallet(wallet.address) await createGiftWallet(desktopUrl, wallet.address)
enqueueSnackbar('Succesfully funded gift wallet', { variant: 'success' }) enqueueSnackbar('Succesfully funded gift wallet', { variant: 'success' })
} catch (error) { } catch (error) {
console.error(error) // eslint-disable-line console.error(error) // eslint-disable-line
+6 -6
View File
@@ -13,8 +13,8 @@ import { Context as SettingsContext } from '../../providers/Settings'
import { Context as BalanceProvider } from '../../providers/WalletBalance' import { Context as BalanceProvider } from '../../providers/WalletBalance'
import { ROUTES } from '../../routes' import { ROUTES } from '../../routes'
import { chainIdToName } from '../../utils/chain' import { chainIdToName } from '../../utils/chain'
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../utils/desktop'
import NodeInfoCard from './NodeInfoCard' import NodeInfoCard from './NodeInfoCard'
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../constants'
export default function Status(): ReactElement { export default function Status(): ReactElement {
const { const {
@@ -27,10 +27,10 @@ export default function Status(): ReactElement {
chequebookBalance, chequebookBalance,
chainId, chainId,
} = useContext(BeeContext) } = useContext(BeeContext)
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop, desktopUrl } = useContext(SettingsContext)
const { balance, error } = useContext(BalanceProvider) const { balance, error } = useContext(BalanceProvider)
const { beeDesktopVersion } = useBeeDesktop(isBeeDesktop) const { beeDesktopVersion } = useBeeDesktop(isDesktop, desktopUrl)
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isBeeDesktop) const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, false)
const navigate = useNavigate() const navigate = useNavigate()
let balanceText = 'Loading...' let balanceText = 'Loading...'
@@ -114,7 +114,7 @@ export default function Status(): ReactElement {
<ExpandableListItem label="Connected peers" value={topology?.connected ?? '-'} /> <ExpandableListItem label="Connected peers" value={topology?.connected ?? '-'} />
<ExpandableListItem label="Population" value={topology?.population ?? '-'} /> <ExpandableListItem label="Population" value={topology?.population ?? '-'} />
<div style={{ height: '16px' }} /> <div style={{ height: '16px' }} />
{isBeeDesktop && ( {isDesktop && (
<ExpandableListItem <ExpandableListItem
label="Desktop version" label="Desktop version"
value={ value={
@@ -142,7 +142,7 @@ export default function Status(): ReactElement {
Bee Bee
</a> </a>
{` ${latestUserVersion ?? '-'} `} {` ${latestUserVersion ?? '-'} `}
{latestUserVersion && !isBeeDesktop && ( {latestUserVersion && !isDesktop && (
<Button <Button
size="small" size="small"
variant="outlined" variant="outlined"
+4 -4
View File
@@ -18,7 +18,7 @@ export default function SettingsPage(): ReactElement {
ensResolver, ensResolver,
providerUrl, providerUrl,
isLoading, isLoading,
isBeeDesktop, isDesktop,
setAndPersistJsonRpcProvider, setAndPersistJsonRpcProvider,
} = useContext(SettingsContext) } = useContext(SettingsContext)
const { refresh } = useContext(BeeContext) const { refresh } = useContext(BeeContext)
@@ -39,13 +39,13 @@ export default function SettingsPage(): ReactElement {
label="Bee API" label="Bee API"
value={apiUrl} value={apiUrl}
onConfirm={setApiUrl} onConfirm={setApiUrl}
locked={lockedApiSettings || isBeeDesktop} locked={lockedApiSettings || isDesktop}
/> />
<ExpandableListItemInput <ExpandableListItemInput
label="Bee Debug API" label="Bee Debug API"
value={apiDebugUrl} value={apiDebugUrl}
onConfirm={setDebugApiUrl} onConfirm={setDebugApiUrl}
locked={lockedApiSettings || isBeeDesktop} locked={lockedApiSettings || isDesktop}
/> />
<ExpandableListItemInput <ExpandableListItemInput
label="Blockchain RPC URL" label="Blockchain RPC URL"
@@ -65,7 +65,7 @@ export default function SettingsPage(): ReactElement {
}} }}
/> />
</ExpandableList> </ExpandableList>
{isBeeDesktop && ( {isDesktop && (
<ExpandableList label="Desktop Settings" defaultOpen> <ExpandableList label="Desktop Settings" defaultOpen>
<ExpandableListItemInput label="CORS" value={cors ?? '-'} locked /> <ExpandableListItemInput label="CORS" value={cors ?? '-'} locked />
<ExpandableListItemInput label="Data DIR" value={dataDir ?? '-'} locked /> <ExpandableListItemInput label="Data DIR" value={dataDir ?? '-'} locked />
+4 -4
View File
@@ -22,7 +22,7 @@ import { BeeModes } from '@ethersphere/bee-js'
export function GiftCardFund(): ReactElement { export function GiftCardFund(): ReactElement {
const { nodeAddresses, nodeInfo } = useContext(BeeContext) const { nodeAddresses, nodeInfo } = useContext(BeeContext)
const { isBeeDesktop, provider, providerUrl } = useContext(SettingsContext) const { isDesktop, desktopUrl, provider, providerUrl } = useContext(SettingsContext)
const { balance } = useContext(BalanceProvider) const { balance } = useContext(BalanceProvider)
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
@@ -45,13 +45,13 @@ export function GiftCardFund(): ReactElement {
return <Loading /> return <Loading />
} }
const canUpgradeToLightNode = isBeeDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
async function restart() { async function restart() {
try { try {
await sleepMs(5_000) await sleepMs(5_000)
await upgradeToLightNode(providerUrl) await upgradeToLightNode(desktopUrl, providerUrl)
await restartBeeNode() await restartBeeNode(desktopUrl)
enqueueSnackbar('Upgraded to light node', { variant: 'success' }) enqueueSnackbar('Upgraded to light node', { variant: 'success' })
navigate(ROUTES.RESTART_LIGHT) navigate(ROUTES.RESTART_LIGHT)
} catch (error) { } catch (error) {
+17 -15
View File
@@ -31,13 +31,21 @@ interface Props {
header: string header: string
} }
function isPositiveDecimal(value: string): boolean {
try {
return new BigNumber(value).isPositive()
} catch {
return false
}
}
export function Swap({ header }: Props): ReactElement { export function Swap({ header }: Props): ReactElement {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const [hasSwapped, setSwapped] = useState(false) const [hasSwapped, setSwapped] = useState(false)
const [userInputSwap, setUserInputSwap] = useState<string | null>(null) const [userInputSwap, setUserInputSwap] = useState<string | null>(null)
const [price, setPrice] = useState(DaiToken.fromDecimal('0.6', 18)) const [price, setPrice] = useState(DaiToken.fromDecimal('0.6', 18))
const { providerUrl, isBeeDesktop } = useContext(SettingsContext) const { providerUrl, isDesktop, desktopUrl } = useContext(SettingsContext)
const { nodeAddresses, nodeInfo } = useContext(BeeContext) const { nodeAddresses, nodeInfo } = useContext(BeeContext)
const { balance } = useContext(BalanceProvider) const { balance } = useContext(BalanceProvider)
@@ -46,8 +54,8 @@ export function Swap({ header }: Props): ReactElement {
useEffect(() => { useEffect(() => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
getBzzPriceAsDai().then(setPrice).catch(console.error) getBzzPriceAsDai(desktopUrl).then(setPrice).catch(console.error)
}, []) }, [desktopUrl])
if (!balance || !nodeAddresses) { if (!balance || !nodeAddresses) {
return <Loading /> return <Loading />
@@ -58,14 +66,6 @@ export function Swap({ header }: Props): ReactElement {
let daiToSwap: DaiToken let daiToSwap: DaiToken
function isPositiveDecimal(value: string): boolean {
try {
return new BigNumber(value).isPositive()
} catch {
return false
}
}
if (userInputSwap && isPositiveDecimal(userInputSwap)) { if (userInputSwap && isPositiveDecimal(userInputSwap)) {
daiToSwap = DaiToken.fromDecimal(userInputSwap, 18) daiToSwap = DaiToken.fromDecimal(userInputSwap, 18)
} else { } else {
@@ -75,13 +75,14 @@ export function Swap({ header }: Props): ReactElement {
const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber)) const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
const bzzAfterSwap = new BzzToken(daiToSwap.toBigNumber.dividedBy(100).dividedToIntegerBy(price.toDecimal)) const bzzAfterSwap = new BzzToken(daiToSwap.toBigNumber.dividedBy(100).dividedToIntegerBy(price.toDecimal))
const canUpgradeToLightNode = isBeeDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
async function restart() { async function restart() {
try { try {
await sleepMs(5_000) await sleepMs(5_000)
await upgradeToLightNode(providerUrl) await upgradeToLightNode(desktopUrl, providerUrl)
await restartBeeNode() await restartBeeNode(desktopUrl)
enqueueSnackbar('Upgraded to light node', { variant: 'success' }) enqueueSnackbar('Upgraded to light node', { variant: 'success' })
navigate(ROUTES.RESTART_LIGHT) navigate(ROUTES.RESTART_LIGHT)
} catch (error) { } catch (error) {
@@ -96,8 +97,9 @@ export function Swap({ header }: Props): ReactElement {
} }
setLoading(true) setLoading(true)
setSwapped(true) setSwapped(true)
try { try {
await performSwap(daiToSwap.toString) await performSwap(desktopUrl, daiToSwap.toString)
enqueueSnackbar('Successfully swapped', { variant: 'success' }) enqueueSnackbar('Successfully swapped', { variant: 'success' })
if (canUpgradeToLightNode) await restart() if (canUpgradeToLightNode) await restart()
+4 -4
View File
@@ -39,7 +39,7 @@ const MINIMUM_XBZZ = '0.1'
export default function TopUp(): ReactElement { export default function TopUp(): ReactElement {
const navigate = useNavigate() const navigate = useNavigate()
const styles = useStyles() const styles = useStyles()
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop, desktopUrl } = useContext(SettingsContext)
const { nodeInfo, status } = useContext(BeeContext) const { nodeInfo, status } = useContext(BeeContext)
const { balance } = useContext(BalanceProvider) const { balance } = useContext(BalanceProvider)
const { providerUrl } = useContext(SettingsContext) const { providerUrl } = useContext(SettingsContext)
@@ -47,7 +47,7 @@ export default function TopUp(): ReactElement {
const { enqueueSnackbar } = useSnackbar() const { enqueueSnackbar } = useSnackbar()
const canUpgradeToLightNode = const canUpgradeToLightNode =
isBeeDesktop && isDesktop &&
nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT &&
balance?.dai.toDecimal.gte(MINIMUM_XDAI) && balance?.dai.toDecimal.gte(MINIMUM_XDAI) &&
balance?.bzz.toDecimal.gte(MINIMUM_XBZZ) balance?.bzz.toDecimal.gte(MINIMUM_XBZZ)
@@ -55,8 +55,8 @@ export default function TopUp(): ReactElement {
async function restart() { async function restart() {
setLoading(true) setLoading(true)
try { try {
await upgradeToLightNode(providerUrl) await upgradeToLightNode(desktopUrl, providerUrl)
await restartBeeNode() await restartBeeNode(desktopUrl)
enqueueSnackbar('Upgraded to light node', { variant: 'success' }) enqueueSnackbar('Upgraded to light node', { variant: 'success' })
navigate(ROUTES.RESTART_LIGHT) navigate(ROUTES.RESTART_LIGHT)
} catch (error) { } catch (error) {
+68 -47
View File
@@ -1,15 +1,15 @@
import { Bee, BeeDebug } from '@ethersphere/bee-js' import { Bee, BeeDebug } from '@ethersphere/bee-js'
import { providers } from 'ethers' import { providers } from 'ethers'
import { createContext, ReactNode, ReactElement, useEffect, useState } from 'react' import { createContext, ReactNode, ReactElement, useEffect, useState } from 'react'
import { config as appConfig } from '../config'
import { useGetBeeConfig } from '../hooks/apiHooks' import { useGetBeeConfig } from '../hooks/apiHooks'
import { restartBeeNode, setJsonRpcInDesktop } from '../utils/desktop' import { restartBeeNode, setJsonRpcInDesktop } from '../utils/desktop'
import { DEFAULT_BEE_API_HOST, DEFAULT_BEE_DEBUG_API_HOST, DEFAULT_RPC_URL } from '../constants'
const LocalStorageKeys = { const LocalStorageKeys = {
providerUrl: 'json-rpc-provider', providerUrl: 'json-rpc-provider',
} }
const providerUrl = localStorage.getItem('json-rpc-provider') || appConfig.DEFAULT_RPC_URL const providerUrl = localStorage.getItem('json-rpc-provider') || DEFAULT_RPC_URL
interface ContextInterface { interface ContextInterface {
apiUrl: string apiUrl: string
@@ -18,6 +18,8 @@ interface ContextInterface {
beeDebugApi: BeeDebug | null beeDebugApi: BeeDebug | null
lockedApiSettings: boolean lockedApiSettings: boolean
desktopApiKey: string desktopApiKey: string
isDesktop: boolean
desktopUrl: string
providerUrl: string providerUrl: string
provider: providers.JsonRpcProvider provider: providers.JsonRpcProvider
cors: string | null cors: string | null
@@ -26,27 +28,27 @@ interface ContextInterface {
setApiUrl: (url: string) => void setApiUrl: (url: string) => void
setDebugApiUrl: (url: string) => void setDebugApiUrl: (url: string) => void
setAndPersistJsonRpcProvider: (url: string) => Promise<void> setAndPersistJsonRpcProvider: (url: string) => Promise<void>
isBeeDesktop: boolean
isLoading: boolean isLoading: boolean
error: Error | null error: Error | null
} }
const initialValues: ContextInterface = { const initialValues: ContextInterface = {
apiUrl: appConfig.BEE_API_HOST,
apiDebugUrl: appConfig.BEE_DEBUG_API_HOST,
beeApi: null, beeApi: null,
beeDebugApi: null, beeDebugApi: null,
apiUrl: DEFAULT_BEE_API_HOST,
apiDebugUrl: DEFAULT_BEE_DEBUG_API_HOST,
setApiUrl: () => {}, // eslint-disable-line setApiUrl: () => {}, // eslint-disable-line
setDebugApiUrl: () => {}, // eslint-disable-line setDebugApiUrl: () => {}, // eslint-disable-line
lockedApiSettings: false, lockedApiSettings: false,
isDesktop: false,
desktopApiKey: '', desktopApiKey: '',
desktopUrl: window.location.origin,
setAndPersistJsonRpcProvider: async () => {}, // eslint-disable-line setAndPersistJsonRpcProvider: async () => {}, // eslint-disable-line
providerUrl, providerUrl,
provider: new providers.JsonRpcProvider(providerUrl), provider: new providers.JsonRpcProvider(providerUrl),
cors: null, cors: null,
dataDir: null, dataDir: null,
ensResolver: null, ensResolver: null,
isBeeDesktop: false,
isLoading: true, isLoading: true,
error: null, error: null,
} }
@@ -54,21 +56,22 @@ const initialValues: ContextInterface = {
export const Context = createContext<ContextInterface>(initialValues) export const Context = createContext<ContextInterface>(initialValues)
export const Consumer = Context.Consumer export const Consumer = Context.Consumer
interface Props { interface InitialSettings {
children: ReactNode
beeApiUrl?: string beeApiUrl?: string
beeDebugApiUrl?: string beeDebugApiUrl?: string
lockedApiSettings?: boolean lockedApiSettings?: boolean
isBeeDesktop?: boolean isDesktop?: boolean
desktopUrl?: string
} }
export function Provider({ interface Props extends InitialSettings {
children, children: ReactNode
beeApiUrl, }
beeDebugApiUrl,
lockedApiSettings: extLockedApiSettings, export function Provider({ children, ...propsSettings }: Props): ReactElement {
isBeeDesktop: extIsBeeDesktop, const desktopUrl = propsSettings.desktopUrl ?? initialValues.desktopUrl
}: Props): ReactElement { const isDesktop = Boolean(propsSettings.isDesktop)
const [apiUrl, setApiUrl] = useState<string>(initialValues.apiUrl) const [apiUrl, setApiUrl] = useState<string>(initialValues.apiUrl)
const [apiDebugUrl, setDebugApiUrl] = useState<string>(initialValues.apiDebugUrl) const [apiDebugUrl, setDebugApiUrl] = useState<string>(initialValues.apiDebugUrl)
const [beeApi, setBeeApi] = useState<Bee | null>(null) const [beeApi, setBeeApi] = useState<Bee | null>(null)
@@ -76,35 +79,17 @@ export function Provider({
const [desktopApiKey, setDesktopApiKey] = useState<string>(initialValues.desktopApiKey) const [desktopApiKey, setDesktopApiKey] = useState<string>(initialValues.desktopApiKey)
const [providerUrl, setProviderUrl] = useState(initialValues.providerUrl) const [providerUrl, setProviderUrl] = useState(initialValues.providerUrl)
const [provider, setProvider] = useState(initialValues.provider) const [provider, setProvider] = useState(initialValues.provider)
const { config, isLoading, error } = useGetBeeConfig() const { config, isLoading, error } = useGetBeeConfig(desktopUrl)
const isBeeDesktop = Boolean(extIsBeeDesktop ?? appConfig.BEE_DESKTOP_ENABLED) const url = makeHttpUrl(
config?.['api-addr'] ?? sessionStorage.getItem('api_host') ?? propsSettings.beeApiUrl ?? apiUrl,
async function setAndPersistJsonRpcProvider(providerUrl: string) { )
try { const debugUrl = makeHttpUrl(
localStorage.setItem(LocalStorageKeys.providerUrl, providerUrl) config?.['debug-api-addr'] ??
setProviderUrl(providerUrl) sessionStorage.getItem('debug_api_host') ??
setProvider(new providers.JsonRpcProvider(providerUrl)) propsSettings.beeDebugApiUrl ??
apiDebugUrl,
if (isBeeDesktop) { )
await setJsonRpcInDesktop(providerUrl)
await restartBeeNode()
}
} catch (error) {
console.error(error) // eslint-disable-line
}
}
function makeHttpUrl(string: string): string {
if (!string.startsWith('http')) {
return `http://${string}`
}
return string
}
const url = makeHttpUrl(config?.['api-addr'] || beeApiUrl || apiUrl)
const debugUrl = makeHttpUrl(config?.['debug-api-addr'] || beeDebugApiUrl || apiDebugUrl)
useEffect(() => { useEffect(() => {
const urlSearchParams = new URLSearchParams(window.location.search) const urlSearchParams = new URLSearchParams(window.location.search)
@@ -144,15 +129,21 @@ export function Provider({
beeDebugApi, beeDebugApi,
setApiUrl, setApiUrl,
setDebugApiUrl, setDebugApiUrl,
lockedApiSettings: Boolean(extLockedApiSettings), lockedApiSettings: Boolean(propsSettings.lockedApiSettings),
desktopApiKey, desktopApiKey,
isDesktop,
desktopUrl,
provider, provider,
providerUrl, providerUrl,
cors: config?.['cors-allowed-origins'] ?? null, cors: config?.['cors-allowed-origins'] ?? null,
dataDir: config?.['data-dir'] ?? null, dataDir: config?.['data-dir'] ?? null,
ensResolver: config?.['resolver-options'] ?? null, ensResolver: config?.['resolver-options'] ?? null,
setAndPersistJsonRpcProvider, setAndPersistJsonRpcProvider: setAndPersistJsonRpcProviderClosure(
isBeeDesktop, isDesktop,
desktopUrl,
setProviderUrl,
setProvider,
),
isLoading, isLoading,
error, error,
}} }}
@@ -161,3 +152,33 @@ export function Provider({
</Context.Provider> </Context.Provider>
) )
} }
function makeHttpUrl(string: string): string {
if (!string.startsWith('http')) {
return `http://${string}`
}
return string
}
function setAndPersistJsonRpcProviderClosure(
isDesktop: boolean,
desktopUrl: string,
setProviderUrl: (url: string) => void,
setProvider: (prov: providers.JsonRpcProvider) => void,
) {
return async (providerUrl: string) => {
try {
localStorage.setItem(LocalStorageKeys.providerUrl, providerUrl)
setProviderUrl(providerUrl)
setProvider(new providers.JsonRpcProvider(providerUrl))
if (isDesktop) {
await setJsonRpcInDesktop(desktopUrl, providerUrl)
await restartBeeNode(desktopUrl)
}
} catch (error) {
console.error(error) // eslint-disable-line
}
}
}
+2 -2
View File
@@ -61,7 +61,7 @@ export const ACCOUNT_TABS = [
] ]
const BaseRouter = (): ReactElement => { const BaseRouter = (): ReactElement => {
const { isBeeDesktop } = useContext(SettingsContext) const { isDesktop } = useContext(SettingsContext)
return ( return (
<Routes> <Routes>
@@ -88,7 +88,7 @@ const BaseRouter = (): ReactElement => {
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} /> <Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} /> <Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
<Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} /> <Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} />
{isBeeDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />} {isDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />}
</Routes> </Routes>
) )
} }
+17 -51
View File
@@ -1,81 +1,47 @@
import axios from 'axios' import axios from 'axios'
import { DaiToken } from '../models/DaiToken' import { DaiToken } from '../models/DaiToken'
import { Token } from '../models/Token' import { Token } from '../models/Token'
import { getJson, postJson, sendRequest } from './net' import { postJson } from './net'
import { BEE_DESKTOP_LATEST_RELEASE_PAGE_API } from '../constants'
interface DesktopStatus { export async function getBzzPriceAsDai(desktopUrl: string): Promise<Token> {
status: 0 | 1 | 2 const response = await axios.get(`${desktopUrl}/price`)
address: string | null
// eslint-disable-next-line @typescript-eslint/no-explicit-any
config: Record<string, any>
}
export const BEE_DESKTOP_LATEST_RELEASE_PAGE = 'https://github.com/ethersphere/bee-desktop/releases/latest'
export async function getDesktopStatus(): Promise<DesktopStatus> {
const response = await getJson(`${getDesktopHost()}/status`)
return response as DesktopStatus
}
export async function getBzzPriceAsDai(): Promise<Token> {
const response = await axios.get(`${getDesktopHost()}/price`)
return DaiToken.fromDecimal(response.data, 18) return DaiToken.fromDecimal(response.data, 18)
} }
export async function upgradeToLightNode(rpcProvider: string): Promise<void> { export async function upgradeToLightNode(desktopUrl: string, rpcProvider: string): Promise<void> {
await updateDesktopConfiguration({ await updateDesktopConfiguration(desktopUrl, {
'chain-enable': true, 'chain-enable': true,
'swap-enable': true, 'swap-enable': true,
'swap-endpoint': rpcProvider, 'swap-endpoint': rpcProvider,
}) })
} }
export async function setJsonRpcInDesktop(value: string): Promise<void> { export async function setJsonRpcInDesktop(desktopUrl: string, value: string): Promise<void> {
await updateDesktopConfiguration({ await updateDesktopConfiguration(desktopUrl, {
'swap-endpoint': value, 'swap-endpoint': value,
}) })
} }
async function updateDesktopConfiguration(values: Record<string, unknown>): Promise<void> { async function updateDesktopConfiguration(desktopUrl: string, values: Record<string, unknown>): Promise<void> {
await postJson(`${getDesktopHost()}/config`, values) await postJson(`${desktopUrl}/config`, values)
} }
export async function restartBeeNode(): Promise<void> { export async function restartBeeNode(desktopUrl: string): Promise<void> {
await postJson(`${getDesktopHost()}/restart`) await postJson(`${desktopUrl}/restart`)
} }
export async function createGiftWallet(address: string): Promise<void> { export async function createGiftWallet(desktopUrl: string, address: string): Promise<void> {
await postJson(`${getDesktopHost()}/gift-wallet/${address}`) await postJson(`${desktopUrl}/gift-wallet/${address}`)
} }
export async function performSwap(daiAmount: string): Promise<void> { export async function performSwap(desktopUrl: string, daiAmount: string): Promise<void> {
await postJson(`${getDesktopHost()}/swap`, { dai: daiAmount }) await postJson(`${desktopUrl}/swap`, { dai: daiAmount })
}
export async function getBeeDesktopLogs(): Promise<string> {
const response = await sendRequest(`${getDesktopHost()}/logs/bee-desktop`, 'GET')
return response as unknown as string
}
export async function getBeeLogs(): Promise<string> {
const response = await sendRequest(`${getDesktopHost()}/logs/bee`, 'GET')
return response as unknown as string
} }
export async function getLatestBeeDesktopVersion(): Promise<string> { export async function getLatestBeeDesktopVersion(): Promise<string> {
const response = await (await fetch('https://api.github.com/repos/ethersphere/bee-desktop/releases/latest')).json() const response = await (await fetch(BEE_DESKTOP_LATEST_RELEASE_PAGE_API)).json()
return response.tag_name.replace('v', '') // We get for example "v0.12.1" return response.tag_name.replace('v', '') // We get for example "v0.12.1"
} }
function getDesktopHost(): string {
if (process.env.REACT_APP_BEE_DESKTOP_URL) {
return process.env.REACT_APP_BEE_DESKTOP_URL
}
return `http://${window.location.host}`
}