+78
-30
@@ -3,6 +3,8 @@ 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 { BrowserTracing } from '@sentry/tracing'
|
||||
import './App.css'
|
||||
import Dashboard from './layout/Dashboard'
|
||||
import { Provider as BeeProvider } from './providers/Bee'
|
||||
@@ -14,6 +16,10 @@ import { Provider as StampsProvider } from './providers/Stamps'
|
||||
import { Provider as TopUpProvider } from './providers/TopUp'
|
||||
import BaseRouter from './routes'
|
||||
import { theme } from './theme'
|
||||
import { config } from './config'
|
||||
import { getBeeDesktopLogs, getBeeLogs } from './utils/desktop'
|
||||
import packageJson from '../package.json'
|
||||
import ItsBroken from './layout/ItsBroken'
|
||||
|
||||
interface Props {
|
||||
beeApiUrl?: string
|
||||
@@ -21,35 +27,77 @@ interface Props {
|
||||
lockedApiSettings?: boolean
|
||||
}
|
||||
|
||||
const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings }: Props): ReactElement => (
|
||||
<div className="App">
|
||||
<ThemeProvider theme={theme}>
|
||||
<SettingsProvider beeApiUrl={beeApiUrl} beeDebugApiUrl={beeDebugApiUrl} lockedApiSettings={lockedApiSettings}>
|
||||
<BeeProvider>
|
||||
<StampsProvider>
|
||||
<FileProvider>
|
||||
<FeedsProvider>
|
||||
<PlatformProvider>
|
||||
<TopUpProvider>
|
||||
<SnackbarProvider>
|
||||
<Router>
|
||||
<>
|
||||
<CssBaseline />
|
||||
<Dashboard>
|
||||
<BaseRouter />
|
||||
</Dashboard>
|
||||
</>
|
||||
</Router>
|
||||
</SnackbarProvider>
|
||||
</TopUpProvider>
|
||||
</PlatformProvider>
|
||||
</FeedsProvider>
|
||||
</FileProvider>
|
||||
</StampsProvider>
|
||||
</BeeProvider>
|
||||
</SettingsProvider>
|
||||
</ThemeProvider>
|
||||
</div>
|
||||
)
|
||||
if (config.SENTRY_KEY) {
|
||||
Sentry.init({
|
||||
dsn: config.SENTRY_KEY,
|
||||
release: packageJson.version,
|
||||
integrations: [new BrowserTracing({ tracingOrigins: ['localhost'] })],
|
||||
tracesSampleRate: 1.0,
|
||||
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
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const App = ({ beeApiUrl, beeDebugApiUrl, lockedApiSettings }: Props): ReactElement => {
|
||||
const mainApp = (
|
||||
<div className="App">
|
||||
<ThemeProvider theme={theme}>
|
||||
<SettingsProvider beeApiUrl={beeApiUrl} beeDebugApiUrl={beeDebugApiUrl} lockedApiSettings={lockedApiSettings}>
|
||||
<BeeProvider>
|
||||
<StampsProvider>
|
||||
<FileProvider>
|
||||
<FeedsProvider>
|
||||
<PlatformProvider>
|
||||
<TopUpProvider>
|
||||
<SnackbarProvider>
|
||||
<Router>
|
||||
<>
|
||||
<CssBaseline />
|
||||
<Dashboard>
|
||||
<BaseRouter />
|
||||
</Dashboard>
|
||||
</>
|
||||
</Router>
|
||||
</SnackbarProvider>
|
||||
</TopUpProvider>
|
||||
</PlatformProvider>
|
||||
</FeedsProvider>
|
||||
</FileProvider>
|
||||
</StampsProvider>
|
||||
</BeeProvider>
|
||||
</SettingsProvider>
|
||||
</ThemeProvider>
|
||||
</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
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Component, ErrorInfo, ReactElement } from 'react'
|
||||
import ItsBroken from '../layout/ItsBroken'
|
||||
|
||||
interface Props {
|
||||
children: ReactElement
|
||||
@@ -26,8 +27,7 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
|
||||
render(): ReactElement {
|
||||
if (this.state.error) {
|
||||
// You can render any custom fallback UI
|
||||
return <h1>Something went wrong. Error: {this.state.error.message}</h1>
|
||||
return <ItsBroken message={this.state.error.message} />
|
||||
}
|
||||
|
||||
return this.props.children
|
||||
|
||||
+9
-13
@@ -1,7 +1,3 @@
|
||||
function getProcessEnv(key: string): string | undefined | false {
|
||||
return typeof process === 'object' && process.env[key]
|
||||
}
|
||||
|
||||
class Config {
|
||||
public readonly BEE_API_HOST: string
|
||||
public readonly BEE_DEBUG_API_HOST: string
|
||||
@@ -10,19 +6,19 @@ class Config {
|
||||
public readonly BEE_DISCORD_HOST: string
|
||||
public readonly GITHUB_REPO_URL: string
|
||||
public readonly BEE_DESKTOP_URL: string
|
||||
public readonly SENTRY_KEY: string | undefined
|
||||
|
||||
constructor() {
|
||||
this.BEE_API_HOST =
|
||||
sessionStorage.getItem('api_host') || getProcessEnv('REACT_APP_BEE_HOST') || 'http://localhost:1633'
|
||||
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.BEE_DEBUG_API_HOST =
|
||||
sessionStorage.getItem('debug_api_host') || getProcessEnv('REACT_APP_BEE_DEBUG_HOST') || 'http://localhost:1635'
|
||||
sessionStorage.getItem('debug_api_host') ?? process.env.REACT_APP_BEE_DEBUG_HOST ?? 'http://localhost:1635'
|
||||
this.BLOCKCHAIN_EXPLORER_URL =
|
||||
getProcessEnv('REACT_APP_BLOCKCHAIN_EXPLORER_URL') || 'https://blockscout.com/xdai/mainnet'
|
||||
this.BEE_DOCS_HOST = getProcessEnv('REACT_APP_BEE_DOCS_HOST') || 'https://docs.ethswarm.org/docs/'
|
||||
this.BEE_DISCORD_HOST = getProcessEnv('REACT_APP_BEE_DISCORD_HOST') || 'https://discord.gg/eKr9XPv7'
|
||||
this.GITHUB_REPO_URL =
|
||||
getProcessEnv('REACT_APP_BEE_GITHUB_REPO_URL') || 'https://api.github.com/repos/ethersphere/bee'
|
||||
this.BEE_DESKTOP_URL = getProcessEnv('REACT_APP_BEE_DESKTOP_URL') || window.location.origin
|
||||
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_URL = process.env.REACT_APP_BEE_DESKTOP_URL ?? window.location.origin
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
-14
@@ -1,9 +1,12 @@
|
||||
import { CircularProgress, Container } from '@material-ui/core'
|
||||
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||
import { ReactElement, useContext } from 'react'
|
||||
import React, { ReactElement, useContext } from 'react'
|
||||
import ErrorBoundary from '../components/ErrorBoundary'
|
||||
import SideBar from '../components/SideBar'
|
||||
import { Context } from '../providers/Bee'
|
||||
import config from '../config'
|
||||
import * as Sentry from '@sentry/react'
|
||||
import ItsBroken from './ItsBroken'
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
@@ -22,23 +25,37 @@ const Dashboard = (props: Props): ReactElement => {
|
||||
const classes = useStyles()
|
||||
|
||||
const { isLoading } = useContext(Context)
|
||||
const content = (
|
||||
<>
|
||||
{isLoading ? (
|
||||
<div style={{ textAlign: 'center', width: '100%' }}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
) : (
|
||||
props.children
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
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}>
|
||||
<ErrorBoundary>
|
||||
<>
|
||||
{isLoading ? (
|
||||
<div style={{ textAlign: 'center', width: '100%' }}>
|
||||
<CircularProgress />
|
||||
</div>
|
||||
) : (
|
||||
props.children
|
||||
)}
|
||||
</>
|
||||
</ErrorBoundary>
|
||||
</Container>
|
||||
<Container className={classes.content}>{errorBoundaryWithContent}</Container>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
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
|
||||
+23
-7
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios'
|
||||
import { getJson, postJson } from './net'
|
||||
import { getJson, postJson, sendRequest } from './net'
|
||||
|
||||
interface DesktopStatus {
|
||||
status: 0 | 1 | 2
|
||||
@@ -9,7 +9,7 @@ interface DesktopStatus {
|
||||
}
|
||||
|
||||
export async function getDesktopStatus(): Promise<DesktopStatus> {
|
||||
const response = await getJson(`http://${getDesktopHost()}/status`)
|
||||
const response = await getJson(`${getDesktopHost()}/status`)
|
||||
|
||||
return response as DesktopStatus
|
||||
}
|
||||
@@ -33,21 +33,37 @@ export async function setJsonRpcInDesktop(value: string): Promise<void> {
|
||||
}
|
||||
|
||||
async function updateDesktopConfiguration(values: Record<string, unknown>): Promise<void> {
|
||||
await postJson(`http://${getDesktopHost()}/config`, values)
|
||||
await postJson(`${getDesktopHost()}/config`, values)
|
||||
}
|
||||
|
||||
export async function restartBeeNode(): Promise<void> {
|
||||
await postJson(`http://${getDesktopHost()}/restart`)
|
||||
await postJson(`${getDesktopHost()}/restart`)
|
||||
}
|
||||
|
||||
export async function createGiftWallet(address: string): Promise<void> {
|
||||
await postJson(`http://${getDesktopHost()}/gift-wallet/${address}`)
|
||||
await postJson(`${getDesktopHost()}/gift-wallet/${address}`)
|
||||
}
|
||||
|
||||
export async function performSwap(daiAmount: string): Promise<void> {
|
||||
await postJson(`http://${getDesktopHost()}/swap`, { dai: daiAmount })
|
||||
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
|
||||
}
|
||||
|
||||
function getDesktopHost(): string {
|
||||
return window.location.host
|
||||
if (process.env.REACT_APP_BEE_DESKTOP_URL) {
|
||||
return process.env.REACT_APP_BEE_DESKTOP_URL
|
||||
}
|
||||
|
||||
return `http://${window.location.host}`
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ export function postJson(url: string, data?: Record<string, any>): Promise<Recor
|
||||
return sendRequest(url, 'POST', data)
|
||||
}
|
||||
|
||||
async function sendRequest(
|
||||
export async function sendRequest(
|
||||
url: string,
|
||||
method: 'GET' | 'POST',
|
||||
data?: Record<string, unknown>,
|
||||
|
||||
Reference in New Issue
Block a user