Skip to content
Permalink
Browse files

feat: use notistack (#147)

* fix: don't clear errors on terminal load

* feat: use notistack

* fix: only show custom flag warning once

* chore: convert FlagPreview change warning to notistack

* fix: pass plugin name to clear errors

* chore: adds redux tests
  • Loading branch information...
ryanio authored and marcgarreau committed Sep 10, 2019
1 parent 1222a51 commit d0f5c243abf8e492a15c20ffddc1f639ff8d2f79
@@ -33,6 +33,7 @@
"ethereum-react-components": "^1.13.11",
"lodash": "^4.17.13",
"moment": "^2.24.0",
"notistack": "^0.9.0",
"numeral": "^2.0.6",
"prop-types": "^15.6.2",
"react": "^16.4.1",
@@ -1,6 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { MuiThemeProvider } from '@material-ui/core/styles'
import { SnackbarProvider } from 'notistack'
import CssBaseline from '@material-ui/core/CssBaseline'
import { darkTheme, lightTheme } from '../theme'
import HelpFab from './shared/HelpFab'
@@ -18,11 +19,20 @@ export default class NewApp extends Component {
const { themeMode } = this.props
return (
<MuiThemeProvider theme={themeMode === 'light' ? lightTheme : darkTheme}>
<CssBaseline />
<HelpFab />
<ErrorBoundary>
<Plugins />
</ErrorBoundary>
<SnackbarProvider
maxSnack={10}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right'
}}
autoHideDuration={null}
>
<CssBaseline />
<HelpFab />
<ErrorBoundary>
<Plugins />
</ErrorBoundary>
</SnackbarProvider>
</MuiThemeProvider>
)
}
@@ -1,12 +1,16 @@
import React, { Component } from 'react'
import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import { withSnackbar } from 'notistack'
import PropTypes from 'prop-types'
import TextField from '@material-ui/core/TextField'
import Button from '@material-ui/core/Button'
import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import Checkbox from '@material-ui/core/Checkbox'
import { setCustomFlags } from '../../../../store/plugin/actions'
import Notification from '../../../shared/Notification'
import {
dismissFlagWarning,
setCustomFlags
} from '../../../../store/plugin/actions'

