Merge branch 'develop' of github.com:MyCryptoHQ/MyCrypto into develop

This commit is contained in:
HenryNguyen5 2018-04-27 14:42:41 -04:00
commit a67f18122f
6 changed files with 112 additions and 40 deletions

View File

@ -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<Props> {
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);

View File

@ -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<Props>(
{!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
</h2>
<section className="WalletDecrypt-decrypt-form">
<selectedWallet.component
value={this.state.value}
onChange={this.onChange}
onUnlock={(value: any) => {
if (selectedWallet.redirect) {
this.props.history.push(selectedWallet.redirect);
<Errorable
errorMessage={`Oops, looks like ${translateRaw(
selectedWallet.lid
)} is not supported by your browser`}
onError={this.clearWalletChoice}
shouldCatch={selectedWallet.lid === this.WALLETS.paritySigner.lid}
>
<selectedWallet.component
value={this.state.value}
onChange={this.onChange}
onUnlock={(value: any) => {
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
}
/>
</Errorable>
</section>
</div>
);
@ -381,12 +390,14 @@ const WalletDecrypt = withRouter<Props>(
}
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(() => {

View File

@ -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';

View File

@ -127,7 +127,8 @@ class InteractExplorerClass extends Component<Props, State> {
{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;

View File

@ -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));

View File

@ -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])
);
});