Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da0ae9cd94 | |||
| 528a810690 | |||
| 0c74dae4e8 | |||
| d42d440f85 | |||
| 0c262a4811 | |||
| 0603018f09 | |||
| 677b6de0f8 | |||
| 27f965ef63 | |||
| e72347d87a | |||
| 0260df61de |
@@ -19,9 +19,6 @@ jobs:
|
||||
env:
|
||||
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_DEV_MODE: 1
|
||||
REACT_APP_SENTRY_KEY: ${{ secrets.SENTRY_KEY }}
|
||||
REACT_APP_SENTRY_ENVIRONMENT: 'preview'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -18,16 +18,3 @@ jobs:
|
||||
- run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
- id: cleanVersion
|
||||
run: |
|
||||
version="${{ github.event.release.release.tag_name }}"
|
||||
echo "::set-output name=value::${version/v}"
|
||||
- name: Create Sentry release
|
||||
uses: getsentry/action-release@v1
|
||||
env:
|
||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
||||
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
||||
with:
|
||||
sourcemaps: ./build/static/js
|
||||
version: ${{ steps.cleanVersion.outputs.value }}
|
||||
|
||||
@@ -17,9 +17,6 @@ jobs:
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
env:
|
||||
REACT_APP_SENTRY_KEY: ${{ secrets.SENTRY_KEY }}
|
||||
REACT_APP_SENTRY_ENVIRONMENT: 'pages'
|
||||
- run: echo "dashboard.ethswarm.org" > ./build/CNAME
|
||||
- name: Deploy to gh-pages
|
||||
uses: peaceiris/actions-gh-pages@v3
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
# 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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* pass isBeeDesktop from provider to hook ([#525](https://github.com/ethersphere/bee-dashboard/issues/525)) ([677b6de](https://github.com/ethersphere/bee-dashboard/commit/677b6de0f82b02e1487420e3c08fbd19a949f97b))
|
||||
|
||||
## [0.19.2](https://github.com/ethersphere/bee-dashboard/compare/v0.19.1...v0.19.2) (2022-08-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove sentry ([#520](https://github.com/ethersphere/bee-dashboard/issues/520)) ([0260df6](https://github.com/ethersphere/bee-dashboard/commit/0260df61de0619202a819b79820cfbef6e3757ae))
|
||||
|
||||
## [0.19.1](https://github.com/ethersphere/bee-dashboard/compare/v0.19.0...v0.19.1) (2022-08-03)
|
||||
|
||||
|
||||
|
||||
@@ -94,7 +94,15 @@ npm start
|
||||
|
||||
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
|
||||
|
||||
|
||||
Generated
+11
-175
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ethersphere/bee-dashboard",
|
||||
"version": "0.19.1",
|
||||
"version": "0.20.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ethersphere/bee-dashboard",
|
||||
"version": "0.19.1",
|
||||
"version": "0.20.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@ethersphere/bee-js": "^5.0.0",
|
||||
@@ -15,8 +15,6 @@
|
||||
"@material-ui/core": "4.12.3",
|
||||
"@material-ui/icons": "4.11.2",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@sentry/react": "^7.1.1",
|
||||
"@sentry/tracing": "^7.1.1",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "0.24.0",
|
||||
"bignumber.js": "9.0.1",
|
||||
@@ -65,9 +63,9 @@
|
||||
"@types/file-saver": "2.0.4",
|
||||
"@types/jest": "27.0.2",
|
||||
"@types/qrcode.react": "1.0.2",
|
||||
"@types/react": ">=17.0.0 || >=18.0.0",
|
||||
"@types/react": "17.0.34",
|
||||
"@types/react-copy-to-clipboard": "5.0.2",
|
||||
"@types/react-dom": ">=17.0.0 || >=18.0.0",
|
||||
"@types/react-dom": "17.0.11",
|
||||
"@types/react-router": "5.1.18",
|
||||
"@types/react-router-dom": "5.3.2",
|
||||
"@types/react-syntax-highlighter": "13.5.2",
|
||||
@@ -101,7 +99,7 @@
|
||||
"react-scripts": "^5.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "4.7.3",
|
||||
"typescript": "4.8.2",
|
||||
"web-vitals": "2.1.2",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
@@ -4183,99 +4181,6 @@
|
||||
"integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.1.1.tgz",
|
||||
"integrity": "sha512-5AQvStZ+nOP/yxsBmeMZpeGLVtuOgnCNvswKd/c1CJwNw7bDmCE4TQeNKp1C3Gb7lSdBk8ViwUKn0ZpoVQ5MTw==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.1.1.tgz",
|
||||
"integrity": "sha512-SADdAoG5u1LTJhPN5KPtn5HHmH6r0mr6h2LokuZnhj6/okrAuCIIKOb6Fh8jV7j2VuABvew8+FjJHORxi7D/3Q==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/hub": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.1.1.tgz",
|
||||
"integrity": "sha512-ASsRVjYDIii6ZTf36JnIYKHWBQBk0P42Tgq324MpyPgaeVDg3saBcyXO5iAtWvY6Vmdi2H4JCVDoir2Zz3Me1w==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/react": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.1.1.tgz",
|
||||
"integrity": "sha512-Z7cZvXHIWxg7OhOSy4InhrRgQPRNtHsyOkIAHkgwW32JYOGTg1HdqQ5mFUxQLejhU/YqsxVjTK4CI58FATykLw==",
|
||||
"dependencies": {
|
||||
"@sentry/browser": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "15.x || 16.x || 17.x || 18.x"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/tracing": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.1.1.tgz",
|
||||
"integrity": "sha512-MJ+EPGfvPlgbJOcZRoIl6+Oi0oRE2nIi/HP2BPJSKGxXFi2Y09bcZUwfxOH8fkUa465jOGBFdCm+sXcbyExvuw==",
|
||||
"dependencies": {
|
||||
"@sentry/hub": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.1.1.tgz",
|
||||
"integrity": "sha512-5N1UMd2SqvUXprcIUMyDEju3H9lJY2oWfWQBGo0lG6Amn/lGAPAYlchg+4vQCLutDQMyd8K9zPwcbKn4u6gHdw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.1.1.tgz",
|
||||
"integrity": "sha512-DPRHDf3InfyVgmxToE4Z+AATAR4OVm+wsXDLFGGyncR91CE1x4wLQKOcAJJwX3F0Hz1VHENfmx1DvyYTHOrC/A==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinclair/typebox": {
|
||||
"version": "0.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz",
|
||||
@@ -19505,9 +19410,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz",
|
||||
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==",
|
||||
"version": "4.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
|
||||
"integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@@ -23578,75 +23483,6 @@
|
||||
"integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==",
|
||||
"dev": true
|
||||
},
|
||||
"@sentry/browser": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.1.1.tgz",
|
||||
"integrity": "sha512-5AQvStZ+nOP/yxsBmeMZpeGLVtuOgnCNvswKd/c1CJwNw7bDmCE4TQeNKp1C3Gb7lSdBk8ViwUKn0ZpoVQ5MTw==",
|
||||
"requires": {
|
||||
"@sentry/core": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/core": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.1.1.tgz",
|
||||
"integrity": "sha512-SADdAoG5u1LTJhPN5KPtn5HHmH6r0mr6h2LokuZnhj6/okrAuCIIKOb6Fh8jV7j2VuABvew8+FjJHORxi7D/3Q==",
|
||||
"requires": {
|
||||
"@sentry/hub": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/hub": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-7.1.1.tgz",
|
||||
"integrity": "sha512-ASsRVjYDIii6ZTf36JnIYKHWBQBk0P42Tgq324MpyPgaeVDg3saBcyXO5iAtWvY6Vmdi2H4JCVDoir2Zz3Me1w==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/react": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.1.1.tgz",
|
||||
"integrity": "sha512-Z7cZvXHIWxg7OhOSy4InhrRgQPRNtHsyOkIAHkgwW32JYOGTg1HdqQ5mFUxQLejhU/YqsxVjTK4CI58FATykLw==",
|
||||
"requires": {
|
||||
"@sentry/browser": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/tracing": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.1.1.tgz",
|
||||
"integrity": "sha512-MJ+EPGfvPlgbJOcZRoIl6+Oi0oRE2nIi/HP2BPJSKGxXFi2Y09bcZUwfxOH8fkUa465jOGBFdCm+sXcbyExvuw==",
|
||||
"requires": {
|
||||
"@sentry/hub": "7.1.1",
|
||||
"@sentry/types": "7.1.1",
|
||||
"@sentry/utils": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sentry/types": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.1.1.tgz",
|
||||
"integrity": "sha512-5N1UMd2SqvUXprcIUMyDEju3H9lJY2oWfWQBGo0lG6Amn/lGAPAYlchg+4vQCLutDQMyd8K9zPwcbKn4u6gHdw=="
|
||||
},
|
||||
"@sentry/utils": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.1.1.tgz",
|
||||
"integrity": "sha512-DPRHDf3InfyVgmxToE4Z+AATAR4OVm+wsXDLFGGyncR91CE1x4wLQKOcAJJwX3F0Hz1VHENfmx1DvyYTHOrC/A==",
|
||||
"requires": {
|
||||
"@sentry/types": "7.1.1",
|
||||
"tslib": "^1.9.3"
|
||||
}
|
||||
},
|
||||
"@sinclair/typebox": {
|
||||
"version": "0.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz",
|
||||
@@ -35074,9 +34910,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.7.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.3.tgz",
|
||||
"integrity": "sha512-WOkT3XYvrpXx4vMMqlD+8R8R37fZkjyLGlxavMc4iB8lrl8L0DeTcHbYgw/v0N/z9wAFsgBhcsF0ruoySS22mA==",
|
||||
"version": "4.8.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz",
|
||||
"integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==",
|
||||
"dev": true
|
||||
},
|
||||
"unbox-primitive": {
|
||||
|
||||
+3
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ethersphere/bee-dashboard",
|
||||
"version": "0.19.1",
|
||||
"version": "0.20.0",
|
||||
"description": "An app which helps users to setup their Bee node and do actions like cash out cheques",
|
||||
"keywords": [
|
||||
"bee",
|
||||
@@ -32,8 +32,6 @@
|
||||
"@material-ui/core": "4.12.3",
|
||||
"@material-ui/icons": "4.11.2",
|
||||
"@material-ui/lab": "4.0.0-alpha.57",
|
||||
"@sentry/react": "^7.1.1",
|
||||
"@sentry/tracing": "^7.1.1",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "0.24.0",
|
||||
"bignumber.js": "9.0.1",
|
||||
@@ -115,7 +113,7 @@
|
||||
"react-scripts": "^5.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"ts-node": "^10.8.1",
|
||||
"typescript": "4.7.3",
|
||||
"typescript": "4.8.2",
|
||||
"web-vitals": "2.1.2",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-cli": "^4.10.0"
|
||||
@@ -162,4 +160,4 @@
|
||||
"npm": ">=6.9.0",
|
||||
"bee": ">=0.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-25
@@ -3,7 +3,6 @@ import { ThemeProvider } from '@material-ui/core/styles'
|
||||
import { SnackbarProvider } from 'notistack'
|
||||
import React, { ReactElement } from 'react'
|
||||
import { HashRouter as Router } from 'react-router-dom'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import './App.css'
|
||||
import Dashboard from './layout/Dashboard'
|
||||
import { Provider as BeeProvider } from './providers/Bee'
|
||||
@@ -16,23 +15,24 @@ import { Provider as TopUpProvider } from './providers/TopUp'
|
||||
import { Provider as BalanceProvider } from './providers/WalletBalance'
|
||||
import BaseRouter from './routes'
|
||||
import { theme } from './theme'
|
||||
import { config } from './config'
|
||||
import ItsBroken from './layout/ItsBroken'
|
||||
import { initSentry } from './utils/sentry'
|
||||
|
||||
interface Props {
|
||||
beeApiUrl?: string
|
||||
beeDebugApiUrl?: string
|
||||
lockedApiSettings?: boolean
|
||||
isBeeDesktop?: boolean
|
||||
isDesktop?: boolean
|
||||
desktopUrl?: string
|
||||
errorReporting?: (err: Error) => void
|
||||
}
|
||||
|
||||
if (config.SENTRY_KEY) {
|
||||
// eslint-disable-next-line no-console
|
||||
initSentry().catch(e => console.error(e))
|
||||
}
|
||||
|
||||
const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Props): ReactElement => {
|
||||
const App = ({
|
||||
beeApiUrl,
|
||||
beeDebugApiUrl,
|
||||
lockedApiSettings,
|
||||
isDesktop,
|
||||
desktopUrl,
|
||||
errorReporting,
|
||||
}: Props): ReactElement => {
|
||||
const mainApp = (
|
||||
<div className="App">
|
||||
<ThemeProvider theme={theme}>
|
||||
@@ -40,7 +40,8 @@ const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Pro
|
||||
beeApiUrl={beeApiUrl}
|
||||
beeDebugApiUrl={beeDebugApiUrl}
|
||||
lockedApiSettings={lockedApiSettings}
|
||||
isBeeDesktop={isBeeDesktop}
|
||||
isDesktop={isDesktop}
|
||||
desktopUrl={desktopUrl}
|
||||
>
|
||||
<TopUpProvider>
|
||||
<BeeProvider>
|
||||
@@ -53,7 +54,7 @@ const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Pro
|
||||
<Router>
|
||||
<>
|
||||
<CssBaseline />
|
||||
<Dashboard>
|
||||
<Dashboard errorReporting={errorReporting}>
|
||||
<BaseRouter />
|
||||
</Dashboard>
|
||||
</>
|
||||
@@ -71,18 +72,6 @@ const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings, isBeeDesktop }: Pro
|
||||
</div>
|
||||
)
|
||||
|
||||
// Displays Report Dialog when some component crashes
|
||||
if (config.SENTRY_KEY) {
|
||||
return (
|
||||
<Sentry.ErrorBoundary
|
||||
showDialog
|
||||
fallback={({ error, componentStack, resetError }) => <ItsBroken message={error.message} />}
|
||||
>
|
||||
{mainApp}
|
||||
</Sentry.ErrorBoundary>
|
||||
)
|
||||
}
|
||||
|
||||
return mainApp
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Component, ErrorInfo, ReactElement } from 'react'
|
||||
import ItsBroken from '../layout/ItsBroken'
|
||||
|
||||
interface Props {
|
||||
children: ReactElement
|
||||
errorReporting?: (err: Error) => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
@@ -10,8 +10,11 @@ interface State {
|
||||
}
|
||||
|
||||
export default class ErrorBoundary extends Component<Props, State> {
|
||||
private errorReporting?: (err: Error) => void
|
||||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.errorReporting = props.errorReporting
|
||||
this.state = { error: null }
|
||||
}
|
||||
|
||||
@@ -21,13 +24,17 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
render(): ReactElement {
|
||||
if (this.state.error) {
|
||||
return <ItsBroken message={this.state.error.message} />
|
||||
// You can render any custom fallback UI
|
||||
return <h1>Something went wrong. Error: {this.state.error.message}</h1>
|
||||
}
|
||||
|
||||
return this.props.children
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Typography } from '@material-ui/core/'
|
||||
import { ReactElement } from 'react'
|
||||
import Identicon from 'react-identicons'
|
||||
import { config } from '../config'
|
||||
import ClipboardCopy from './ClipboardCopy'
|
||||
import QRCodeModal from './QRCodeModal'
|
||||
import { BLOCKCHAIN_EXPLORER_URL } from '../constants'
|
||||
|
||||
interface Props {
|
||||
address: string | undefined
|
||||
@@ -36,7 +36,7 @@ export default function EthereumAddress(props: Props): ReactElement {
|
||||
}
|
||||
: { 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"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import { ReactElement, useEffect, useState } from 'react'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import { Link } from '@material-ui/core'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import MessageSquare from 'remixicon-react/Message2LineIcon'
|
||||
|
||||
import config from '../config'
|
||||
import SideBarItem from './SideBarItem'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
link: {
|
||||
color: '#9f9f9f',
|
||||
textDecoration: 'none',
|
||||
'&:hover': {
|
||||
textDecoration: 'none',
|
||||
|
||||
// https://github.com/mui-org/material-ui/issues/22543
|
||||
'@media (hover: none)': {
|
||||
textDecoration: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
icon: {
|
||||
height: theme.spacing(4),
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
/**
|
||||
* Parses Sentry DNS so it could be transformed into API call
|
||||
* Sentry DNS like https://1asfasdf2312asdf3@o132123.ingest.sentry.io/13123123
|
||||
*/
|
||||
const SENTRY_PARSING_REGEX = /^https:\/\/(?<key>\w+)@(?<sub>\w+)\.ingest\.sentry\.io\/(?<path>\d+)$/gm
|
||||
|
||||
async function isSentryReachable(): Promise<boolean> {
|
||||
const key = config.SENTRY_KEY
|
||||
|
||||
if (!key) {
|
||||
return false
|
||||
}
|
||||
|
||||
const match = SENTRY_PARSING_REGEX.exec(key)
|
||||
|
||||
if (!match) {
|
||||
return false
|
||||
}
|
||||
|
||||
const url = `https://${match.groups?.sub}.ingest.sentry.io/api/${match.groups?.path}/envelope/?sentry_key=${match.groups?.key}`
|
||||
|
||||
try {
|
||||
await fetch(url, { method: 'POST' })
|
||||
|
||||
// Since we got some reply (even though most probably with some error) that means Sentry is reachable ==> lets provide the Feedback form
|
||||
return true
|
||||
} catch (e) {
|
||||
// If an error was thrown than the request was blocked by the browser so Sentry is not accessible to us
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function showFeedbackForm(): void {
|
||||
const eventId = Sentry.captureMessage('User feedback')
|
||||
Sentry.showReportDialog({
|
||||
eventId,
|
||||
title: 'Provide us feedback!',
|
||||
subtitle: 'Share with us what you like and/or dislike.',
|
||||
subtitle2: 'We will be very happy.',
|
||||
labelComments: 'What is your impression about this app?',
|
||||
labelSubmit: 'Send Feedback',
|
||||
})
|
||||
}
|
||||
|
||||
export default function Feedback(): ReactElement {
|
||||
const [sentryEnabled, setSentryEnabled] = useState(false)
|
||||
const classes = useStyles()
|
||||
|
||||
// Run this only on component mount to verify once that Sentry is reachable
|
||||
useEffect(() => {
|
||||
isSentryReachable().then(result => {
|
||||
setSentryEnabled(result)
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (sentryEnabled) {
|
||||
return (
|
||||
<Link onClick={showFeedbackForm} className={classes.link}>
|
||||
<SideBarItem iconStart={<MessageSquare className={classes.icon} />} label={<span>Send feedback</span>} />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
return <></>
|
||||
}
|
||||
@@ -12,12 +12,11 @@ import { Context as BeeContext } from '../providers/Bee'
|
||||
import { Context as SettingsContext } from '../providers/Settings'
|
||||
import DashboardLogo from '../assets/dashboard-logo.svg'
|
||||
import DesktopLogo from '../assets/desktop-logo.svg'
|
||||
import { config } from '../config'
|
||||
import { ROUTES } from '../routes'
|
||||
import Feedback from './Feedback'
|
||||
import SideBarItem from './SideBarItem'
|
||||
import SideBarStatus from './SideBarStatus'
|
||||
import { BeeModes } from '@ethersphere/bee-js'
|
||||
import { BEE_DOCS_HOST } from '../constants'
|
||||
|
||||
const drawerWidth = 300
|
||||
|
||||
@@ -67,7 +66,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
|
||||
export default function SideBar(): ReactElement {
|
||||
const classes = useStyles()
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { isDesktop } = useContext(SettingsContext)
|
||||
const { nodeInfo } = useContext(BeeContext)
|
||||
|
||||
const navBarItems = [
|
||||
@@ -100,7 +99,7 @@ export default function SideBar(): ReactElement {
|
||||
<Grid container direction="column" justifyContent="space-between" className={classes.root}>
|
||||
<Grid className={classes.logo}>
|
||||
<Link to={ROUTES.INFO}>
|
||||
<img alt="swarm" src={isBeeDesktop ? DesktopLogo : DashboardLogo} />
|
||||
<img alt="swarm" src={isDesktop ? DesktopLogo : DashboardLogo} />
|
||||
</Link>
|
||||
</Grid>
|
||||
<Grid>
|
||||
@@ -119,7 +118,7 @@ export default function SideBar(): ReactElement {
|
||||
</List>
|
||||
<Divider className={classes.divider} />
|
||||
<List>
|
||||
<MUILink href={config.BEE_DOCS_HOST} target="_blank" className={classes.link}>
|
||||
<MUILink href={BEE_DOCS_HOST} target="_blank" className={classes.link}>
|
||||
<SideBarItem
|
||||
iconStart={<DocsIcon className={classes.icon} />}
|
||||
iconEnd={<ExternalLinkIcon className={classes.icon} color="#595959" />}
|
||||
@@ -133,7 +132,6 @@ export default function SideBar(): ReactElement {
|
||||
<Link to={ROUTES.STATUS} className={classes.link}>
|
||||
<SideBarStatus path={ROUTES.STATUS} />
|
||||
</Link>
|
||||
<Feedback />
|
||||
</List>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -3,8 +3,8 @@ import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import type { ReactElement } from 'react'
|
||||
import Activity from 'remixicon-react/PulseLineIcon'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { config } from '../config'
|
||||
import { ROUTES } from '../routes'
|
||||
import { BEE_DISCORD_HOST, BEE_DOCS_HOST } from '../constants'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -37,11 +37,11 @@ export default function TroubleshootConnectionCard(): ReactElement {
|
||||
<Grid item className={classes.content}>
|
||||
<Typography align="center">
|
||||
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
|
||||
</MuiLink>{' '}
|
||||
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
|
||||
</MuiLink>
|
||||
.
|
||||
|
||||
@@ -1,33 +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 SENTRY_KEY: string | undefined
|
||||
public readonly SENTRY_ENVIRONMENT: string | undefined
|
||||
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.SENTRY_KEY = process.env.REACT_APP_SENTRY_KEY
|
||||
this.SENTRY_ENVIRONMENT = process.env.REACT_APP_SENTRY_ENVIRONMENT
|
||||
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
@@ -1,4 +1,14 @@
|
||||
export const META_FILE_NAME = '.swarmgatewaymeta.json'
|
||||
export const PREVIEW_FILE_NAME = '.swarmgatewaypreview.jpeg'
|
||||
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,8 +1,8 @@
|
||||
import { renderHook } from '@testing-library/react-hooks'
|
||||
import express from 'express'
|
||||
import cors from 'cors'
|
||||
import express from 'express'
|
||||
import type { Server } from 'http'
|
||||
import { useIsBeeDesktop } from './apiHooks'
|
||||
import { useBeeDesktop } from './apiHooks'
|
||||
|
||||
interface AddressInfo {
|
||||
address: string
|
||||
@@ -39,9 +39,9 @@ afterAll(async () => {
|
||||
await new Promise(resolve => serverCorrect.close(resolve))
|
||||
})
|
||||
|
||||
describe('useIsBeeDesktop', () => {
|
||||
describe('useBeeDesktop', () => {
|
||||
it('should not have error when connected to bee-desktop', async () => {
|
||||
const { result, waitFor } = renderHook(() => useIsBeeDesktop(true, { BEE_DESKTOP_URL: serverCorrectURL }))
|
||||
const { result, waitFor } = renderHook(() => useBeeDesktop(true, serverCorrectURL))
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false)
|
||||
|
||||
+20
-25
@@ -1,8 +1,8 @@
|
||||
import axios from 'axios'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { config } from '../config'
|
||||
import { getJson } from '../utils/net'
|
||||
import { getLatestBeeDesktopVersion } from '../utils/desktop'
|
||||
import { getJson } from '../utils/net'
|
||||
import { GITHUB_REPO_URL } from '../constants'
|
||||
|
||||
export interface LatestBeeReleaseHook {
|
||||
latestBeeRelease: LatestBeeRelease | null
|
||||
@@ -10,7 +10,7 @@ export interface LatestBeeReleaseHook {
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
export interface IsBeeDesktopHook {
|
||||
export interface BeeDesktopHook {
|
||||
error: Error | null
|
||||
isLoading: boolean
|
||||
beeDesktopVersion: string
|
||||
@@ -21,16 +21,7 @@ export interface NewDesktopVersionHook {
|
||||
newBeeDesktopVersion: string
|
||||
}
|
||||
|
||||
interface Config {
|
||||
BEE_DESKTOP_URL: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the dashboard is run within bee-desktop
|
||||
*
|
||||
* @returns isBeeDesktop true if this is run within bee-desktop
|
||||
*/
|
||||
export const useIsBeeDesktop = (isBeeDesktop = false, conf: Config = config): IsBeeDesktopHook => {
|
||||
export const useBeeDesktop = (isBeeDesktop = false, desktopUrl: string): BeeDesktopHook => {
|
||||
const [desktopAutoUpdateEnabled, setDesktopAutoUpdateEnabled] = useState<boolean>(true)
|
||||
const [beeDesktopVersion, setBeeDesktopVersion] = useState<string>('')
|
||||
const [isLoading, setLoading] = useState<boolean>(true)
|
||||
@@ -42,7 +33,7 @@ export const useIsBeeDesktop = (isBeeDesktop = false, conf: Config = config): Is
|
||||
setError(null)
|
||||
} else {
|
||||
axios
|
||||
.get(`${conf.BEE_DESKTOP_URL}/info`)
|
||||
.get(`${desktopUrl}/info`)
|
||||
.then(res => {
|
||||
setBeeDesktopVersion(res.data?.version)
|
||||
setDesktopAutoUpdateEnabled(res.data?.autoUpdateEnabled)
|
||||
@@ -55,13 +46,13 @@ export const useIsBeeDesktop = (isBeeDesktop = false, conf: Config = config): Is
|
||||
setLoading(false)
|
||||
})
|
||||
}
|
||||
}, [conf, isBeeDesktop])
|
||||
}, [desktopUrl, isBeeDesktop])
|
||||
|
||||
return { error, isLoading, beeDesktopVersion, desktopAutoUpdateEnabled }
|
||||
}
|
||||
|
||||
async function checkNewVersion(conf: Config): Promise<string> {
|
||||
const resJson = await (await fetch(`${conf.BEE_DESKTOP_URL}/info`)).json()
|
||||
async function checkNewVersion(desktopUrl: string): Promise<string> {
|
||||
const resJson = await (await fetch(`${desktopUrl}/info`)).json()
|
||||
const currentVersion = resJson.version
|
||||
const latestVersion = await getLatestBeeDesktopVersion()
|
||||
|
||||
@@ -72,20 +63,24 @@ async function checkNewVersion(conf: Config): Promise<string> {
|
||||
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>('')
|
||||
|
||||
useEffect(() => {
|
||||
if (!isBeeDesktop) {
|
||||
if (!isBeeDesktop || desktopAutoUpdateEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
checkNewVersion(conf).then(version => {
|
||||
checkNewVersion(desktopUrl).then(version => {
|
||||
if (version !== '') {
|
||||
setNewBeeDesktopVersion(version)
|
||||
}
|
||||
})
|
||||
}, [isBeeDesktop, conf])
|
||||
}, [isBeeDesktop, desktopUrl, desktopAutoUpdateEnabled])
|
||||
|
||||
return { newBeeDesktopVersion }
|
||||
}
|
||||
@@ -115,13 +110,13 @@ export interface GetBeeConfig {
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
export const useGetBeeConfig = (conf: Config = config): GetBeeConfig => {
|
||||
export const useGetBeeConfig = (desktopUrl: string): GetBeeConfig => {
|
||||
const [beeConfig, setBeeConfig] = useState<BeeConfig | null>(null)
|
||||
const [isLoading, setLoading] = useState<boolean>(true)
|
||||
const [error, setError] = useState<Error | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
getJson<BeeConfig>(`${conf.BEE_DESKTOP_URL}/config`)
|
||||
getJson<BeeConfig>(`${desktopUrl}/config`)
|
||||
.then(beeConf => {
|
||||
setBeeConfig(beeConf)
|
||||
setError(null)
|
||||
@@ -133,7 +128,7 @@ export const useGetBeeConfig = (conf: Config = config): GetBeeConfig => {
|
||||
.finally(() => {
|
||||
setLoading(false)
|
||||
})
|
||||
}, [conf])
|
||||
}, [desktopUrl])
|
||||
|
||||
return { config: beeConfig, isLoading, error }
|
||||
}
|
||||
@@ -145,7 +140,7 @@ export const useLatestBeeRelease = (): LatestBeeReleaseHook => {
|
||||
|
||||
useEffect(() => {
|
||||
axios
|
||||
.get(`${config.GITHUB_REPO_URL}/releases/latest`)
|
||||
.get(`${GITHUB_REPO_URL}/releases/latest`)
|
||||
.then(res => {
|
||||
setLatestBeeRelease(res.data)
|
||||
})
|
||||
|
||||
+6
-1
@@ -4,9 +4,14 @@ import './index.css'
|
||||
import App from './App'
|
||||
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(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<App isDesktop={desktopEnabled} desktopUrl={desktopUrl} beeApiUrl={beeApiUrl} beeDebugApiUrl={beeDebugApiUrl} />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root'),
|
||||
)
|
||||
|
||||
+18
-26
@@ -7,11 +7,8 @@ import ErrorBoundary from '../components/ErrorBoundary'
|
||||
import SideBar from '../components/SideBar'
|
||||
import { Context as BeeContext } from '../providers/Bee'
|
||||
import { Context as SettingsContext } from '../providers/Settings'
|
||||
import config from '../config'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import ItsBroken from './ItsBroken'
|
||||
import { useNewBeeDesktopVersion } from '../hooks/apiHooks'
|
||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../utils/desktop'
|
||||
import { useBeeDesktop, useNewBeeDesktopVersion } from '../hooks/apiHooks'
|
||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../constants'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -24,6 +21,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||
|
||||
interface Props {
|
||||
children?: ReactElement
|
||||
errorReporting?: (err: Error) => void
|
||||
}
|
||||
|
||||
const Dashboard = (props: Props): ReactElement => {
|
||||
@@ -31,13 +29,14 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
|
||||
const { isLoading, isLatestBeeVersion, latestBeeRelease, latestBeeVersionUrl, latestUserVersion } =
|
||||
useContext(BeeContext)
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isBeeDesktop)
|
||||
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||
const { desktopAutoUpdateEnabled } = useBeeDesktop(isDesktop, desktopUrl)
|
||||
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, desktopAutoUpdateEnabled)
|
||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
|
||||
|
||||
// New version of Bee client notification
|
||||
useEffect(() => {
|
||||
if (!isLoading && !isBeeDesktop && !isLatestBeeVersion && latestBeeRelease && latestUserVersion) {
|
||||
if (!isLoading && !isDesktop && !isLatestBeeVersion && latestBeeRelease && latestUserVersion) {
|
||||
enqueueSnackbar(`There is new Bee version ${latestBeeRelease?.name}!`, {
|
||||
variant: 'warning',
|
||||
preventDuplicate: true,
|
||||
@@ -68,7 +67,7 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
closeSnackbar,
|
||||
enqueueSnackbar,
|
||||
isLatestBeeVersion,
|
||||
isBeeDesktop,
|
||||
isDesktop,
|
||||
latestBeeRelease,
|
||||
latestBeeVersionUrl,
|
||||
isLoading,
|
||||
@@ -76,6 +75,11 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
])
|
||||
|
||||
useEffect(() => {
|
||||
// When autoupdate is enabled then we leave the version check for the built-in Electron update mechanism
|
||||
if (desktopAutoUpdateEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
if (newBeeDesktopVersion !== '') {
|
||||
enqueueSnackbar(`There is new Swarm Dashboard version ${newBeeDesktopVersion}!`, {
|
||||
variant: 'warning',
|
||||
@@ -103,7 +107,7 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
),
|
||||
})
|
||||
}
|
||||
}, [enqueueSnackbar, closeSnackbar, newBeeDesktopVersion])
|
||||
}, [enqueueSnackbar, closeSnackbar, newBeeDesktopVersion, desktopAutoUpdateEnabled])
|
||||
|
||||
const content = (
|
||||
<>
|
||||
@@ -117,25 +121,13 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
</>
|
||||
)
|
||||
|
||||
let errorBoundaryWithContent
|
||||
|
||||
if (config.SENTRY_KEY) {
|
||||
errorBoundaryWithContent = (
|
||||
<Sentry.ErrorBoundary
|
||||
showDialog
|
||||
fallback={({ error, componentStack, resetError }) => <ItsBroken message={error.message} />}
|
||||
>
|
||||
{content}
|
||||
</Sentry.ErrorBoundary>
|
||||
)
|
||||
} else {
|
||||
errorBoundaryWithContent = <ErrorBoundary>{content}</ErrorBoundary>
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex' }}>
|
||||
<SideBar />
|
||||
<Container className={classes.content}>{errorBoundaryWithContent}</Container>
|
||||
<Container className={classes.content}>
|
||||
{' '}
|
||||
<ErrorBoundary errorReporting={props.errorReporting}>{content}</ErrorBoundary>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Container } from '@material-ui/core'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import { ReactElement } from 'react'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
content: {
|
||||
backgroundColor: theme.palette.background.default,
|
||||
minHeight: '100vh',
|
||||
textAlign: 'center',
|
||||
},
|
||||
errorMsg: {
|
||||
marginTop: '30px',
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
interface Props {
|
||||
message: string
|
||||
}
|
||||
|
||||
// TODO: Provide some nicer design
|
||||
const ItsBroken = ({ message }: Props): ReactElement => {
|
||||
const classes = useStyles()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container className={classes.content}>
|
||||
<h1>Ups, there was a problem 😅</h1>
|
||||
<h3 className={classes.errorMsg}>Error: {message}</h3>
|
||||
</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ItsBroken
|
||||
@@ -20,7 +20,7 @@ import { Header } from '../Header'
|
||||
|
||||
export function AccountWallet(): ReactElement {
|
||||
const { nodeAddresses, nodeInfo, status } = useContext(BeeContext)
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { isDesktop } = useContext(SettingsContext)
|
||||
const { balance } = useContext(BalanceProvider)
|
||||
|
||||
const navigate = useNavigate()
|
||||
@@ -72,7 +72,7 @@ export function AccountWallet(): ReactElement {
|
||||
<SwarmButton onClick={onCheckTransactions} iconType={Link}>
|
||||
Check transactions on Blockscout
|
||||
</SwarmButton>
|
||||
{isBeeDesktop && (
|
||||
{isDesktop && (
|
||||
<SwarmButton onClick={onInvite} iconType={Gift}>
|
||||
Invite to Swarm...
|
||||
</SwarmButton>
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useNavigate, useParams } from 'react-router-dom'
|
||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||
import { Loading } from '../../components/Loading'
|
||||
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
|
||||
import config from '../../config'
|
||||
import { META_FILE_NAME, PREVIEW_FILE_NAME } from '../../constants'
|
||||
import { Context as BeeContext } from '../../providers/Bee'
|
||||
import { Context as SettingsContext } from '../../providers/Settings'
|
||||
@@ -78,7 +77,7 @@ export function Share(): ReactElement {
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (previewFile) {
|
||||
setPreview(`${config.BEE_API_HOST}/bzz/${reference}/${PREVIEW_FILE_NAME}`)
|
||||
setPreview(`${apiUrl}/bzz/${reference}/${PREVIEW_FILE_NAME}`)
|
||||
}
|
||||
|
||||
setMetadata(metadata)
|
||||
|
||||
@@ -23,7 +23,7 @@ const GIFT_WALLET_FUND_BZZ_AMOUNT = Token.fromDecimal('0.5', 16)
|
||||
|
||||
export default function Index(): ReactElement {
|
||||
const { giftWallets, addGiftWallet } = useContext(TopUpContext)
|
||||
const { provider } = useContext(SettingsContext)
|
||||
const { provider, desktopUrl } = useContext(SettingsContext)
|
||||
const { balance } = useContext(BalanceProvider)
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -50,7 +50,7 @@ export default function Index(): ReactElement {
|
||||
try {
|
||||
const wallet = Wallet.createRandom()
|
||||
addGiftWallet(wallet)
|
||||
await createGiftWallet(wallet.address)
|
||||
await createGiftWallet(desktopUrl, wallet.address)
|
||||
enqueueSnackbar('Succesfully funded gift wallet', { variant: 'success' })
|
||||
} catch (error) {
|
||||
console.error(error) // eslint-disable-line
|
||||
|
||||
+14
-15
@@ -1,21 +1,20 @@
|
||||
import { ReactElement, useContext } from 'react'
|
||||
import { Button } from '@material-ui/core'
|
||||
import Wallet from 'remixicon-react/Wallet3LineIcon'
|
||||
import { ReactElement, useContext } from 'react'
|
||||
import { useNavigate } from 'react-router'
|
||||
import ExchangeFunds from 'remixicon-react/ExchangeFundsLineIcon'
|
||||
import Upload from 'remixicon-react/UploadLineIcon'
|
||||
|
||||
import Wallet from 'remixicon-react/Wallet3LineIcon'
|
||||
import Card from '../../components/Card'
|
||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||
import Map from '../../components/Map'
|
||||
import { useBeeDesktop, useNewBeeDesktopVersion } from '../../hooks/apiHooks'
|
||||
import { Context as BeeContext } from '../../providers/Bee'
|
||||
import { Context as SettingsContext } from '../../providers/Settings'
|
||||
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
||||
import Card from '../../components/Card'
|
||||
import Map from '../../components/Map'
|
||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||
import { useNavigate } from 'react-router'
|
||||
import { ROUTES } from '../../routes'
|
||||
import { useIsBeeDesktop, useNewBeeDesktopVersion } from '../../hooks/apiHooks'
|
||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../utils/desktop'
|
||||
import NodeInfoCard from './NodeInfoCard'
|
||||
import { chainIdToName } from '../../utils/chain'
|
||||
import NodeInfoCard from './NodeInfoCard'
|
||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../constants'
|
||||
|
||||
export default function Status(): ReactElement {
|
||||
const {
|
||||
@@ -28,10 +27,10 @@ export default function Status(): ReactElement {
|
||||
chequebookBalance,
|
||||
chainId,
|
||||
} = useContext(BeeContext)
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||
const { balance, error } = useContext(BalanceProvider)
|
||||
const { beeDesktopVersion } = useIsBeeDesktop()
|
||||
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isBeeDesktop)
|
||||
const { beeDesktopVersion } = useBeeDesktop(isDesktop, desktopUrl)
|
||||
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, false)
|
||||
const navigate = useNavigate()
|
||||
|
||||
let balanceText = 'Loading...'
|
||||
@@ -115,7 +114,7 @@ export default function Status(): ReactElement {
|
||||
<ExpandableListItem label="Connected peers" value={topology?.connected ?? '-'} />
|
||||
<ExpandableListItem label="Population" value={topology?.population ?? '-'} />
|
||||
<div style={{ height: '16px' }} />
|
||||
{isBeeDesktop && (
|
||||
{isDesktop && (
|
||||
<ExpandableListItem
|
||||
label="Desktop version"
|
||||
value={
|
||||
@@ -143,7 +142,7 @@ export default function Status(): ReactElement {
|
||||
Bee
|
||||
</a>
|
||||
{` ${latestUserVersion ?? '-'} `}
|
||||
{latestUserVersion && !isBeeDesktop && (
|
||||
{latestUserVersion && !isDesktop && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function SettingsPage(): ReactElement {
|
||||
ensResolver,
|
||||
providerUrl,
|
||||
isLoading,
|
||||
isBeeDesktop,
|
||||
isDesktop,
|
||||
setAndPersistJsonRpcProvider,
|
||||
} = useContext(SettingsContext)
|
||||
const { refresh } = useContext(BeeContext)
|
||||
@@ -39,13 +39,13 @@ export default function SettingsPage(): ReactElement {
|
||||
label="Bee API"
|
||||
value={apiUrl}
|
||||
onConfirm={setApiUrl}
|
||||
locked={lockedApiSettings || isBeeDesktop}
|
||||
locked={lockedApiSettings || isDesktop}
|
||||
/>
|
||||
<ExpandableListItemInput
|
||||
label="Bee Debug API"
|
||||
value={apiDebugUrl}
|
||||
onConfirm={setDebugApiUrl}
|
||||
locked={lockedApiSettings || isBeeDesktop}
|
||||
locked={lockedApiSettings || isDesktop}
|
||||
/>
|
||||
<ExpandableListItemInput
|
||||
label="Blockchain RPC URL"
|
||||
@@ -65,7 +65,7 @@ export default function SettingsPage(): ReactElement {
|
||||
}}
|
||||
/>
|
||||
</ExpandableList>
|
||||
{isBeeDesktop && (
|
||||
{isDesktop && (
|
||||
<ExpandableList label="Desktop Settings" defaultOpen>
|
||||
<ExpandableListItemInput label="CORS" value={cors ?? '-'} locked />
|
||||
<ExpandableListItemInput label="Data DIR" value={dataDir ?? '-'} locked />
|
||||
|
||||
@@ -22,7 +22,7 @@ import { BeeModes } from '@ethersphere/bee-js'
|
||||
|
||||
export function GiftCardFund(): ReactElement {
|
||||
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
|
||||
const { isBeeDesktop, provider, providerUrl } = useContext(SettingsContext)
|
||||
const { isDesktop, desktopUrl, provider, providerUrl } = useContext(SettingsContext)
|
||||
const { balance } = useContext(BalanceProvider)
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -45,13 +45,13 @@ export function GiftCardFund(): ReactElement {
|
||||
return <Loading />
|
||||
}
|
||||
|
||||
const canUpgradeToLightNode = isBeeDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
|
||||
const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
|
||||
|
||||
async function restart() {
|
||||
try {
|
||||
await sleepMs(5_000)
|
||||
await upgradeToLightNode(providerUrl)
|
||||
await restartBeeNode()
|
||||
await upgradeToLightNode(desktopUrl, providerUrl)
|
||||
await restartBeeNode(desktopUrl)
|
||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
||||
navigate(ROUTES.RESTART_LIGHT)
|
||||
} catch (error) {
|
||||
|
||||
+17
-15
@@ -31,13 +31,21 @@ interface Props {
|
||||
header: string
|
||||
}
|
||||
|
||||
function isPositiveDecimal(value: string): boolean {
|
||||
try {
|
||||
return new BigNumber(value).isPositive()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
export function Swap({ header }: Props): ReactElement {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [hasSwapped, setSwapped] = useState(false)
|
||||
const [userInputSwap, setUserInputSwap] = useState<string | null>(null)
|
||||
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 { balance } = useContext(BalanceProvider)
|
||||
|
||||
@@ -46,8 +54,8 @@ export function Swap({ header }: Props): ReactElement {
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
getBzzPriceAsDai().then(setPrice).catch(console.error)
|
||||
}, [])
|
||||
getBzzPriceAsDai(desktopUrl).then(setPrice).catch(console.error)
|
||||
}, [desktopUrl])
|
||||
|
||||
if (!balance || !nodeAddresses) {
|
||||
return <Loading />
|
||||
@@ -58,14 +66,6 @@ export function Swap({ header }: Props): ReactElement {
|
||||
|
||||
let daiToSwap: DaiToken
|
||||
|
||||
function isPositiveDecimal(value: string): boolean {
|
||||
try {
|
||||
return new BigNumber(value).isPositive()
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if (userInputSwap && isPositiveDecimal(userInputSwap)) {
|
||||
daiToSwap = DaiToken.fromDecimal(userInputSwap, 18)
|
||||
} else {
|
||||
@@ -75,13 +75,14 @@ export function Swap({ header }: Props): ReactElement {
|
||||
const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
|
||||
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() {
|
||||
try {
|
||||
await sleepMs(5_000)
|
||||
await upgradeToLightNode(providerUrl)
|
||||
await restartBeeNode()
|
||||
await upgradeToLightNode(desktopUrl, providerUrl)
|
||||
await restartBeeNode(desktopUrl)
|
||||
|
||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
||||
navigate(ROUTES.RESTART_LIGHT)
|
||||
} catch (error) {
|
||||
@@ -96,8 +97,9 @@ export function Swap({ header }: Props): ReactElement {
|
||||
}
|
||||
setLoading(true)
|
||||
setSwapped(true)
|
||||
|
||||
try {
|
||||
await performSwap(daiToSwap.toString)
|
||||
await performSwap(desktopUrl, daiToSwap.toString)
|
||||
enqueueSnackbar('Successfully swapped', { variant: 'success' })
|
||||
|
||||
if (canUpgradeToLightNode) await restart()
|
||||
|
||||
@@ -39,7 +39,7 @@ const MINIMUM_XBZZ = '0.1'
|
||||
export default function TopUp(): ReactElement {
|
||||
const navigate = useNavigate()
|
||||
const styles = useStyles()
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||
const { nodeInfo, status } = useContext(BeeContext)
|
||||
const { balance } = useContext(BalanceProvider)
|
||||
const { providerUrl } = useContext(SettingsContext)
|
||||
@@ -47,7 +47,7 @@ export default function TopUp(): ReactElement {
|
||||
const { enqueueSnackbar } = useSnackbar()
|
||||
|
||||
const canUpgradeToLightNode =
|
||||
isBeeDesktop &&
|
||||
isDesktop &&
|
||||
nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT &&
|
||||
balance?.dai.toDecimal.gte(MINIMUM_XDAI) &&
|
||||
balance?.bzz.toDecimal.gte(MINIMUM_XBZZ)
|
||||
@@ -55,8 +55,8 @@ export default function TopUp(): ReactElement {
|
||||
async function restart() {
|
||||
setLoading(true)
|
||||
try {
|
||||
await upgradeToLightNode(providerUrl)
|
||||
await restartBeeNode()
|
||||
await upgradeToLightNode(desktopUrl, providerUrl)
|
||||
await restartBeeNode(desktopUrl)
|
||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
||||
navigate(ROUTES.RESTART_LIGHT)
|
||||
} catch (error) {
|
||||
|
||||
+68
-47
@@ -1,15 +1,15 @@
|
||||
import { Bee, BeeDebug } from '@ethersphere/bee-js'
|
||||
import { providers } from 'ethers'
|
||||
import { createContext, ReactNode, ReactElement, useEffect, useState } from 'react'
|
||||
import { config as appConfig } from '../config'
|
||||
import { useGetBeeConfig } from '../hooks/apiHooks'
|
||||
import { restartBeeNode, setJsonRpcInDesktop } from '../utils/desktop'
|
||||
import { DEFAULT_BEE_API_HOST, DEFAULT_BEE_DEBUG_API_HOST, DEFAULT_RPC_URL } from '../constants'
|
||||
|
||||
const LocalStorageKeys = {
|
||||
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 {
|
||||
apiUrl: string
|
||||
@@ -18,6 +18,8 @@ interface ContextInterface {
|
||||
beeDebugApi: BeeDebug | null
|
||||
lockedApiSettings: boolean
|
||||
desktopApiKey: string
|
||||
isDesktop: boolean
|
||||
desktopUrl: string
|
||||
providerUrl: string
|
||||
provider: providers.JsonRpcProvider
|
||||
cors: string | null
|
||||
@@ -26,27 +28,27 @@ interface ContextInterface {
|
||||
setApiUrl: (url: string) => void
|
||||
setDebugApiUrl: (url: string) => void
|
||||
setAndPersistJsonRpcProvider: (url: string) => Promise<void>
|
||||
isBeeDesktop: boolean
|
||||
isLoading: boolean
|
||||
error: Error | null
|
||||
}
|
||||
|
||||
const initialValues: ContextInterface = {
|
||||
apiUrl: appConfig.BEE_API_HOST,
|
||||
apiDebugUrl: appConfig.BEE_DEBUG_API_HOST,
|
||||
beeApi: null,
|
||||
beeDebugApi: null,
|
||||
apiUrl: DEFAULT_BEE_API_HOST,
|
||||
apiDebugUrl: DEFAULT_BEE_DEBUG_API_HOST,
|
||||
setApiUrl: () => {}, // eslint-disable-line
|
||||
setDebugApiUrl: () => {}, // eslint-disable-line
|
||||
lockedApiSettings: false,
|
||||
isDesktop: false,
|
||||
desktopApiKey: '',
|
||||
desktopUrl: window.location.origin,
|
||||
setAndPersistJsonRpcProvider: async () => {}, // eslint-disable-line
|
||||
providerUrl,
|
||||
provider: new providers.JsonRpcProvider(providerUrl),
|
||||
cors: null,
|
||||
dataDir: null,
|
||||
ensResolver: null,
|
||||
isBeeDesktop: false,
|
||||
isLoading: true,
|
||||
error: null,
|
||||
}
|
||||
@@ -54,21 +56,22 @@ const initialValues: ContextInterface = {
|
||||
export const Context = createContext<ContextInterface>(initialValues)
|
||||
export const Consumer = Context.Consumer
|
||||
|
||||
interface Props {
|
||||
children: ReactNode
|
||||
interface InitialSettings {
|
||||
beeApiUrl?: string
|
||||
beeDebugApiUrl?: string
|
||||
lockedApiSettings?: boolean
|
||||
isBeeDesktop?: boolean
|
||||
isDesktop?: boolean
|
||||
desktopUrl?: string
|
||||
}
|
||||
|
||||
export function Provider({
|
||||
children,
|
||||
beeApiUrl,
|
||||
beeDebugApiUrl,
|
||||
lockedApiSettings: extLockedApiSettings,
|
||||
isBeeDesktop: extIsBeeDesktop,
|
||||
}: Props): ReactElement {
|
||||
interface Props extends InitialSettings {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function Provider({ children, ...propsSettings }: Props): ReactElement {
|
||||
const desktopUrl = propsSettings.desktopUrl ?? initialValues.desktopUrl
|
||||
const isDesktop = Boolean(propsSettings.isDesktop)
|
||||
|
||||
const [apiUrl, setApiUrl] = useState<string>(initialValues.apiUrl)
|
||||
const [apiDebugUrl, setDebugApiUrl] = useState<string>(initialValues.apiDebugUrl)
|
||||
const [beeApi, setBeeApi] = useState<Bee | null>(null)
|
||||
@@ -76,35 +79,17 @@ export function Provider({
|
||||
const [desktopApiKey, setDesktopApiKey] = useState<string>(initialValues.desktopApiKey)
|
||||
const [providerUrl, setProviderUrl] = useState(initialValues.providerUrl)
|
||||
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)
|
||||
|
||||
async function setAndPersistJsonRpcProvider(providerUrl: string) {
|
||||
try {
|
||||
localStorage.setItem(LocalStorageKeys.providerUrl, providerUrl)
|
||||
setProviderUrl(providerUrl)
|
||||
setProvider(new providers.JsonRpcProvider(providerUrl))
|
||||
|
||||
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)
|
||||
const url = makeHttpUrl(
|
||||
config?.['api-addr'] ?? sessionStorage.getItem('api_host') ?? propsSettings.beeApiUrl ?? apiUrl,
|
||||
)
|
||||
const debugUrl = makeHttpUrl(
|
||||
config?.['debug-api-addr'] ??
|
||||
sessionStorage.getItem('debug_api_host') ??
|
||||
propsSettings.beeDebugApiUrl ??
|
||||
apiDebugUrl,
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search)
|
||||
@@ -144,15 +129,21 @@ export function Provider({
|
||||
beeDebugApi,
|
||||
setApiUrl,
|
||||
setDebugApiUrl,
|
||||
lockedApiSettings: Boolean(extLockedApiSettings),
|
||||
lockedApiSettings: Boolean(propsSettings.lockedApiSettings),
|
||||
desktopApiKey,
|
||||
isDesktop,
|
||||
desktopUrl,
|
||||
provider,
|
||||
providerUrl,
|
||||
cors: config?.['cors-allowed-origins'] ?? null,
|
||||
dataDir: config?.['data-dir'] ?? null,
|
||||
ensResolver: config?.['resolver-options'] ?? null,
|
||||
setAndPersistJsonRpcProvider,
|
||||
isBeeDesktop,
|
||||
setAndPersistJsonRpcProvider: setAndPersistJsonRpcProviderClosure(
|
||||
isDesktop,
|
||||
desktopUrl,
|
||||
setProviderUrl,
|
||||
setProvider,
|
||||
),
|
||||
isLoading,
|
||||
error,
|
||||
}}
|
||||
@@ -161,3 +152,33 @@ export function 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
@@ -61,7 +61,7 @@ export const ACCOUNT_TABS = [
|
||||
]
|
||||
|
||||
const BaseRouter = (): ReactElement => {
|
||||
const { isBeeDesktop } = useContext(SettingsContext)
|
||||
const { isDesktop } = useContext(SettingsContext)
|
||||
|
||||
return (
|
||||
<Routes>
|
||||
@@ -88,7 +88,7 @@ const BaseRouter = (): ReactElement => {
|
||||
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
|
||||
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
+17
-51
@@ -1,81 +1,47 @@
|
||||
import axios from 'axios'
|
||||
import { DaiToken } from '../models/DaiToken'
|
||||
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 {
|
||||
status: 0 | 1 | 2
|
||||
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`)
|
||||
export async function getBzzPriceAsDai(desktopUrl: string): Promise<Token> {
|
||||
const response = await axios.get(`${desktopUrl}/price`)
|
||||
|
||||
return DaiToken.fromDecimal(response.data, 18)
|
||||
}
|
||||
|
||||
export async function upgradeToLightNode(rpcProvider: string): Promise<void> {
|
||||
await updateDesktopConfiguration({
|
||||
export async function upgradeToLightNode(desktopUrl: string, rpcProvider: string): Promise<void> {
|
||||
await updateDesktopConfiguration(desktopUrl, {
|
||||
'chain-enable': true,
|
||||
'swap-enable': true,
|
||||
'swap-endpoint': rpcProvider,
|
||||
})
|
||||
}
|
||||
|
||||
export async function setJsonRpcInDesktop(value: string): Promise<void> {
|
||||
await updateDesktopConfiguration({
|
||||
export async function setJsonRpcInDesktop(desktopUrl: string, value: string): Promise<void> {
|
||||
await updateDesktopConfiguration(desktopUrl, {
|
||||
'swap-endpoint': value,
|
||||
})
|
||||
}
|
||||
|
||||
async function updateDesktopConfiguration(values: Record<string, unknown>): Promise<void> {
|
||||
await postJson(`${getDesktopHost()}/config`, values)
|
||||
async function updateDesktopConfiguration(desktopUrl: string, values: Record<string, unknown>): Promise<void> {
|
||||
await postJson(`${desktopUrl}/config`, values)
|
||||
}
|
||||
|
||||
export async function restartBeeNode(): Promise<void> {
|
||||
await postJson(`${getDesktopHost()}/restart`)
|
||||
export async function restartBeeNode(desktopUrl: string): Promise<void> {
|
||||
await postJson(`${desktopUrl}/restart`)
|
||||
}
|
||||
|
||||
export async function createGiftWallet(address: string): Promise<void> {
|
||||
await postJson(`${getDesktopHost()}/gift-wallet/${address}`)
|
||||
export async function createGiftWallet(desktopUrl: string, address: string): Promise<void> {
|
||||
await postJson(`${desktopUrl}/gift-wallet/${address}`)
|
||||
}
|
||||
|
||||
export async function performSwap(daiAmount: string): Promise<void> {
|
||||
await postJson(`${getDesktopHost()}/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 performSwap(desktopUrl: string, daiAmount: string): Promise<void> {
|
||||
await postJson(`${desktopUrl}/swap`, { dai: daiAmount })
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
function getDesktopHost(): string {
|
||||
if (process.env.REACT_APP_BEE_DESKTOP_URL) {
|
||||
return process.env.REACT_APP_BEE_DESKTOP_URL
|
||||
}
|
||||
|
||||
return `http://${window.location.host}`
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { config } from '../config'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import packageJson from '../../package.json'
|
||||
import { BrowserTracing } from '@sentry/tracing'
|
||||
import { getBeeDesktopLogs, getBeeLogs } from './desktop'
|
||||
|
||||
export async function initSentry(): Promise<void> {
|
||||
let tunnelAvailable
|
||||
|
||||
try {
|
||||
const result = await fetch(`${config.BEE_DESKTOP_URL}/sentry`, { method: 'OPTIONS' })
|
||||
|
||||
if (result.status === 204) {
|
||||
tunnelAvailable = true
|
||||
}
|
||||
} catch (e) {
|
||||
// There was an error, so tunnel is not available
|
||||
tunnelAvailable = false
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
dsn: config.SENTRY_KEY,
|
||||
release: packageJson.version,
|
||||
environment: config.SENTRY_ENVIRONMENT,
|
||||
tunnel: tunnelAvailable ? `${config.BEE_DESKTOP_URL}/sentry` : undefined,
|
||||
integrations: [new BrowserTracing({ tracingOrigins: [config.BEE_DESKTOP_URL] })],
|
||||
tracesSampleRate: 0.4,
|
||||
beforeSend: async (event, hint) => {
|
||||
hint.attachments = []
|
||||
|
||||
try {
|
||||
// This will fail if we are not running in Bee Desktop, but that is alright
|
||||
hint.attachments.push({ filename: 'bee-desktop.log', data: await getBeeDesktopLogs() })
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
// This will fail if we are not running in Bee Desktop, but that is alright
|
||||
hint.attachments.push({ filename: 'bee.log', data: await getBeeLogs() })
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (e) {}
|
||||
|
||||
return event
|
||||
},
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user