From df2c3bc7fdcb7e0d9073de6fad639ef453fc8464 Mon Sep 17 00:00:00 2001 From: HenryNguyen5 Date: Thu, 26 Apr 2018 02:26:37 -0400 Subject: [PATCH 1/4] Add Error Boundary to Parity Signer (#1675) * add jenkins config for mac signing (#1666) * More RC Bugfixes (#1670) * add jenkins config for mac signing (#1664) * Fix #1653 * Fix #1648 * Fix #1638 * Fix test * Electron Alpha Prep (#1671) * Adjust update flow to not auto update, not publish in CI * Revert "Adjust update flow to not auto update, not publish in CI" This reverts commit 74fb382ce8d8cd9e227703ccfa8d6310bffd9dda. * First pass at new app version modal * Added app alpha notice that either warns you about alpha, or blocks the whole app. * Improve newer version detection, add unit tests * Remove native auto update behavior * add jenkins config for mac signing (#1664) * Notice once per session * copy changes per PR review * More RC Bugfixes (#1669) * Fix #1653 * Fix #1648 * Fix #1638 * Fix test * Add errorable component * Fix lint * Change instance order --- common/components/Errorable.tsx | 52 +++++++++++++++++++ .../WalletDecrypt/WalletDecrypt.tsx | 49 ++++++++++------- common/components/index.ts | 1 + 3 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 common/components/Errorable.tsx diff --git a/common/components/Errorable.tsx b/common/components/Errorable.tsx new file mode 100644 index 00000000..4c3c8b1f --- /dev/null +++ b/common/components/Errorable.tsx @@ -0,0 +1,52 @@ +import { showNotification, TShowNotification } from 'actions/notifications'; +import { connect } from 'react-redux'; +import React from 'react'; + +interface DispatchProps { + showNotification: TShowNotification; +} + +interface OwnProps { + /** + * Optional custom error message to display when a error is caught, otherwise the + * actual error message is displayed to the user + */ + errorMessage?: string; + /** + * Optional should catch condition, if left undefined then the component will by default + * catch all errors, if false, then the component will not catch errors, if true, + * the component will catch errors + */ + shouldCatch?: boolean; + + /** + * Optional callback handler when an error is encountered and this component + * should catch it + */ + onError?(): void; +} + +type Props = DispatchProps & OwnProps; + +class ErrorBoundary extends React.Component { + public componentDidCatch(error: Error, info: any) { + console.error(error); + console.error(info); + const { errorMessage, onError, shouldCatch } = this.props; + + if (shouldCatch === false) { + throw error; + } + + this.props.showNotification('danger', errorMessage || error.message); + if (onError) { + onError(); + } + } + + public render() { + return this.props.children; + } +} + +export default connect(null, { showNotification })(ErrorBoundary); diff --git a/common/components/WalletDecrypt/WalletDecrypt.tsx b/common/components/WalletDecrypt/WalletDecrypt.tsx index 7907f571..7971aebe 100644 --- a/common/components/WalletDecrypt/WalletDecrypt.tsx +++ b/common/components/WalletDecrypt/WalletDecrypt.tsx @@ -52,6 +52,7 @@ import ParitySignerIcon from 'assets/images/wallets/parity-signer.svg'; import { wikiLink as paritySignerHelpLink } from 'libs/wallet/non-deterministic/parity'; import './WalletDecrypt.scss'; import { withRouter, RouteComponentProps } from 'react-router'; +import { Errorable } from 'components'; interface OwnProps { hidden?: boolean; @@ -271,27 +272,35 @@ const WalletDecrypt = withRouter( {!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
- { - if (selectedWallet.redirect) { - this.props.history.push(selectedWallet.redirect); + + { + if (selectedWallet.redirect) { + this.props.history.push(selectedWallet.redirect); + } + this.onUnlock(value); + }} + showNotification={this.props.showNotification} + isWalletPending={ + this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE + ? this.props.isWalletPending + : undefined } - this.onUnlock(value); - }} - showNotification={this.props.showNotification} - isWalletPending={ - this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE - ? this.props.isWalletPending - : undefined - } - isPasswordPending={ - this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE - ? this.props.isPasswordPending - : undefined - } - /> + isPasswordPending={ + this.state.selectedWalletKey === InsecureWalletName.KEYSTORE_FILE + ? this.props.isPasswordPending + : undefined + } + /> +
); diff --git a/common/components/index.ts b/common/components/index.ts index 99b79863..4543dfbc 100644 --- a/common/components/index.ts +++ b/common/components/index.ts @@ -22,4 +22,5 @@ export { default as GenerateKeystoreModal } from './GenerateKeystoreModal'; export { default as TransactionStatus } from './TransactionStatus'; export { default as ParityQrSigner } from './ParityQrSigner'; export { default as ElectronNav } from './ElectronNav'; +export { default as Errorable } from './Errorable'; export { default as AppAlphaNotice } from './AppAlphaNotice'; From 4f6dde23c0aa5f1565d5659be8e2d0427e6f5d71 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Thu, 26 Apr 2018 14:19:54 -0400 Subject: [PATCH 2/4] Render Falsey Contract Outputs (#1684) --- .../components/Interact/components/InteractExplorer/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/containers/Tabs/Contracts/components/Interact/components/InteractExplorer/index.tsx b/common/containers/Tabs/Contracts/components/Interact/components/InteractExplorer/index.tsx index 1ab39872..ae8277e6 100644 --- a/common/containers/Tabs/Contracts/components/Interact/components/InteractExplorer/index.tsx +++ b/common/containers/Tabs/Contracts/components/Interact/components/InteractExplorer/index.tsx @@ -127,7 +127,8 @@ class InteractExplorerClass extends Component { {selectedFunction.contract.outputs.map((output: any, index: number) => { const { type, name } = output; const parsedName = name === '' ? index : name; - const rawFieldValue = outputs[parsedName] || ''; + const o = outputs[parsedName]; + const rawFieldValue = o === null || o === undefined ? '' : o; const decodedFieldValue = Buffer.isBuffer(rawFieldValue) ? bufferToHex(rawFieldValue) : rawFieldValue; From 5733833f5e48e7fda9305fe79bb570fd58f1380a Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Thu, 26 Apr 2018 14:24:28 -0400 Subject: [PATCH 3/4] Wallet Selection Optimization (#1680) --- common/components/WalletDecrypt/WalletDecrypt.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/common/components/WalletDecrypt/WalletDecrypt.tsx b/common/components/WalletDecrypt/WalletDecrypt.tsx index 7971aebe..7fbe7489 100644 --- a/common/components/WalletDecrypt/WalletDecrypt.tsx +++ b/common/components/WalletDecrypt/WalletDecrypt.tsx @@ -390,12 +390,14 @@ const WalletDecrypt = withRouter( } let timeout = 0; - const web3Available = await isWeb3NodeAvailable(); - if (wallet.attemptUnlock && web3Available) { - // timeout is only the maximum wait time before secondary view is shown - // send view will be shown immediately on web3 resolve - timeout = 1000; - wallet.unlock(); + if (wallet.attemptUnlock) { + const web3Available = await isWeb3NodeAvailable(); + if (web3Available) { + // timeout is only the maximum wait time before secondary view is shown + // send view will be shown immediately on web3 resolve + timeout = 1500; + wallet.unlock(); + } } window.setTimeout(() => { From 82e0530bec5f2c08e8535c4034b2a14eab157c47 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Thu, 26 Apr 2018 23:55:31 -0400 Subject: [PATCH 4/4] Allow Network Change Offline (#1683) * Allow changing to offline node when currently offline * Fix tests --- common/sagas/config/node.ts | 11 +++++++---- spec/reducers/config/config.spec.ts | 22 +++++++++++++--------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/common/sagas/config/node.ts b/common/sagas/config/node.ts index a394833b..39ba5c4e 100644 --- a/common/sagas/config/node.ts +++ b/common/sagas/config/node.ts @@ -160,6 +160,7 @@ export function* handleNodeChangeIntent({ ); } + const isOffline = yield select(getOffline); if (isAutoNode(nodeIdToSwitchTo)) { shepherd.auto(); if (getShepherdNetwork() !== nextNodeConfig.network) { @@ -167,19 +168,21 @@ export function* handleNodeChangeIntent({ } } else { try { - yield apply(shepherd, shepherd.manual, [nodeIdToSwitchTo, false]); + yield apply(shepherd, shepherd.manual, [nodeIdToSwitchTo, isOffline]); } catch (err) { console.error(err); return yield* bailOut(translateRaw('ERROR_32')); } } - let currentBlock; + let currentBlock = '???'; try { currentBlock = yield apply(shepherdProvider, shepherdProvider.getCurrentBlock); } catch (err) { - console.error(err); - return yield* bailOut(translateRaw('ERROR_32')); + if (!isOffline) { + console.error(err); + return yield* bailOut(translateRaw('ERROR_32')); + } } yield put(setLatestBlock(currentBlock)); diff --git a/spec/reducers/config/config.spec.ts b/spec/reducers/config/config.spec.ts index 6e34ece4..dc19a322 100644 --- a/spec/reducers/config/config.spec.ts +++ b/spec/reducers/config/config.spec.ts @@ -133,7 +133,7 @@ describe('handleNodeChangeIntent*', () => { : acc ); const newNodeConfig: StaticNodeConfig = (staticNodesExpectedState as any).initialState[newNodeId]; - + const isOffline = false; const changeNodeIntentAction = changeNodeIntent(newNodeId); const latestBlock = '0xa'; @@ -174,21 +174,25 @@ describe('handleNodeChangeIntent*', () => { expect(data.gen.next(newNodeConfig).value).toMatchSnapshot(); }); - it('should show error and revert to previous node if check times out', () => { - data.clone1 = data.gen.clone(); - data.clone1.next(true); - expect(data.clone1.throw('err').value).toEqual(select(getNodeId)); - expect(data.clone1.next(defaultNodeId).value).toEqual( + it('should select isOffline', () => { + expect(data.gen.next(true).value).toEqual(select(getOffline)); + }); + + it('should show error and revert to previous node if online check times out', () => { + data.nodeError = data.gen.clone(); + data.nodeError.next(isOffline); + expect(data.nodeError.throw('err').value).toEqual(select(getNodeId)); + expect(data.nodeError.next(defaultNodeId).value).toEqual( put(showNotification('danger', translateRaw('ERROR_32'), 5000)) ); - expect(data.clone1.next().value).toEqual( + expect(data.nodeError.next().value).toEqual( put(changeNode({ networkId: defaultNodeConfig.network, nodeId: defaultNodeId })) ); - expect(data.clone1.next().done).toEqual(true); + expect(data.nodeError.next().done).toEqual(true); }); it('should sucessfully switch to the manual node', () => { - expect(data.gen.next(latestBlock).value).toEqual( + expect(data.gen.next(isOffline).value).toEqual( apply(shepherd, shepherd.manual, [newNodeId, false]) ); });