Browse Source

Merge pull request #679 from LedgerHQ/develop

Prepare for beta.2
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
8f5ae0420a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      src/components/ManagerPage/AppSearchBar.js
  2. 33
      src/components/ManagerPage/AppsList.js
  3. 14
      src/components/ManagerPage/Dashboard.js
  4. 4
      src/components/ManagerPage/UpdateFirmwareButton.js
  5. 32
      src/components/RenderError.js
  6. 2
      src/components/ThrowBlock.js
  7. 1
      src/config/cryptocurrencies.js
  8. 20
      src/helpers/apps/installApp.js
  9. 14
      src/helpers/apps/uninstallApp.js
  10. 16
      src/logger.js
  11. 3
      src/renderer/init.js
  12. 4
      src/sentry/browser.js
  13. 4
      src/sentry/node.js
  14. 10
      static/i18n/en/errors.yml

91
src/components/ManagerPage/AppSearchBar.js

@ -1,14 +1,12 @@
// @flow
import React, { PureComponent } from 'react'
import styled from 'styled-components'
import { color, fontSize, space } from 'styled-system'
import fontFamily from 'styles/styled/fontFamily'
import type { LedgerScriptParams } from 'helpers/common'
import React, { PureComponent, Fragment } from 'react'
import { ff } from 'styles/helpers'
import type { LedgerScriptParams } from 'helpers/common'
import Box from 'components/base/Box'
import Space from 'components/base/Space'
import Input from 'components/base/Input'
import Search from 'components/base/Search'
import SearchIcon from 'icons/Search'
@ -24,53 +22,13 @@ type State = {
focused: boolean,
}
const SearchBarWrapper = styled(Box).attrs({
horizontal: true,
borderRadius: 4,
})`
height: 42px;
width: 100%;
margin: 0 0 20px 0;
background-color: white;
padding: 0 13px;
${p =>
p.focused
? `
border: 1px solid #6490f1;
`
: 'border: 1px solid white;'};
`
const Input = styled.input.attrs({
ff: 'Open Sans|SemiBold',
color: 'dark',
mx: 3,
fontSize: 4,
})`
${space};
${fontFamily};
${fontSize};
${color};
border: 0;
flex: 1;
outline: none;
background: transparent;
&::placeholder {
color: ${p => p.theme.colors.fog};
${() => ff('Open Sans|Regular')};
}
`
class AppSearchBar extends PureComponent<Props, State> {
state = {
query: '',
focused: false,
}
handleChange = (e: any) => this.setState({ query: e.target.value })
handleChange = (query: string) => this.setState({ query })
handleFocus = (bool: boolean) => () => this.setState({ focused: bool })
@ -88,20 +46,29 @@ class AppSearchBar extends PureComponent<Props, State> {
const color = focused ? 'black' : 'grey'
return (
<Box>
<SearchBarWrapper align="center" focused={focused}>
<SearchIcon size={16} style={{ color }} />
<Input
innerRef={c => (this.input = c)}
type="text"
value={query}
onChange={this.handleChange}
onFocus={this.handleFocus(true)}
onBlur={this.handleFocus(false)}
placeholder={'Search app'}
/>
{!!query && <CrossIcon size={16} cursor="pointer" onClick={this.reset} />}
</SearchBarWrapper>
<Fragment>
<Input
innerRef={c => (this.input = c)}
type="text"
value={query}
onChange={this.handleChange}
onFocus={this.handleFocus(true)}
onBlur={this.handleFocus(false)}
placeholder={'Search app'}
renderLeft={
<Box pl={3} justify="center">
<SearchIcon size={16} style={{ color }} />
</Box>
}
renderRight={
query ? (
<Box justify="center" cursor="pointer" onClick={this.reset} px={3}>
<CrossIcon size={16} />
</Box>
) : null
}
/>
<Space of={30} />
<Search
fuseOptions={{
threshold: 0.5,
@ -111,7 +78,7 @@ class AppSearchBar extends PureComponent<Props, State> {
items={list}
render={items => children(items)}
/>
</Box>
</Fragment>
)
}
}

33
src/components/ManagerPage/AppsList.js

@ -21,7 +21,7 @@ import Spinner from 'components/base/Spinner'
import Button from 'components/base/Button'
import TranslatedError from 'components/TranslatedError'
import ExclamationCircle from 'icons/ExclamationCircle'
import IconInfoCircle from 'icons/InfoCircle'
import ExclamationCircleThin from 'icons/ExclamationCircleThin'
import Update from 'icons/Update'
import Trash from 'icons/Trash'
@ -37,8 +37,6 @@ const List = styled(Box).attrs({
flex-wrap: wrap;
`
let CACHED_APPS = null
const ICONS_FALLBACK = {
bitcoin_testnet: 'bitcoin',
}
@ -85,8 +83,7 @@ class AppsList extends PureComponent<Props, State> {
async fetchAppList() {
try {
const { targetId, version } = this.props
const appsList = CACHED_APPS || (await listApps.send({ targetId, version }).toPromise())
CACHED_APPS = appsList
const appsList = await listApps.send({ targetId, version }).toPromise()
if (!this._unmounted) {
this.setState({ appsList, status: 'idle', appsLoaded: true })
}
@ -249,19 +246,19 @@ class AppsList extends PureComponent<Props, State> {
return (
<Box flow={6}>
<Box>
<Box mb={4} color="dark" ff="Museo Sans" fontSize={5} flow={2} horizontal>
<span>{t('app:manager.apps.all')}</span>
<span>
<Tooltip
render={() => (
<Box ff="Open Sans|SemiBold" fontSize={2}>
{t('app:manager.apps.help')}
</Box>
)}
>
<ExclamationCircle size={12} />
</Tooltip>
</span>
<Box mb={4} color="dark" ff="Museo Sans" fontSize={5} flow={2} horizontal align="center">
<span style={{ lineHeight: 1 }}>{t('app:manager.apps.all')}</span>
<Tooltip
render={() => (
<Box ff="Open Sans|SemiBold" fontSize={2}>
{t('app:manager.apps.help')}
</Box>
)}
>
<Box color="grey">
<IconInfoCircle size={12} />
</Box>
</Tooltip>
</Box>
{this.renderList()}
</Box>

14
src/components/ManagerPage/Dashboard.js

@ -2,7 +2,6 @@
import React from 'react'
import { translate } from 'react-i18next'
import { EXPERIMENTAL_FIRMWARE_UPDATE } from 'config/constants'
import type { T, Device } from 'types/common'
import Box from 'components/base/Box'
@ -35,15 +34,10 @@ const Dashboard = ({ device, deviceInfo, t }: Props) => (
</Text>
</Box>
<Box mt={5}>
{EXPERIMENTAL_FIRMWARE_UPDATE ? (
<FirmwareUpdate
infos={{
targetId: deviceInfo.targetId,
version: deviceInfo.version,
}}
device={device}
/>
) : null}
<FirmwareUpdate
infos={{ targetId: deviceInfo.targetId, version: deviceInfo.version }}
device={device}
/>
</Box>
<Box mt={5}>
<AppsList device={device} targetId={deviceInfo.targetId} version={deviceInfo.version} />

4
src/components/ManagerPage/UpdateFirmwareButton.js

@ -4,6 +4,8 @@ import { translate } from 'react-i18next'
import type { T } from 'types/common'
import { EXPERIMENTAL_FIRMWARE_UPDATE } from 'config/constants'
import Button from 'components/base/Button'
import Text from 'components/base/Text'
import { getCleanVersion } from 'components/ManagerPage/FirmwareUpdate'
@ -25,7 +27,7 @@ const UpdateFirmwareButton = ({ t, firmware, installFirmware }: Props) =>
<Text ff="Open Sans|Regular" fontSize={4} style={{ marginLeft: 'auto', marginRight: 15 }}>
{t('app:manager.firmware.latest', { version: getCleanVersion(firmware.name) })}
</Text>
<Button primary onClick={installFirmware}>
<Button primary onClick={installFirmware} disabled={!EXPERIMENTAL_FIRMWARE_UPDATE}>
{t('app:manager.firmware.update')}
</Button>
</Fragment>

32
src/components/RenderError.js

@ -10,12 +10,10 @@ import hardReset from 'helpers/hardReset'
import type { T } from 'types/common'
import Spoiler from 'components/base/Spoiler'
import ExportLogsBtn from 'components/ExportLogsBtn'
import Box from 'components/base/Box'
import Space from 'components/base/Space'
import Button from 'components/base/Button'
import TranslatedError from './TranslatedError'
type Props = {
error: Error,
@ -94,17 +92,23 @@ ${error.stack}
{t('app:crash.reset')}
</Button>
</Box>
<Space of={20} />
<Spoiler color="wallet" title={t('app:crash.showError')}>
<Box my={6}>
<ErrContainer>
<TranslatedError error={error} />
<strong>{String(error)}</strong>
<div>{error.stack || 'no stacktrace'}</div>
</ErrContainer>
</Spoiler>
<Space of={10} />
<Spoiler color="wallet" title={t('app:crash.showDetails')}>
<ErrContainer>{error.stack}</ErrContainer>
</Spoiler>
<Space of={100} />
</Box>
<pre
style={{
position: 'fixed',
bottom: 8,
left: 8,
opacity: 0.2,
fontSize: 10,
}}
>
{__APP_VERSION__}
</pre>
{children}
</Box>
)
@ -114,14 +118,14 @@ ${error.stack}
const ErrContainer = ({ children }: { children: any }) => (
<pre
style={{
marginTop: 10,
maxWidth: '80%',
margin: 'auto',
maxWidth: '80vw',
overflow: 'auto',
fontSize: 10,
fontFamily: 'monospace',
background: 'rgba(0, 0, 0, 0.05)',
cursor: 'text',
userSelect: 'text',
opacity: 0.3,
}}
>
{children}

2
src/components/ThrowBlock.js

@ -17,7 +17,7 @@ class ThrowBlock extends PureComponent<Props, State> {
}
componentDidCatch(error: Error) {
logger.error(error)
logger.critical(error)
this.setState({ error })
}

1
src/config/cryptocurrencies.js

@ -26,6 +26,7 @@ const supported: CryptoCurrencyIds[] = [
'viacoin',
'stealthcoin',
'poswallet',
'clubcoin',
'bitcoin_testnet',
]

20
src/helpers/apps/installApp.js

@ -9,14 +9,26 @@ import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
const CannotInstall = createCustomErrorClass('CannotInstall')
const ManagerUnexpectedError = createCustomErrorClass('ManagerUnexpected')
const ManagerNotEnoughSpaceError = createCustomErrorClass('ManagerNotEnoughSpace')
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked')
const ManagerAppAlreadyInstalledError = createCustomErrorClass('ManagerAppAlreadyInstalled')
const ManagerAppRelyOnBTCError = createCustomErrorClass('ManagerAppRelyOnBTC')
function remapError(promise) {
return promise.catch((e: Error) => {
if (e.message.endsWith('6982')) {
throw new CannotInstall()
switch (true) {
case e.message.endsWith('6982'):
throw new ManagerDeviceLockedError()
case e.message.endsWith('6a84') || e.message.endsWith('6a85'):
throw new ManagerNotEnoughSpaceError()
case e.message.endsWith('6a80') || e.message.endsWith('6a81'):
throw new ManagerAppAlreadyInstalledError()
case e.message.endsWith('6a83'):
throw new ManagerAppRelyOnBTCError()
default:
throw new ManagerUnexpectedError(e.message, { msg: e.message })
}
throw e
})
}

14
src/helpers/apps/uninstallApp.js

@ -8,14 +8,20 @@ import { createDeviceSocket } from 'helpers/socket'
import type { LedgerScriptParams } from 'helpers/common'
import createCustomErrorClass from '../createCustomErrorClass'
const CannotUninstall = createCustomErrorClass('CannotUninstall')
const ManagerUnexpectedError = createCustomErrorClass('ManagerUnexpectedError')
const ManagerDeviceLockedError = createCustomErrorClass('ManagerDeviceLocked')
const ManagerUninstallBTCDep = createCustomErrorClass('ManagerUninstallBTCDep')
function remapError(promise) {
return promise.catch((e: Error) => {
if (e.message.endsWith('6a83')) {
throw new CannotUninstall()
switch (true) {
case e.message.endsWith('6982'):
throw new ManagerDeviceLockedError()
case e.message.endsWith('6a83'):
throw new ManagerUninstallBTCDep()
default:
throw new ManagerUnexpectedError(e.message, { msg: e.message })
}
throw e
})
}

16
src/logger.js

@ -134,15 +134,31 @@ export default {
console.log(...args)
addLog('log', ...args)
},
warn: (...args: any) => {
console.warn(...args)
addLog('warn', ...args)
},
error: (...args: any) => {
console.error(...args)
addLog('error', ...args)
},
critical: (error: Error) => {
addLog('critical', error)
console.error(error)
try {
if (typeof window !== 'undefined') {
require('sentry/browser').captureException(error)
} else {
require('sentry/node').captureException(error)
}
} catch (e) {
console.warn("Can't send to sentry", error, e)
}
},
exportLogs: (): Array<{ type: string, date: Date, args: Array<any> }> =>
logs.map(({ type, date, args }) => ({
type,

3
src/renderer/init.js

@ -98,7 +98,6 @@ function r(Comp) {
}
init().catch(e => {
// for now we make the app crash instead of pending forever. later we can render the error OR try to recover, but probably this is unrecoverable cases.
logger.error(e)
logger.critical(e)
r(<AppError error={e} language="en" />)
})

4
src/sentry/browser.js

@ -7,3 +7,7 @@ import install from './install'
export default (shouldSendCallback: () => boolean) => {
install(Raven, shouldSendCallback, user().id)
}
export const captureException = (e: Error) => {
Raven.captureException(e)
}

4
src/sentry/node.js

@ -6,3 +6,7 @@ import install from './install'
export default (shouldSendCallback: () => boolean, userId: string) => {
install(Raven, shouldSendCallback, userId)
}
export const captureException = (e: Error) => {
Raven.captureException(e)
}

10
static/i18n/en/errors.yml

@ -21,5 +21,11 @@ DeviceSocketNoBulkStatus: Oops, device connection failed. Please try again [bulk
DeviceSocketNoHandler: Oops, device connection failed (handler {{query}}). Please try again.
LatestMCUInstalledError: MCU on device already up to date.
HardResetFail: Reset failed. Please try again.
CannotUninstall: Cannot uninstall app.
CannotInstall: Not enough room left on your device. Please uninstall some apps and try again.
ManagerAPIsFail: Our services are currently unavailable. Please try again later.
ManagerUnexpected: Unexpected error occurred ({{msg}}). Please try again later.
ManagerNotEnoughSpace: Not enough room left on your device. Please uninstall some apps and try again.
ManagerDeviceLocked: Device is locked
ManagerAppAlreadyInstalled: App is already installed
ManagerAppRelyOnBTC: You must install Bitcoin application first
ManagerUninstallBTCDep: You must uninstall other altcoins first

Loading…
Cancel
Save