class FlagPreview extends Component {
static propTypes = {
@@ -15,10 +19,41 @@ class FlagPreview extends Component {
flags: PropTypes.array,
isEditingFlags: PropTypes.bool,
toggleEditGeneratedFlags: PropTypes.func,
dispatch: PropTypes.func
dispatch: PropTypes.func,
showWarning: PropTypes.bool,
enqueueSnackbar: PropTypes.func,
closeSnackbar: PropTypes.func
}

state = { showWarning: true }
componentDidUpdate = () => {
const {
isEditingFlags,
showWarning,
enqueueSnackbar,
closeSnackbar
} = this.props
if (isEditingFlags && showWarning) {
enqueueSnackbar("Use caution! Don't take flags from strangers.", {
variant: 'warning',
onClose: () => {
this.dismissFlagWarning()
},
action: key => (
<Fragment>
<Button
style={{ color: '#000' }}
onClick={() => {
closeSnackbar(key)
this.dismissFlagWarning()
}}
>
{'Dismiss'}
</Button>
</Fragment>
)
})
}
}

toggleEdit = event => {
const { toggleEditGeneratedFlags } = this.props
@@ -32,9 +67,13 @@ class FlagPreview extends Component {
dispatch(setCustomFlags(pluginName, flags))
}

dismissFlagWarning = () => {
const { dispatch } = this.props
dispatch(dismissFlagWarning())
}

render() {
const { flags, isEditingFlags, isPluginRunning } = this.props
const { showWarning } = this.state

return (
<React.Fragment>
@@ -61,20 +100,15 @@ class FlagPreview extends Component {
label="Use custom flags"
/>
</FormGroup>
{isEditingFlags && showWarning && (
<Notification
type="warning"
message="Use caution! Don't take flags from strangers."
onDismiss={() => this.setState({ showWarning: false })}
/>
)}
</React.Fragment>
)
}
}

function mapStateToProps() {
return {}
function mapStateToProps(state) {
return {
showWarning: state.plugin.showCustomFlagWarning
}
}

export default connect(mapStateToProps)(FlagPreview)
export default connect(mapStateToProps)(withSnackbar(FlagPreview))
@@ -2,9 +2,11 @@ import React, { Component, Fragment } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { withSnackbar } from 'notistack'
import AppBar from '@material-ui/core/AppBar'
import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab'
import Button from '@material-ui/core/Button'
import Badge from '@material-ui/core/Badge'
import Typography from '@material-ui/core/Typography'
import VersionList from './VersionList'
@@ -16,10 +18,10 @@ import PluginView from '../PluginView'
import {
clearError,
selectTab,
setAppBadges
setAppBadges,
getPluginErrors
} from '../../../store/plugin/actions'

import Notification from '../../shared/Notification'
import ErrorBoundary from '../../GenericErrorBoundary'
import { getPluginSettingsConfig } from '../../../lib/utils'

@@ -59,12 +61,18 @@ class PluginConfig extends Component {
handlePluginConfigChanged: PropTypes.func,
pluginErrors: PropTypes.array,
appBadges: PropTypes.object,
selectedTab: PropTypes.number
selectedTab: PropTypes.number,
enqueueSnackbar: PropTypes.func,
closeSnackbar: PropTypes.func
}

constructor(props) {
super(props)
this.state = {
displayedErrors: {}
}
this.getAppBadges()
this.enqueueErrors()
}

componentDidUpdate(prevProps) {
@@ -80,6 +88,8 @@ class PluginConfig extends Component {
this.handleTabChange(null, 0)
this.getAppBadges()
}

this.enqueueErrors()
}

getAppBadges = () => {
@@ -93,10 +103,6 @@ class PluginConfig extends Component {
handleTabChange = (event, tab) => {
const { dispatch } = this.props
dispatch(selectTab(tab))
// Clear errors if going to Terminal tab
if (tab === 3) {
this.clearPluginErrors()
}
}

handlePluginConfigChanged = (key, value) => {
@@ -106,41 +112,54 @@ class PluginConfig extends Component {

dismissError = index => {
const { dispatch, plugin } = this.props
dispatch(clearError(plugin.name, index))
this.clearPluginErrors()
}

clearPluginErrors = () => {
// Clear errors in nano
const { plugin, pluginErrors } = this.props
if (pluginErrors.length > 0) {
plugin.emit('clearPluginErrors')
}
dispatch(clearError(plugin, index))
}

appBadgesCount() {
const { appBadges } = this.props
return Object.values(appBadges).reduce((a, b) => a + b, 0)
}

renderErrors() {
const { pluginErrors } = this.props
const renderErrors = []
pluginErrors.forEach((error, index) => {
const renderError = (
<Notification
key={index}
type="error"
message={error}
onDismiss={() => {
this.dismissError(index)
}}
/>
)
renderErrors.push(renderError)
})
enqueueErrors() {
const { displayedErrors } = this.state
const {
pluginErrors,
plugin,
enqueueSnackbar,
dispatch,
closeSnackbar
} = this.props

return renderErrors
const onClose = (thisPlugin, key) => {
dispatch(clearError(thisPlugin, key))
delete displayedErrors[key]
}

dispatch(getPluginErrors(plugin))
pluginErrors.forEach(error => {
if (displayedErrors[error.key]) return
enqueueSnackbar(error.message, {
key: error.key,
variant: 'error',
onClose: (event, reason, key) => {
onClose(plugin, key)
},
action: key => (
<Fragment>
<Button
style={{ color: '#000' }}
onClick={() => {
closeSnackbar(key)
onClose(plugin, key)
}}
>
{'Dismiss'}
</Button>
</Fragment>
)
})
displayedErrors[error.key] = true
})
}

render() {
@@ -169,7 +188,6 @@ class PluginConfig extends Component {
{isActivePlugin ? pluginStatus : 'STOPPED'}
</StyledState>
</Typography>
{this.renderErrors()}
<StyledAppBar position="static">
<Tabs
value={selectedTab}
@@ -248,7 +266,7 @@ function mapStateToProps(state) {
}
}

export default connect(mapStateToProps)(PluginConfig)
export default connect(mapStateToProps)(withSnackbar(PluginConfig))

const StyledAppBar = styled(AppBar)`
margin: 20px 0;
@@ -85,7 +85,7 @@ class Notification extends Component {
return (
<Snackbar
anchorOrigin={{
vertical: 'bottom',
vertical: 'top',
horizontal: 'right'
}}
open
@@ -73,6 +73,10 @@ export const initPlugin = plugin => {
}
}

export const dismissFlagWarning = () => {
return { type: 'PLUGIN:DISMISS_FLAG_WARNING' }
}

export const newBlock = (pluginName, blockNumber, timestamp) => {
return {
type: 'PLUGIN:UPDATE_NEW_BLOCK',
@@ -126,16 +130,35 @@ export const updatePeerCountError = (pluginName, message) => {
}

export const addPluginError = (pluginName, error) => {
return { type: 'PLUGIN:ERROR:ADD', error, payload: { pluginName } }
return (dispatch, getState) => {
const state = getState()
if (state.plugin[pluginName].errors.find(e => e.key === error.key)) {
return
}
dispatch({ type: 'PLUGIN:ERROR:ADD', error, payload: { pluginName } })
}
}

export const getPluginErrors = plugin => {
return dispatch => {
plugin.getErrors().forEach(error => {
dispatch(addPluginError(plugin.name, error))
})
}
}

export const clearError = (pluginName, index) => {
export const clearError = (plugin, key) => {
plugin.plugin.dismissError(key)
return {
type: 'PLUGIN:CLEAR_ERROR',
payload: { pluginName, index }
type: 'PLUGIN:ERROR:CLEAR',
payload: { pluginName: plugin.name, key }
}
}

export const clearPluginErrors = pluginName => {
return { type: 'PLUGIN:ERROR:CLEAR_ALL', payload: { pluginName } }
}

export const selectPlugin = (pluginName, tab) => {
return { type: 'PLUGIN:SELECT', payload: { pluginName, tab } }
}

0 comments on commit d0f5c24

Please sign in to comment.
You can’t perform that action at this time.