Skip to content

Commit

Permalink
Add some help in for failed network connections
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas101 committed Jan 31, 2019
1 parent ff20586 commit 7428438
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 2 deletions.
1 change: 1 addition & 0 deletions scripts/generateFA.js
Expand Up @@ -40,6 +40,7 @@ const MAPPING = [
['farDesktop', 'fasDesktop'],
['farPenSquare', 'fasPenSquare'],
['farClone', 'farClone'],
['farFrown', 'farFrown'],

['falWindowClose', 'farWindowClose'],
['falWindowMaximize', 'farWindowMaximize'],
Expand Down
Expand Up @@ -28,6 +28,7 @@ import classNames from 'classnames'
import ServiceInvalidAuthCover from './ServiceInvalidAuthCover'
import ServiceCrashedCover from './ServiceCrashedCover'
import ServiceSleepHelper from './ServiceSleepHelper'
import ServiceLoadErrorCover from './ServiceLoadErrorCover'

const styles = {
root: {
Expand Down Expand Up @@ -189,6 +190,7 @@ class CoreServiceWebView extends React.Component {
initialLoadDone: false,
isLoading: false,
isCrashed: false,
loadError: null,
focusedUrl: null,
permissionRequests: [],
permissionRequestsUrl: undefined,
Expand Down Expand Up @@ -258,6 +260,15 @@ class CoreServiceWebView extends React.Component {
this.refs[BROWSER_REF].reset()
}

/**
* Clears a load error
* @param evt: the event that fired
*/
handleClearLoadError = (evt) => {
this.setState({ loadError: null })
this.refs[BROWSER_REF].reload()
}

/**
* Handles a permission being resolved
* @param type: the permission type
Expand Down Expand Up @@ -533,7 +544,10 @@ class CoreServiceWebView extends React.Component {
* @param evt: the event that fired
*/
handleDidStartLoading = (evt) => {
this.setState({ isLoading: true })
this.setState({
isLoading: true,
loadError: null
})
}

/**
Expand Down Expand Up @@ -572,6 +586,23 @@ class CoreServiceWebView extends React.Component {
this.setState({ isCrashed: true })
}

/**
* Handles a load error
* @param evt: the event that fired
*/
handleLoadError = (evt) => {
if (!evt.isMainFrame) { return }
if (!ServiceLoadErrorCover.HANDLED_ERROR_CODES.has(evt.errorCode)) { return }

this.setState({
loadError: {
code: evt.errorCode,
description: evt.errorDescription,
url: evt.validatedURL
}
})
}

/**
* Handles the pending permission requests changing
*/
Expand Down Expand Up @@ -640,7 +671,8 @@ class CoreServiceWebView extends React.Component {
isolateMailboxProcesses,
authDataId,
permissionRequests,
permissionRequestsUrl
permissionRequestsUrl,
loadError
} = this.state

if (!mailbox || !service) { return false }
Expand Down Expand Up @@ -714,6 +746,9 @@ class CoreServiceWebView extends React.Component {
onWebContentsAttached={this.handleWebContentsAttached}

{...webviewEventProps}
didFailLoad={(evt) => {
this.multiCallBrowserEvent([this.handleLoadError, webviewEventProps.didFailLoad], [evt])
}}

crashed={(evt) => {
this.multiCallBrowserEvent([this.handleCrashed, webviewEventProps.crashed], [evt])
Expand Down Expand Up @@ -776,6 +811,7 @@ class CoreServiceWebView extends React.Component {
{hasSearch ? (
<ServiceSearch mailboxId={mailbox.id} serviceId={serviceId} />
) : undefined}
<ServiceLoadErrorCover loadError={loadError} attemptReload={this.handleClearLoadError} />
<ServiceCrashedCover isCrashed={isCrashed} attemptUncrash={this.handleUncrash} />
<ServiceInvalidAuthCover serviceId={serviceId} />
</div>
Expand Down
@@ -0,0 +1,137 @@
import React from 'react'
import PropTypes from 'prop-types'
import shallowCompare from 'react-addons-shallow-compare'
import ServiceInformationCover from '../ServiceInformationCover'
import { Button } from '@material-ui/core'
import { withStyles } from '@material-ui/core/styles'
import RefreshIcon from '@material-ui/icons/Refresh'
import WifiOffIcon from '@material-ui/icons/WifiOff'
import FARFrown from 'wbfa/FARFrown'

const HANDLED_ERROR_CODES = new Set([
-102, // CONNECTION_REFUSED
-105, // ERR_NAME_NOT_RESOLVED
-106 // ERR_INTERNET_DISCONNECTED
])

const styles = {
infoButtonIcon: {
marginRight: 6
}
}

@withStyles(styles)
class ServiceLoadErrorCover extends React.Component {
/* **************************************************************************/
// Class
/* **************************************************************************/

static propTypes = {
attemptReload: PropTypes.func.isRequired,
loadError: PropTypes.shape({
code: PropTypes.oneOf(Array.from(HANDLED_ERROR_CODES)).isRequired,
description: PropTypes.string.isRequired,
url: PropTypes.string
})
}

static get HANDLED_ERROR_CODES () { return HANDLED_ERROR_CODES }

/* **************************************************************************/
// Rendering
/* **************************************************************************/

shouldComponentUpdate (nextProps, nextState) {
return shallowCompare(this, nextProps, nextState)
}

/**
* @param code: the error code
* @return icon component
*/
renderIconComponent (code) {
switch (code) {
case -102: return FARFrown
case -105: return FARFrown
case -106: return WifiOffIcon
}
}

/**
* @param code: the error code
* @return error title
*/
renderTitle (code) {
switch (code) {
case -102: return `This site can't be reached`
case -105: return `This site can't be reached`
case -106: return `No internet`
}
}

/**
* @param code: the error code
* @param description: the error description
* @param url: the url that errored
* @return error text
*/
renderText (code, description, url) {
switch (code) {
case -102: return [
'Refused to connect to the server:',
url,
'',
description
]
case -105: return [
'There server IP address could not be found for:',
url,
'',
description
]
case -106: return [
'Try checking your internet connection',
'',
description
]
}
}

/**
* @param classes: the css classes
* @param code: the error code
* @param attemptReload: the reload function
* @return jsx
*/
renderButton (classes, code, attemptReload) {
switch (code) {
case -102: return undefined
case -105: return undefined
case -106: return (
<Button variant='contained' onClick={attemptReload}>
<RefreshIcon className={classes.infoButtonIcon} />
Reload
</Button>
)
}
}

render () {
const { attemptReload, loadError, classes, ...passProps } = this.props

if (loadError) {
return (
<ServiceInformationCover
{...passProps}
IconComponent={this.renderIconComponent(loadError.code)}
title={this.renderTitle(loadError.code)}
text={this.renderText(loadError.code, loadError.description, loadError.url)}
button={this.renderButton(classes, loadError.code, attemptReload)} />
)
} else {
return false
}
}
}

export default ServiceLoadErrorCover
1 change: 1 addition & 0 deletions src/scenes/mailboxes/src/Server/Analytics.js
Expand Up @@ -310,6 +310,7 @@ class Analytics {
return Promise.resolve()
}
})
.catch(() => { /* no-op */ })
}

/* ****************************************************************************/
Expand Down
8 changes: 8 additions & 0 deletions src/scenes/wbfa/generated/FARFrown.free.js
@@ -0,0 +1,8 @@
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faFrown } from '@fortawesome/free-regular-svg-icons/faFrown'
export default class FARFrown extends React.Component {
render () {
return (<FontAwesomeIcon {...this.props} icon={faFrown} />)
}
}
8 changes: 8 additions & 0 deletions src/scenes/wbfa/generated/FARFrown.pro.js
@@ -0,0 +1,8 @@
import React from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faFrown } from '@fortawesome/pro-regular-svg-icons/faFrown'
export default class FARFrown extends React.Component {
render () {
return (<FontAwesomeIcon {...this.props} icon={faFrown} />)
}
}

0 comments on commit 7428438

Please sign in to comment.