mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-01-12 03:54:13 +00:00
Merge branch 'develop' of github.com:MyCryptoHQ/MyCrypto into develop
This commit is contained in:
commit
a67f18122f
52
common/components/Errorable.tsx
Normal file
52
common/components/Errorable.tsx
Normal 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);
|
@ -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,6 +272,13 @@ const WalletDecrypt = withRouter<Props>(
|
||||
{!selectedWallet.isReadOnly && 'Unlock your'} {translate(selectedWallet.lid)}
|
||||
</h2>
|
||||
<section className="WalletDecrypt-decrypt-form">
|
||||
<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}
|
||||
@ -292,6 +300,7 @@ const WalletDecrypt = withRouter<Props>(
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</Errorable>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
@ -381,13 +390,15 @@ const WalletDecrypt = withRouter<Props>(
|
||||
}
|
||||
|
||||
let timeout = 0;
|
||||
if (wallet.attemptUnlock) {
|
||||
const web3Available = await isWeb3NodeAvailable();
|
||||
if (wallet.attemptUnlock && web3Available) {
|
||||
if (web3Available) {
|
||||
// timeout is only the maximum wait time before secondary view is shown
|
||||
// send view will be shown immediately on web3 resolve
|
||||
timeout = 1000;
|
||||
timeout = 1500;
|
||||
wallet.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
this.setState({
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
|
@ -160,6 +160,7 @@ export function* handleNodeChangeIntent({
|
||||
);
|
||||
}
|
||||
|
||||
const isOffline = yield select(getOffline);
|
||||
if (isAutoNode(nodeIdToSwitchTo)) {
|
||||
shepherd.auto();
|
||||
if (getShepherdNetwork() !== nextNodeConfig.network) {
|
||||
@ -167,20 +168,22 @@ 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) {
|
||||
if (!isOffline) {
|
||||
console.error(err);
|
||||
return yield* bailOut(translateRaw('ERROR_32'));
|
||||
}
|
||||
}
|
||||
|
||||
yield put(setLatestBlock(currentBlock));
|
||||
yield put(changeNode({ networkId: nextNodeConfig.network, nodeId: nodeIdToSwitchTo }));
|
||||
|
@ -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])
|
||||
);
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user