1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-25 03:20:23 +01:00

Fix #18984 - UX: Multichain - Network connection fixes (#19000)

This commit is contained in:
David Walsh 2023-05-05 09:02:28 -05:00 committed by GitHub
parent 33f9d6f480
commit 67dbac6b0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 146 additions and 54 deletions

View File

@ -2346,6 +2346,10 @@
"message": "Gas fees are $1 relative to the past 72 hours.",
"description": "$1 is networks stability value - stable, low, high"
},
"networkSwitchConnectionError": {
"message": "We can't connect to $1",
"description": "$1 represents the network name"
},
"networkURL": {
"message": "Network URL"
},

View File

@ -1,9 +1,24 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Button from '../../ui/button';
import LoadingScreen from '../../ui/loading-screen';
import { SECOND } from '../../../../shared/constants/time';
import { NETWORK_TYPES } from '../../../../shared/constants/network';
import Popover from '../../ui/popover/popover.component';
import {
ButtonPrimary,
ButtonSecondary,
Icon,
IconName,
IconSize,
Text,
} from '../../component-library';
import {
DISPLAY,
IconColor,
TextAlign,
TextVariant,
} from '../../../helpers/constants/design-system';
import Box from '../../ui/box/box';
export default class LoadingNetworkScreen extends PureComponent {
state = {
@ -56,63 +71,76 @@ export default class LoadingNetworkScreen extends PureComponent {
}
};
renderDeprecatedRpcUrlWarning = () => {
const { showNetworkDropdown } = this.props;
return (
<div className="loading-overlay__error-screen">
<span className="loading-overlay__emoji">&#128542;</span>
<span>{this.context.t('currentRpcUrlDeprecated')}</span>
<div className="loading-overlay__error-buttons">
<Button
type="secondary"
onClick={() => {
window.clearTimeout(this.cancelCallTimeout);
showNetworkDropdown();
}}
>
{this.context.t('switchNetworks')}
</Button>
</div>
</div>
);
};
renderErrorScreenContent = () => {
renderConnectionFailureNotification = (message, showTryAgain = false) => {
const { showNetworkDropdown, setProviderArgs, setProviderType } =
this.props;
return (
<div className="loading-overlay__error-screen">
<span className="loading-overlay__emoji">&#128542;</span>
<span>{this.context.t('somethingWentWrong')}</span>
<div className="loading-overlay__error-buttons">
<Button
type="secondary"
<Popover
onClose={() => {
window.clearTimeout(this.cancelCallTimeout);
}}
centerTitle
title={
<Icon
name={IconName.Danger}
size={IconSize.Xl}
color={IconColor.warningDefault}
/>
}
>
<Text
variant={TextVariant.bodyLgMedium}
textAlign={TextAlign.Center}
margin={[0, 4, 4, 4]}
>
{message}
</Text>
<Box display={DISPLAY.FLEX} padding={4} gap={2}>
<ButtonSecondary
onClick={() => {
window.clearTimeout(this.cancelCallTimeout);
showNetworkDropdown();
}}
variant={TextVariant.bodySm}
block
>
{this.context.t('switchNetworks')}
</Button>
</ButtonSecondary>
{showTryAgain ? (
<ButtonPrimary
onClick={() => {
this.setState({ showErrorScreen: false });
setProviderType(...setProviderArgs);
window.clearTimeout(this.cancelCallTimeout);
this.cancelCallTimeout = setTimeout(
this.cancelCall,
this.props.cancelTime || SECOND * 15,
);
}}
variant={TextVariant.bodySm}
block
>
{this.context.t('tryAgain')}
</ButtonPrimary>
) : null}
</Box>
</Popover>
);
};
<Button
type="primary"
onClick={() => {
this.setState({ showErrorScreen: false });
setProviderType(...setProviderArgs);
window.clearTimeout(this.cancelCallTimeout);
this.cancelCallTimeout = setTimeout(
this.cancelCall,
this.props.cancelTime || SECOND * 15,
);
}}
>
{this.context.t('tryAgain')}
</Button>
</div>
</div>
renderDeprecatedRpcUrlWarning = () => {
return this.renderConnectionFailureNotification(
this.context.t('currentRpcUrlDeprecated'),
false,
);
};
renderErrorScreenContent = () => {
const { providerConfig } = this.props;
return this.renderConnectionFailureNotification(
this.context.t('networkSwitchConnectionError', [providerConfig.nickname]),
true,
);
};

View File

@ -1,7 +1,11 @@
import { connect } from 'react-redux';
import { NETWORK_TYPES } from '../../../../shared/constants/network';
import * as actions from '../../../store/actions';
import { getNetworkIdentifier, isNetworkLoading } from '../../../selectors';
import {
getAllEnabledNetworks,
getNetworkIdentifier,
isNetworkLoading,
} from '../../../selectors';
import { getProviderConfig } from '../../../ducks/metamask/metamask';
import LoadingNetworkScreen from './loading-network-screen.component';
@ -21,11 +25,27 @@ const mapStateToProps = (state) => {
const isInfuraRpcUrl = rpcUrl && new URL(rpcUrl).host.endsWith('.infura.io');
const showDeprecatedRpcUrlWarning = isDeprecatedNetwork && isInfuraRpcUrl;
// Ensure we have a nickname to provide the user
// in case of connection error
let networkName = nickname;
if (networkName === undefined) {
const networks = getAllEnabledNetworks(state);
const desiredNetwork = networks.find(
(network) => network.chainId === chainId,
);
if (desiredNetwork) {
networkName = desiredNetwork.nickname;
}
}
return {
isNetworkLoading: isNetworkLoading(state),
loadingMessage,
setProviderArgs,
providerConfig,
providerConfig: {
...providerConfig,
nickname: networkName,
},
providerId: getNetworkIdentifier(state),
showDeprecatedRpcUrlWarning,
};
@ -38,7 +58,12 @@ const mapDispatchToProps = (dispatch) => {
},
rollbackToPreviousProvider: () =>
dispatch(actions.rollbackToPreviousProvider()),
showNetworkDropdown: () => dispatch(actions.showNetworkDropdown()),
showNetworkDropdown: () => {
if (process.env.MULTICHAIN) {
return dispatch(actions.toggleNetworkMenu());
}
return dispatch(actions.showNetworkDropdown());
},
};
};

View File

@ -11,12 +11,14 @@ import {
setShowTestNetworks,
setProviderType,
toggleNetworkMenu,
upsertNetworkConfiguration,
} from '../../../store/actions';
import { CHAIN_IDS, TEST_CHAINS } from '../../../../shared/constants/network';
import {
getShowTestNetworks,
getAllEnabledNetworks,
getCurrentChainId,
getNetworkConfigurations,
} from '../../../selectors';
import Box from '../../ui/box/box';
import ToggleButton from '../../ui/toggle-button';
@ -32,6 +34,7 @@ import { MetaMetricsContext } from '../../../contexts/metametrics';
import {
MetaMetricsEventCategory,
MetaMetricsEventName,
MetaMetricsNetworkEventSource,
} from '../../../../shared/constants/metametrics';
const UNREMOVABLE_CHAIN_IDS = [CHAIN_IDS.MAINNET, ...TEST_CHAINS];
@ -40,6 +43,7 @@ export const NetworkListMenu = ({ onClose }) => {
const t = useI18nContext();
const networks = useSelector(getAllEnabledNetworks);
const showTestNetworks = useSelector(getShowTestNetworks);
const networkConfigurations = useSelector(getNetworkConfigurations);
const currentChainId = useSelector(getCurrentChainId);
const dispatch = useDispatch();
const history = useHistory();
@ -75,12 +79,34 @@ export const NetworkListMenu = ({ onClose }) => {
iconSrc={network?.rpcPrefs?.imageUrl}
key={network.id || network.chainId}
selected={isCurrentNetwork}
onClick={() => {
onClick={async () => {
dispatch(toggleNetworkMenu());
if (network.providerType) {
dispatch(setProviderType(network.providerType));
} else {
dispatch(setActiveNetwork(network.id));
// Linea needs to be added as a custom network because
// it is not yet supported by Infura. The following lazily
// adds Linea to the custom network configurations object
let networkId = network.id;
if (network.chainId === CHAIN_IDS.LINEA_TESTNET) {
const lineaNetworkConfiguration = Object.values(
networkConfigurations,
).find(
({ chainId }) => chainId === CHAIN_IDS.LINEA_TESTNET,
);
if (lineaNetworkConfiguration) {
networkId = lineaNetworkConfiguration.id;
} else {
networkId = await dispatch(
upsertNetworkConfiguration(network, {
setActive: true,
source:
MetaMetricsNetworkEventSource.CustomNetworkForm,
}),
);
}
}
dispatch(setActiveNetwork(networkId));
}
trackEvent({
event: MetaMetricsEventName.NavNetworkSwitched,

View File

@ -29,6 +29,8 @@ import {
GOERLI_DISPLAY_NAME,
ETH_TOKEN_IMAGE_URL,
LINEA_TESTNET_DISPLAY_NAME,
CURRENCY_SYMBOLS,
TEST_NETWORK_TICKER_MAP,
} from '../../shared/constants/network';
import {
WebHIDConnectedStatuses,
@ -1180,13 +1182,18 @@ export function getAllNetworks(state) {
imageUrl: ETH_TOKEN_IMAGE_URL,
},
providerType: NETWORK_TYPES.MAINNET,
ticker: CURRENCY_SYMBOLS.ETH,
});
// Custom networks added
networks.push(
...Object.entries(networkConfigurations)
.filter(
([, network]) =>
!localhostFilter(network) && network.chainId !== CHAIN_IDS.MAINNET,
!localhostFilter(network) &&
network.chainId !== CHAIN_IDS.MAINNET &&
// Linea gets added as a custom network configuration so
// we must ignore it here to display in test networks
network.chainId !== CHAIN_IDS.LINEA_TESTNET,
)
.map(([, network]) => network),
);
@ -1198,18 +1205,20 @@ export function getAllNetworks(state) {
nickname: GOERLI_DISPLAY_NAME,
rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.GOERLI],
providerType: NETWORK_TYPES.GOERLI,
ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.GOERLI],
},
{
chainId: CHAIN_IDS.SEPOLIA,
nickname: SEPOLIA_DISPLAY_NAME,
rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.SEPOLIA],
providerType: NETWORK_TYPES.SEPOLIA,
ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA],
},
{
chainId: CHAIN_IDS.LINEA_TESTNET,
nickname: LINEA_TESTNET_DISPLAY_NAME,
rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_TESTNET],
provderType: NETWORK_TYPES.LINEA_TESTNET,
ticker: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.LINEA_TESTNET],
},
], // Localhosts
...Object.entries(networkConfigurations)