diff --git a/README.md b/README.md
index 7ebf21be..a8eb732f 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,6 @@ DEBUG_ACTION=1
DEBUG_TAB_KEY=1
DEBUG_LIBCORE=1
DEBUG_WS=1
-LEDGER_RESET_ALL=1
LEDGER_DEBUG_ALL_LANGS=1
SKIP_GENUINE=1
SKIP_ONBOARDING=1
diff --git a/src/components/DashboardPage/AccountCard.js b/src/components/DashboardPage/AccountCard.js
deleted file mode 100644
index a9881a2f..00000000
--- a/src/components/DashboardPage/AccountCard.js
+++ /dev/null
@@ -1,103 +0,0 @@
-// @flow
-
-import React, { PureComponent } from 'react'
-import styled from 'styled-components'
-
-import type { Account, Currency } from '@ledgerhq/live-common/lib/types'
-
-import Chart from 'components/base/Chart'
-import Bar from 'components/base/Bar'
-import Box, { Card } from 'components/base/Box'
-import CalculateBalance from 'components/CalculateBalance'
-import FormattedVal from 'components/base/FormattedVal'
-import Ellipsis from 'components/base/Ellipsis'
-import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
-import DeltaChange from '../DeltaChange'
-
-const Wrapper = styled(Card).attrs({
- p: 4,
- flex: 1,
-})`
- cursor: ${p => (p.onClick ? 'pointer' : 'default')};
-`
-
-class AccountCard extends PureComponent<{
- counterValue: Currency,
- account: Account,
- onClick?: Account => void,
- daysCount: number,
-}> {
- render() {
- const { counterValue, account, onClick, daysCount, ...props } = this.props
- return (
- onClick(account) : null} {...props}>
-
-
-
-
-
-
-
- {account.currency.name}
-
-
- {account.name}
-
-
-
-
-
-
-
-
-
- {({ isAvailable, balanceHistory, balanceStart, balanceEnd }) => (
-
-
-
- {isAvailable ? (
-
- ) : null}
-
-
- {isAvailable && !balanceStart.isZero() ? (
-
- ) : null}
-
-
-
-
- )}
-
-
- )
- }
-}
-
-export default AccountCard
diff --git a/src/components/DashboardPage/AccountCard/Header.js b/src/components/DashboardPage/AccountCard/Header.js
new file mode 100644
index 00000000..642ec56e
--- /dev/null
+++ b/src/components/DashboardPage/AccountCard/Header.js
@@ -0,0 +1,33 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
+import Box from 'components/base/Box'
+import Ellipsis from 'components/base/Ellipsis'
+import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
+
+class AccountCardHeader extends PureComponent<{
+ currency: CryptoCurrency,
+ accountName: string,
+}> {
+ render() {
+ const { currency, accountName } = this.props
+ return (
+
+
+
+
+
+
+ {currency.name}
+
+
+ {accountName}
+
+
+
+ )
+ }
+}
+
+export default AccountCardHeader
diff --git a/src/components/DashboardPage/AccountCard/index.js b/src/components/DashboardPage/AccountCard/index.js
new file mode 100644
index 00000000..25dc16d4
--- /dev/null
+++ b/src/components/DashboardPage/AccountCard/index.js
@@ -0,0 +1,94 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import styled from 'styled-components'
+
+import type { Account, Currency } from '@ledgerhq/live-common/lib/types'
+
+import Chart from 'components/base/Chart'
+import Bar from 'components/base/Bar'
+import Box, { Card } from 'components/base/Box'
+import CalculateBalance from 'components/CalculateBalance'
+import FormattedVal from 'components/base/FormattedVal'
+import DeltaChange from 'components/DeltaChange'
+import AccountCardHeader from './Header'
+
+const Wrapper = styled(Card).attrs({
+ p: 4,
+ flex: 1,
+})`
+ cursor: ${p => (p.onClick ? 'pointer' : 'default')};
+`
+
+class AccountCard extends PureComponent<{
+ counterValue: Currency,
+ account: Account,
+ onClick: Account => void,
+ daysCount: number,
+}> {
+ renderBody = ({ isAvailable, balanceHistory, balanceStart, balanceEnd }: *) => {
+ const { counterValue, account } = this.props
+ return (
+
+
+
+ {isAvailable ? (
+
+ ) : null}
+
+
+ {isAvailable && !balanceStart.isZero() ? (
+
+ ) : null}
+
+
+
+
+ )
+ }
+ onClick = () => {
+ const { account, onClick } = this.props
+ onClick(account)
+ }
+ render() {
+ const { counterValue, account, onClick, daysCount, ...props } = this.props
+ return (
+
+
+
+
+
+
+
+
+
+ {this.renderBody}
+
+
+ )
+ }
+}
+
+export default AccountCard
diff --git a/src/components/DashboardPage/AccountCardList.js b/src/components/DashboardPage/AccountCardList.js
new file mode 100644
index 00000000..eee7321e
--- /dev/null
+++ b/src/components/DashboardPage/AccountCardList.js
@@ -0,0 +1,66 @@
+// @flow
+
+import React, { Component } from 'react'
+import type { Account, Currency } from '@ledgerhq/live-common/lib/types'
+
+import Box from 'components/base/Box'
+import AccountCard from './AccountCard'
+import AccountCardListHeader from './AccountCardListHeader'
+import AccountCardPlaceholder from './AccountCardPlaceholder'
+
+type Props = {
+ accounts: Account[],
+ onAccountClick: Account => void,
+ counterValue: Currency,
+ daysCount: number,
+}
+
+class AccountCardList extends Component {
+ render() {
+ const { accounts, counterValue, daysCount, onAccountClick } = this.props
+
+ return (
+
+
+
+ {accounts
+ .map(account => ({
+ key: account.id,
+ account,
+ }))
+ .concat(
+ Array(3 - (accounts.length % 3))
+ .fill(null)
+ .map((_, i) => ({
+ key: `placeholder_${i}`,
+ withPlaceholder: i === 0,
+ })),
+ )
+ .map(item => (
+
+ {item.account ? (
+
+ ) : item.withPlaceholder ? (
+
+ ) : null}
+
+ ))}
+
+
+ )
+ }
+}
+
+export default AccountCardList
diff --git a/src/components/DashboardPage/AccountCardListHeader.js b/src/components/DashboardPage/AccountCardListHeader.js
new file mode 100644
index 00000000..9da0fde5
--- /dev/null
+++ b/src/components/DashboardPage/AccountCardListHeader.js
@@ -0,0 +1,33 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import { translate } from 'react-i18next'
+import type { T } from 'types/common'
+
+import Box from 'components/base/Box'
+import Text from 'components/base/Text'
+import AccountsOrder from './AccountsOrder'
+
+type Props = {
+ t: T,
+ accountsLength: number,
+}
+
+class AccountCardListHeader extends PureComponent {
+ render() {
+ const { accountsLength, t } = this.props
+
+ return (
+
+
+ {t('app:dashboard.accounts.title', { count: accountsLength })}
+
+
+
+
+
+ )
+ }
+}
+
+export default translate()(AccountCardListHeader)
diff --git a/src/components/DashboardPage/AccountCardPlaceholder.js b/src/components/DashboardPage/AccountCardPlaceholder.js
new file mode 100644
index 00000000..1936fe4d
--- /dev/null
+++ b/src/components/DashboardPage/AccountCardPlaceholder.js
@@ -0,0 +1,64 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import { connect } from 'react-redux'
+import { translate } from 'react-i18next'
+import styled from 'styled-components'
+
+import { openModal } from 'reducers/modals'
+import { MODAL_ADD_ACCOUNTS } from 'config/constants'
+import type { T } from 'types/common'
+import { i } from 'helpers/staticPath'
+import Box from 'components/base/Box'
+import Button from 'components/base/Button'
+
+const Wrapper = styled(Box).attrs({
+ p: 4,
+ flex: 1,
+ alignItems: 'center',
+})`
+ border: 1px dashed ${p => p.theme.colors.fog};
+ border-radius: 4px;
+ height: 215px;
+`
+
+class AccountCardPlaceholder extends PureComponent<{
+ t: T,
+ openModal: string => void,
+}> {
+ onAddAccounts = () => this.props.openModal(MODAL_ADD_ACCOUNTS)
+
+ render() {
+ const { t } = this.props
+ return (
+
+
+
+
+
+ {t('app:dashboard.emptyAccountTile.desc')}
+
+
+
+ )
+ }
+}
+
+export default translate()(
+ connect(
+ null,
+ {
+ openModal,
+ },
+ )(AccountCardPlaceholder),
+)
diff --git a/src/components/DashboardPage/CurrentGreetings.js b/src/components/DashboardPage/CurrentGreetings.js
new file mode 100644
index 00000000..da4896b8
--- /dev/null
+++ b/src/components/DashboardPage/CurrentGreetings.js
@@ -0,0 +1,31 @@
+// @flow
+import React, { PureComponent } from 'react'
+import { translate } from 'react-i18next'
+import type { T } from 'types/common'
+
+import Text from 'components/base/Text'
+
+const getCurrentGreetings = () => {
+ const localTimeHour = new Date().getHours()
+ const afternoon_breakpoint = 12
+ const evening_breakpoint = 17
+ if (localTimeHour >= afternoon_breakpoint && localTimeHour < evening_breakpoint) {
+ return 'app:dashboard.greeting.afternoon'
+ } else if (localTimeHour >= evening_breakpoint) {
+ return 'app:dashboard.greeting.evening'
+ }
+ return 'app:dashboard.greeting.morning'
+}
+
+class CurrentGettings extends PureComponent<{ t: T }> {
+ render() {
+ const { t } = this.props
+ return (
+
+ {t(getCurrentGreetings())}
+
+ )
+ }
+}
+
+export default translate()(CurrentGettings)
diff --git a/src/components/DashboardPage/SummaryDesc.js b/src/components/DashboardPage/SummaryDesc.js
new file mode 100644
index 00000000..ff8c5f3e
--- /dev/null
+++ b/src/components/DashboardPage/SummaryDesc.js
@@ -0,0 +1,22 @@
+// @flow
+
+import React, { PureComponent } from 'react'
+import { translate } from 'react-i18next'
+import type { T } from 'types/common'
+import Text from 'components/base/Text'
+
+class SummaryDesc extends PureComponent<{
+ t: T,
+ totalAccounts: number,
+}> {
+ render() {
+ const { totalAccounts, t } = this.props
+ return (
+
+ {t('app:dashboard.summary', { count: totalAccounts })}
+
+ )
+ }
+}
+
+export default translate()(SummaryDesc)
diff --git a/src/components/DashboardPage/index.js b/src/components/DashboardPage/index.js
index 384f6d71..2b3b6340 100644
--- a/src/components/DashboardPage/index.js
+++ b/src/components/DashboardPage/index.js
@@ -5,7 +5,6 @@ import uniq from 'lodash/uniq'
import { compose } from 'redux'
import { translate } from 'react-i18next'
import { connect } from 'react-redux'
-import styled from 'styled-components'
import { push } from 'react-router-redux'
import { createStructuredSelector } from 'reselect'
import type { Account, Currency } from '@ledgerhq/live-common/lib/types'
@@ -14,11 +13,8 @@ import type { T } from 'types/common'
import { colors } from 'styles/theme'
import { accountsSelector } from 'reducers/accounts'
-import { openModal } from 'reducers/modals'
-import { MODAL_ADD_ACCOUNTS } from 'config/constants'
import {
counterValueCurrencySelector,
- localeSelector,
selectedTimeRangeSelector,
timeRangeDaysByKey,
} from 'reducers/settings'
@@ -32,27 +28,23 @@ import UpdateNotifier from 'components/UpdateNotifier'
import BalanceInfos from 'components/BalanceSummary/BalanceInfos'
import BalanceSummary from 'components/BalanceSummary'
import Box from 'components/base/Box'
-import { i } from 'helpers/staticPath'
import PillsDaysCount from 'components/PillsDaysCount'
-import Text from 'components/base/Text'
import OperationsList from 'components/OperationsList'
import StickyBackToTop from 'components/StickyBackToTop'
-import Button from 'components/base/Button'
-import AccountCard from './AccountCard'
-import AccountsOrder from './AccountsOrder'
import EmptyState from './EmptyState'
+import CurrentGreetings from './CurrentGreetings'
+import SummaryDesc from './SummaryDesc'
+import AccountCardList from './AccountCardList'
const mapStateToProps = createStructuredSelector({
accounts: accountsSelector,
counterValue: counterValueCurrencySelector,
- locale: localeSelector,
selectedTimeRange: selectedTimeRangeSelector,
})
const mapDispatchToProps = {
push,
saveSettings,
- openModal,
}
type Props = {
@@ -62,41 +54,33 @@ type Props = {
counterValue: Currency,
selectedTimeRange: TimeRange,
saveSettings: ({ selectedTimeRange: TimeRange }) => *,
- openModal: string => void,
}
class DashboardPage extends PureComponent {
onAccountClick = account => this.props.push(`/account/${account.id}`)
- handleGreeting = () => {
- const localTimeHour = new Date().getHours()
- const afternoon_breakpoint = 12
- const evening_breakpoint = 17
-
- if (localTimeHour >= afternoon_breakpoint && localTimeHour < evening_breakpoint) {
- return 'app:dashboard.greeting.afternoon'
- } else if (localTimeHour >= evening_breakpoint) {
- return 'app:dashboard.greeting.evening'
- }
- return 'app:dashboard.greeting.morning'
- }
-
handleChangeSelectedTime = item => {
this.props.saveSettings({ selectedTimeRange: item.key })
}
- _cacheBalance = null
+ renderHeader = ({ isAvailable, totalBalance, selectedTimeRange, sinceBalance, refBalance }) => (
+
+ )
render() {
- const { accounts, t, counterValue, selectedTimeRange, openModal } = this.props
+ const { accounts, t, counterValue, selectedTimeRange } = this.props
const daysCount = timeRangeDaysByKey[selectedTimeRange]
- const timeFrame = this.handleGreeting()
- const imagePath = i('empty-account-tile.svg')
const totalAccounts = accounts.length
const totalCurrencies = uniq(accounts.map(a => a.currency.id)).length
const totalOperations = accounts.reduce((sum, a) => sum + a.operations.length, 0)
- const displayOperationsHelper = (account: Account) => account.operations.length > 0
- const displayOperations = accounts.some(displayOperationsHelper)
return (
@@ -113,12 +97,8 @@ class DashboardPage extends PureComponent {
-
- {t(timeFrame)}
-
-
- {t('app:dashboard.summary', { count: totalAccounts })}
-
+
+
{
/>
-
-
+
+
+
+ {totalOperations > 0 && (
+ (
-
- )}
+ title={t('app:dashboard.recentActivity')}
+ withAccount
/>
-
-
-
- {t('app:dashboard.accounts.title', { count: accounts.length })}
-
-
-
-
-
-
- {accounts
- .concat(
- Array(3 - (accounts.length % 3))
- .fill(null)
- .map((_, i) => i === 0),
- )
- .map((account, i) => (
-
- {account ? (
- typeof account === 'object' ? (
-
- ) : (
-
-
-
-
-
- {t('app:dashboard.emptyAccountTile.desc')}
-
-
-
- )
- ) : null}
-
- ))}
-
-
- {displayOperations && (
-
- )}
-
-
+ )}
+
) : (
@@ -243,13 +151,3 @@ export default compose(
),
translate(),
)(DashboardPage)
-
-const Wrapper = styled(Box).attrs({
- p: 4,
- flex: 1,
- alignItems: 'center',
-})`
- border: 1px dashed ${p => p.theme.colors.fog};
- border-radius: 4px;
- height: 215px;
-`
diff --git a/src/components/base/Button/index.js b/src/components/base/Button/index.js
index 4bf4839e..1d7a0444 100644
--- a/src/components/base/Button/index.js
+++ b/src/components/base/Button/index.js
@@ -93,16 +93,22 @@ const buttonStyles: { [_: string]: Style } = {
background: ${rgba(c, 0.1)};
`
},
- active: p => `
- color: ${darken(
- p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
- 0.1,
- )};
- border-color: ${darken(
- p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
- 0.1,
- )};
- `,
+ active: p => {
+ const c = p.outlineColor
+ ? p.theme.colors[p.outlineColor] || p.outlineColor
+ : p.theme.colors.wallet
+ return `
+ background: ${rgba(c, 0.15)};
+ color: ${darken(
+ p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
+ 0.1,
+ )};
+ border-color: ${darken(
+ p.outlineColor ? p.theme.colors[p.outlineColor] || p.outlineColor : p.theme.colors.wallet,
+ 0.1,
+ )};
+ `
+ },
},
outlineGrey: {
default: p => `
diff --git a/src/config/constants.js b/src/config/constants.js
index 3090cfe9..cbe5b29e 100644
--- a/src/config/constants.js
+++ b/src/config/constants.js
@@ -45,7 +45,7 @@ export const SYNC_ALL_INTERVAL = 120 * 1000
export const SYNC_BOOT_DELAY = 2 * 1000
export const SYNC_PENDING_INTERVAL = 10 * 1000
export const SYNC_MAX_CONCURRENT = intFromEnv('LEDGER_SYNC_MAX_CONCURRENT', 1)
-export const SYNC_TIMEOUT = intFromEnv('SYNC_TIMEOUT', 30 * 1000)
+export const SYNC_TIMEOUT = intFromEnv('SYNC_TIMEOUT', 60 * 1000)
// Endpoints...
@@ -79,7 +79,6 @@ export const DEBUG_TAB_KEY = boolFromEnv('DEBUG_TAB_KEY')
export const DEBUG_LIBCORE = boolFromEnv('DEBUG_LIBCORE')
export const DEBUG_WS = boolFromEnv('DEBUG_WS')
export const DEBUG_SYNC = boolFromEnv('DEBUG_SYNC')
-export const LEDGER_RESET_ALL = boolFromEnv('LEDGER_RESET_ALL')
export const LEDGER_DEBUG_ALL_LANGS = boolFromEnv('LEDGER_DEBUG_ALL_LANGS')
export const SKIP_GENUINE = boolFromEnv('SKIP_GENUINE')
export const SKIP_ONBOARDING = boolFromEnv('SKIP_ONBOARDING')
diff --git a/src/config/errors.js b/src/config/errors.js
index fa6508bd..d6140d6c 100644
--- a/src/config/errors.js
+++ b/src/config/errors.js
@@ -12,6 +12,7 @@ export const UserRefusedAddress = createCustomErrorClass('UserRefusedAddress')
export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount')
export const DeviceNotGenuineError = createCustomErrorClass('DeviceNotGenuine')
export const DeviceGenuineSocketEarlyClose = createCustomErrorClass('DeviceGenuineSocketEarlyClose')
+export const TimeoutTagged = createCustomErrorClass('TimeoutTagged')
// db stuff, no need to translate
export const NoDBPathGiven = createCustomErrorClass('NoDBPathGiven')
diff --git a/src/helpers/libcore.js b/src/helpers/libcore.js
index a9ed673d..630c0c14 100644
--- a/src/helpers/libcore.js
+++ b/src/helpers/libcore.js
@@ -16,6 +16,7 @@ import { isSegwitPath, isUnsplitPath } from 'helpers/bip32'
import * as accountIdHelper from 'helpers/accountId'
import { createCustomErrorClass, deserializeError } from './errors'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName'
+import { timeoutTagged } from './promise'
const NoAddressesFound = createCustomErrorClass('NoAddressesFound')
@@ -202,6 +203,7 @@ const coreSyncAccount = (core, account) =>
new Promise((resolve, reject) => {
const eventReceiver = createEventReceiver(core, e => {
const code = e.getCode()
+ logger.debug(`syncAccountEvent ${code}`, { type: 'libcore-sync' })
if (code === core.EVENT_CODE.UNDEFINED || code === core.EVENT_CODE.SYNCHRONIZATION_FAILED) {
const payload = e.getPayload()
const message = (
@@ -270,7 +272,7 @@ async function scanNextAccount(props: {
const shouldSyncAccount = true // TODO: let's sync everytime. maybe in the future we can optimize.
if (shouldSyncAccount) {
- await coreSyncAccount(core, njsAccount)
+ await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount))
}
if (isUnsubscribed()) return []
@@ -325,10 +327,10 @@ async function getOrCreateWallet(
): NJSWallet {
const pool = core.getPoolInstance()
try {
- const wallet = await pool.getWallet(WALLET_IDENTIFIER)
+ const wallet = await timeoutTagged('getWallet', 5000, pool.getWallet(WALLET_IDENTIFIER))
return wallet
} catch (err) {
- const currency = await pool.getCurrency(currencyId)
+ const currency = await timeoutTagged('getCurrency', 5000, pool.getCurrency(currencyId))
const splitConfig = isUnsplit ? SPLITTED_CURRENCIES[currencyId] || null : null
const coinType = splitConfig ? splitConfig.coinType : ''
const walletConfig = isSegwit
@@ -342,9 +344,11 @@ async function getOrCreateWallet(
}
: undefined
const njsWalletConfig = createWalletConfig(core, walletConfig)
- const wallet = await core
- .getPoolInstance()
- .createWallet(WALLET_IDENTIFIER, currency, njsWalletConfig)
+ const wallet = await timeoutTagged(
+ 'createWallet',
+ 10000,
+ core.getPoolInstance().createWallet(WALLET_IDENTIFIER, currency, njsWalletConfig),
+ )
return wallet
}
}
@@ -368,21 +372,33 @@ async function buildAccountRaw({
core: *,
ops: NJSOperation[],
}): Promise {
- const njsBalance = await njsAccount.getBalance()
+ const njsBalance = await timeoutTagged('getBalance', 10000, njsAccount.getBalance())
const balance = njsBalance.toLong()
const jsCurrency = getCryptoCurrencyById(currencyId)
- const { derivations } = await wallet.getAccountCreationInfo(accountIndex)
+ const { derivations } = await timeoutTagged(
+ 'getAccountCreationInfo',
+ 10000,
+ wallet.getAccountCreationInfo(accountIndex),
+ )
const [walletPath, accountPath] = derivations
// retrieve xpub
const xpub = njsAccount.getRestoreKey()
// blockHeight
- const { height: blockHeight } = await njsAccount.getLastBlock()
+ const { height: blockHeight } = await timeoutTagged(
+ 'getLastBlock',
+ 30000,
+ njsAccount.getLastBlock(),
+ )
// get a bunch of fresh addresses
- const rawAddresses = await njsAccount.getFreshPublicAddresses()
+ const rawAddresses = await timeoutTagged(
+ 'getFreshPublicAddresses',
+ 10000,
+ njsAccount.getFreshPublicAddresses(),
+ )
const addresses = rawAddresses.map(njsAddress => ({
str: njsAddress.toString(),
@@ -500,7 +516,11 @@ export async function syncAccount({
const isUnsplit = isUnsplitPath(freshAddressPath, SPLITTED_CURRENCIES[currencyId])
let njsWallet
try {
- njsWallet = await core.getPoolInstance().getWallet(decodedAccountId.walletName)
+ njsWallet = await timeoutTagged(
+ 'getWallet',
+ 10000,
+ core.getPoolInstance().getWallet(decodedAccountId.walletName),
+ )
} catch (e) {
logger.warn(`Have to reimport the account... (${e})`)
njsWallet = await getOrCreateWallet(
@@ -514,20 +534,28 @@ export async function syncAccount({
let njsAccount
try {
- njsAccount = await njsWallet.getAccount(index)
+ njsAccount = await timeoutTagged('getAccount', 10000, njsWallet.getAccount(index))
} catch (e) {
logger.warn(`Have to recreate the account... (${e.message})`)
- const extendedInfos = await njsWallet.getExtendedKeyAccountCreationInfo(index)
+ const extendedInfos = await timeoutTagged(
+ 'getEKACI',
+ 10000,
+ njsWallet.getExtendedKeyAccountCreationInfo(index),
+ )
extendedInfos.extendedKeys.push(decodedAccountId.xpub)
- njsAccount = await njsWallet.newAccountWithExtendedKeyInfo(extendedInfos)
+ njsAccount = await timeoutTagged(
+ 'newAWEKI',
+ 10000,
+ njsWallet.newAccountWithExtendedKeyInfo(extendedInfos),
+ )
}
- const unsub = await coreSyncAccount(core, njsAccount)
+ const unsub = await timeoutTagged('coreSyncAccount', 30000, coreSyncAccount(core, njsAccount))
unsub()
const query = njsAccount.queryOperations()
- const ops = await query.complete().execute()
- const njsBalance = await njsAccount.getBalance()
+ const ops = await timeoutTagged('ops', 30000, query.complete().execute())
+ const njsBalance = await timeoutTagged('getBalance', 10000, njsAccount.getBalance())
const syncedRawAccount = await buildAccountRaw({
njsAccount,
diff --git a/src/helpers/linking.js b/src/helpers/linking.js
index e810f123..36855a21 100644
--- a/src/helpers/linking.js
+++ b/src/helpers/linking.js
@@ -1,12 +1,17 @@
// @flow
-import { shell } from 'electron'
import { track } from 'analytics/segment'
+let shell
+if (!process.env.STORYBOOK_ENV) {
+ const electron = require('electron')
+ shell = electron.shell
+}
+
export const openURL = (
url: string,
customEventName: string = 'OpenURL',
extraParams: Object = {},
) => {
track(customEventName, { ...extraParams, url })
- shell.openExternal(url)
+ shell && shell.openExternal(url)
}
diff --git a/src/helpers/promise.js b/src/helpers/promise.js
index 529fdb23..7a0d7676 100644
--- a/src/helpers/promise.js
+++ b/src/helpers/promise.js
@@ -2,6 +2,7 @@
// small utilities for Promises
import logger from 'logger'
+import { TimeoutTagged } from 'config/errors'
export const delay = (ms: number): Promise => new Promise(f => setTimeout(f, ms))
@@ -65,6 +66,23 @@ export function createCancelablePolling(
return { unsubscribe, promise }
}
+export const timeoutTagged = (tag: string, delay: number, promise: Promise): Promise =>
+ new Promise((resolve, reject) => {
+ const timeout = setTimeout(() => {
+ reject(new TimeoutTagged('timeout', { tag }))
+ }, delay)
+ promise.then(
+ r => {
+ clearTimeout(timeout)
+ resolve(r)
+ },
+ e => {
+ clearTimeout(timeout)
+ reject(e)
+ },
+ )
+ })
+
export const promisify = (fn: any) => (...args: any) =>
new Promise((resolve, reject) =>
fn(...args, (err: Error, res: any) => {
diff --git a/src/renderer/init.js b/src/renderer/init.js
index 52fd35f7..4f7278df 100644
--- a/src/renderer/init.js
+++ b/src/renderer/init.js
@@ -12,7 +12,6 @@ import { runMigrations } from 'migrations'
import createStore from 'renderer/createStore'
import events from 'renderer/events'
-import { LEDGER_RESET_ALL } from 'config/constants'
import { enableGlobalTab, disableGlobalTab, isGlobalTabEnabled } from 'config/global-tab'
import { fetchAccounts } from 'actions/accounts'
@@ -25,7 +24,6 @@ import resolveUserDataDirectory from 'helpers/resolveUserDataDirectory'
import db from 'helpers/db'
import dbMiddleware from 'middlewares/db'
import CounterValues from 'helpers/countervalues'
-import hardReset from 'helpers/hardReset'
import { decodeAccountsModel, encodeAccountsModel } from 'reducers/accounts'
@@ -43,10 +41,6 @@ const TAB_KEY = 9
db.init(userDataDirectory)
async function init() {
- if (LEDGER_RESET_ALL) {
- await hardReset()
- }
-
await runMigrations()
db.init(userDataDirectory)
db.registerTransform('app', 'accounts', { get: decodeAccountsModel, set: encodeAccountsModel })
diff --git a/static/i18n/en/app.json b/static/i18n/en/app.json
index cbed0f97..4584fa6b 100644
--- a/static/i18n/en/app.json
+++ b/static/i18n/en/app.json
@@ -196,7 +196,7 @@
"successDescription_plural": "Your accounts have been created.",
"createNewAccount": {
"title": "Add a new account",
- "noOperationOnLastAccount": "No transactions found on your last new account <1><0>{{accountName}}0>1>. You can add a new account after you've started transacting on that account.",
+ "noOperationOnLastAccount": "There are no transactions on your last created <1><0>{{accountName}}0>1> account. You must first receive crypto assets on that account before you can add a new one.",
"noAccountToCreate": "No <1><0>{{currencyName}}0>1> account was found to create"
},
"cta": {
@@ -399,7 +399,7 @@
},
"softResetModal": {
"title": "Clear cache",
- "desc": "Clearing the Ledger Live cache forces network resynchronization"
+ "desc": "Clearing the Ledger Live cache forces network resynchronization. Your settings and accounts are not affected. The private keys to access your crypto assets in the blockchain remain secure on your Ledger device and on your Recovery sheet."
},
"removeAccountModal": {
"title": "Remove account",
@@ -459,4 +459,4 @@
"desc_2": "Please beware that Ledger does not provide financial, tax, or legal advice. You should take such decisions on your own or consult with reliable experts.",
"cta": "Got it"
}
-}
\ No newline at end of file
+}
diff --git a/static/i18n/en/errors.json b/static/i18n/en/errors.json
index 2249bec7..154b6da5 100644
--- a/static/i18n/en/errors.json
+++ b/static/i18n/en/errors.json
@@ -115,6 +115,10 @@
"title": "Oops, a time out occurred",
"description": "It took too long for the server to respond."
},
+ "TimeoutTagged": {
+ "title": "Oops, a time out occurred ({{tag}})",
+ "description": "It took too long for the server to respond."
+ },
"TransportError": {
"title": "Something went wrong. Please reconnect your device.",
"description": "{{message}}"