mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
Merge branch 'develop' of github.com:MetaMask/metamask-extension into minimal
This commit is contained in:
commit
c63ffe4f24
@ -2,82 +2,82 @@ export const suggestedAssets = [
|
||||
{
|
||||
asset: {
|
||||
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
symbol: 'META',
|
||||
symbol: 'ETH',
|
||||
decimals: 18,
|
||||
image: 'metamark.svg',
|
||||
unlisted: false
|
||||
image: './images/eth_logo.png',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0xB8c77482e45F1F44dE1745F52C74426C631bDD52',
|
||||
'symbol': '0X',
|
||||
'decimals': 18,
|
||||
'image': '0x.svg',
|
||||
'unlisted': false
|
||||
address: '0xB8c77482e45F1F44dE1745F52C74426C631bDD52',
|
||||
symbol: '0X',
|
||||
decimals: 18,
|
||||
image: '0x.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
|
||||
'symbol': 'AST',
|
||||
'decimals': 18,
|
||||
'image': 'ast.png',
|
||||
'unlisted': false
|
||||
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
|
||||
symbol: 'AST',
|
||||
decimals: 18,
|
||||
image: 'ast.png',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
|
||||
'symbol': 'BAT',
|
||||
'decimals': 18,
|
||||
'image': 'BAT_icon.svg',
|
||||
'unlisted': false
|
||||
address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
|
||||
symbol: 'BAT',
|
||||
decimals: 18,
|
||||
image: 'BAT_icon.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1',
|
||||
'symbol': 'CVL',
|
||||
'decimals': 18,
|
||||
'image': 'CVL_token.svg',
|
||||
'unlisted': false
|
||||
address: '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1',
|
||||
symbol: 'CVL',
|
||||
decimals: 18,
|
||||
image: 'CVL_token.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e',
|
||||
'symbol': 'GLA',
|
||||
'decimals': 18,
|
||||
'image': 'gladius.svg',
|
||||
'unlisted': false
|
||||
address: '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e',
|
||||
symbol: 'GLA',
|
||||
decimals: 18,
|
||||
image: 'gladius.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0x467Bccd9d29f223BcE8043b84E8C8B282827790F',
|
||||
'symbol': 'GNO',
|
||||
'decimals': 18,
|
||||
'image': 'gnosis.svg',
|
||||
'unlisted': false
|
||||
address: '0x467Bccd9d29f223BcE8043b84E8C8B282827790F',
|
||||
symbol: 'GNO',
|
||||
decimals: 18,
|
||||
image: 'gnosis.svg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0xff20817765cb7f73d4bde2e66e067e58d11095c2',
|
||||
'symbol': 'OMG',
|
||||
'decimals': 18,
|
||||
'image': 'omg.jpg',
|
||||
'unlisted': false
|
||||
address: '0xff20817765cb7f73d4bde2e66e067e58d11095c2',
|
||||
symbol: 'OMG',
|
||||
decimals: 18,
|
||||
image: 'omg.jpg',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
asset: {
|
||||
'address': '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
|
||||
'symbol': 'WED',
|
||||
'decimals': 18,
|
||||
'image': 'wed.png',
|
||||
'unlisted': false
|
||||
address: '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
|
||||
symbol: 'WED',
|
||||
decimals: 18,
|
||||
image: 'wed.png',
|
||||
unlisted: false,
|
||||
},
|
||||
},
|
||||
]
|
||||
];
|
||||
|
@ -172,9 +172,9 @@ const state = {
|
||||
},
|
||||
'0x6b175474e89094c44da98b954eedeac495271d0f': {
|
||||
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
|
||||
symbol: 'META',
|
||||
symbol: 'ETH',
|
||||
decimals: 18,
|
||||
image: 'metamark.svg',
|
||||
image: './images/eth_logo.png',
|
||||
unlisted: false,
|
||||
},
|
||||
'0xB8c77482e45F1F44dE1745F52C74426C631bDD52': {
|
||||
|
14
CHANGELOG.md
14
CHANGELOG.md
@ -6,6 +6,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [10.28.3]
|
||||
### Fixed
|
||||
- Fix network switching prompted by dapps for users that added the network prior to v10.28.0. ([#18513](https://github.com/MetaMask/metamask-extension/pull/18513))
|
||||
|
||||
## [10.28.2]
|
||||
### Fixed
|
||||
- Fix network switching prompted by dapps by fixing the `wallet_switchEthereumChain` handler. ([#18483](https://github.com/MetaMask/metamask-extension/pull/18483))
|
||||
- Fix to ensure all users see the NFT and transaction security notifications ([#18460](https://github.com/MetaMask/metamask-extension/pull/18460))
|
||||
- Fix issue blocking Hindi, Japanese and Turkish language users from installing from the Chrome store ([#18487](https://github.com/MetaMask/metamask-extension/pull/18487))
|
||||
|
||||
## [10.28.1]
|
||||
### Changed
|
||||
- Fix release automation ([#18427](https://github.com/MetaMask/metamask-extension/pull/18427))
|
||||
@ -3643,7 +3653,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Uncategorized
|
||||
- Added the ability to restore accounts from seed words.
|
||||
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.28.1...HEAD
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.28.3...HEAD
|
||||
[10.28.3]: https://github.com/MetaMask/metamask-extension/compare/v10.28.2...v10.28.3
|
||||
[10.28.2]: https://github.com/MetaMask/metamask-extension/compare/v10.28.1...v10.28.2
|
||||
[10.28.1]: https://github.com/MetaMask/metamask-extension/compare/v10.28.0...v10.28.1
|
||||
[10.28.0]: https://github.com/MetaMask/metamask-extension/compare/v10.27.0...v10.28.0
|
||||
[10.27.0]: https://github.com/MetaMask/metamask-extension/compare/v10.26.2...v10.27.0
|
||||
|
29
app/_locales/en/messages.json
generated
29
app/_locales/en/messages.json
generated
@ -2537,6 +2537,19 @@
|
||||
"message": "Swapping on mobile is here!",
|
||||
"description": "Title for a notification in the 'See What's New' popup. Tells users that they can now use MetaMask Swaps on Mobile."
|
||||
},
|
||||
"notifications20ActionText": {
|
||||
"message": "Learn more",
|
||||
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a ledger page to resolve the U2F connection issue."
|
||||
},
|
||||
|
||||
"notifications20Description": {
|
||||
"message": "If you're on the latest version of Firefox, you might be experiencing an issue related to Firefox dropping U2F support.",
|
||||
"description": "Description of a notification in the 'See What's New' popup. Describes the U2F support being dropped by firefox and that it affects ledger users."
|
||||
},
|
||||
"notifications20Title": {
|
||||
"message": "Ledger and Firefox Users Experiencing Connection Issues",
|
||||
"description": "Title for a notification in the 'See What's New' popup. Tells users that latest firefox users using U2F may experience connection issues."
|
||||
},
|
||||
"notifications3ActionText": {
|
||||
"message": "Read more",
|
||||
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website."
|
||||
@ -4541,6 +4554,22 @@
|
||||
"transferFrom": {
|
||||
"message": "Transfer from"
|
||||
},
|
||||
"troubleConnectingToLedgerU2FOnFirefox": {
|
||||
"message": "We're having trouble connecting your Ledger. $1",
|
||||
"description": "$1 is a link to the wallet connection guide;"
|
||||
},
|
||||
"troubleConnectingToLedgerU2FOnFirefox2": {
|
||||
"message": "Review our hardware wallet connection guide and try again.",
|
||||
"description": "$1 of the ledger wallet connection guide"
|
||||
},
|
||||
"troubleConnectingToLedgerU2FOnFirefoxLedgerSolution": {
|
||||
"message": "If you're on the latest version of Firefox, you might be experiencing an issue related to Firefox dropping U2F support. Learn how to fix this issue $1.",
|
||||
"description": "It is a link to the ledger website for the workaround."
|
||||
},
|
||||
"troubleConnectingToLedgerU2FOnFirefoxLedgerSolution2": {
|
||||
"message": "here",
|
||||
"description": "Second part of the error message; It is a link to the ledger website for the workaround."
|
||||
},
|
||||
"troubleConnectingToWallet": {
|
||||
"message": "We had trouble connecting to your $1, try reviewing $2 and try again.",
|
||||
"description": "$1 is the wallet device name; $2 is a link to wallet connection guide"
|
||||
|
BIN
app/images/eth_logo.png
Normal file
BIN
app/images/eth_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
@ -1,18 +0,0 @@
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#343434;}
|
||||
.st1{fill:#8C8C8C;}
|
||||
.st2{fill:#3C3C3B;}
|
||||
.st3{fill:#141414;}
|
||||
.st4{fill:#393939;}
|
||||
</style>
|
||||
<g id="XMLID_1_">
|
||||
<polygon id="XMLID_2_" class="st0" points="250,67.5 247.5,75.8 247.5,317.2 250,319.6 362,253.4 "/>
|
||||
<polygon id="XMLID_3_" class="st1" points="250,67.5 137.9,253.4 250,319.6 250,202.5 "/>
|
||||
<polygon id="XMLID_4_" class="st2" points="250,340.8 248.6,342.5 248.6,428.5 250,432.5 362.1,274.6 "/>
|
||||
<polygon id="XMLID_5_" class="st1" points="250,432.5 250,340.8 137.9,274.6 "/>
|
||||
<polygon id="XMLID_6_" class="st3" points="250,319.6 362,253.4 250,202.5 "/>
|
||||
<polygon id="XMLID_7_" class="st4" points="137.9,253.4 250,319.6 250,202.5 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 919 B |
@ -6740,7 +6740,7 @@ describe('NetworkController', () => {
|
||||
it('throws if the given chain ID is not a 0x-prefixed hex number', async () => {
|
||||
const invalidChainId = '1';
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
controller.upsertNetworkConfiguration(
|
||||
{
|
||||
/* @ts-expect-error We are intentionally passing bad input. */
|
||||
@ -6755,7 +6755,7 @@ describe('NetworkController', () => {
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
},
|
||||
),
|
||||
).toThrow(
|
||||
).rejects.toThrow(
|
||||
new Error(
|
||||
`Invalid chain ID "${invalidChainId}": invalid hex string.`,
|
||||
),
|
||||
@ -6765,7 +6765,7 @@ describe('NetworkController', () => {
|
||||
|
||||
it('throws if the given chain ID is greater than the maximum allowed ID', async () => {
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
controller.upsertNetworkConfiguration(
|
||||
{
|
||||
chainId: '0xFFFFFFFFFFFFFFFF',
|
||||
@ -6779,7 +6779,7 @@ describe('NetworkController', () => {
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
},
|
||||
),
|
||||
).toThrow(
|
||||
).rejects.toThrow(
|
||||
new Error(
|
||||
'Invalid chain ID "0xFFFFFFFFFFFFFFFF": numerical value greater than max safe value.',
|
||||
),
|
||||
@ -6789,7 +6789,7 @@ describe('NetworkController', () => {
|
||||
|
||||
it('throws if the no (or a falsy) rpcUrl is passed', async () => {
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
controller.upsertNetworkConfiguration(
|
||||
/* @ts-expect-error We are intentionally passing bad input. */
|
||||
{
|
||||
@ -6803,7 +6803,7 @@ describe('NetworkController', () => {
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
},
|
||||
),
|
||||
).toThrow(
|
||||
).rejects.toThrow(
|
||||
new Error(
|
||||
'An rpcUrl is required to add or update network configuration',
|
||||
),
|
||||
@ -6813,7 +6813,7 @@ describe('NetworkController', () => {
|
||||
|
||||
it('throws if rpcUrl passed is not a valid Url', async () => {
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
controller.upsertNetworkConfiguration(
|
||||
{
|
||||
chainId: '0x9999',
|
||||
@ -6827,13 +6827,13 @@ describe('NetworkController', () => {
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
},
|
||||
),
|
||||
).toThrow(new Error('rpcUrl must be a valid URL'));
|
||||
).rejects.toThrow(new Error('rpcUrl must be a valid URL'));
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if the no (or a falsy) ticker is passed', async () => {
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
controller.upsertNetworkConfiguration(
|
||||
/* @ts-expect-error We are intentionally passing bad input. */
|
||||
{
|
||||
@ -6847,7 +6847,7 @@ describe('NetworkController', () => {
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
},
|
||||
),
|
||||
).toThrow(
|
||||
).rejects.toThrow(
|
||||
new Error(
|
||||
'A ticker is required to add or update networkConfiguration',
|
||||
),
|
||||
@ -6857,7 +6857,7 @@ describe('NetworkController', () => {
|
||||
|
||||
it('throws if an options object is not passed as a second argument', async () => {
|
||||
await withController(async ({ controller }) => {
|
||||
expect(() =>
|
||||
await expect(() =>
|
||||
/* @ts-expect-error We are intentionally passing bad input. */
|
||||
controller.upsertNetworkConfiguration({
|
||||
chainId: '0x5',
|
||||
@ -6865,7 +6865,7 @@ describe('NetworkController', () => {
|
||||
rpcPrefs: { blockExplorerUrl: 'test-block-explorer.com' },
|
||||
rpcUrl: 'https://mock-rpc-url',
|
||||
}),
|
||||
).toThrow(
|
||||
).rejects.toThrow(
|
||||
new Error(
|
||||
"Cannot read properties of undefined (reading 'setActive')",
|
||||
),
|
||||
@ -6888,7 +6888,7 @@ describe('NetworkController', () => {
|
||||
ticker: 'test_ticker',
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
await controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -6926,7 +6926,7 @@ describe('NetworkController', () => {
|
||||
invalidKey2: {},
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
await controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -6975,7 +6975,7 @@ describe('NetworkController', () => {
|
||||
ticker: 'RPC',
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
await controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -7024,7 +7024,7 @@ describe('NetworkController', () => {
|
||||
rpcPrefs: { blockExplorerUrl: 'alternativetestchainscan.io' },
|
||||
chainId: '0x1' as const,
|
||||
};
|
||||
controller.upsertNetworkConfiguration(updatedConfiguration, {
|
||||
await controller.upsertNetworkConfiguration(updatedConfiguration, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -7069,7 +7069,7 @@ describe('NetworkController', () => {
|
||||
},
|
||||
},
|
||||
async ({ controller }) => {
|
||||
controller.upsertNetworkConfiguration(
|
||||
await controller.upsertNetworkConfiguration(
|
||||
{
|
||||
rpcUrl: 'https://test-rpc-url',
|
||||
ticker: 'new-ticker',
|
||||
@ -7136,7 +7136,7 @@ describe('NetworkController', () => {
|
||||
ticker: 'test_ticker',
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
await controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -7180,7 +7180,7 @@ describe('NetworkController', () => {
|
||||
ticker: 'test_ticker',
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
await controller.upsertNetworkConfiguration(rpcUrlNetwork, {
|
||||
setActive: true,
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
@ -7229,7 +7229,7 @@ describe('NetworkController', () => {
|
||||
rpcPrefs: { blockExplorerUrl: 'https://block-explorer' },
|
||||
};
|
||||
|
||||
controller.upsertNetworkConfiguration(newNetworkConfiguration, {
|
||||
await controller.upsertNetworkConfiguration(newNetworkConfiguration, {
|
||||
referrer: 'https://test-dapp.com',
|
||||
source: MetaMetricsNetworkEventSource.Dapp,
|
||||
});
|
||||
@ -7296,10 +7296,10 @@ describe('NetworkController', () => {
|
||||
rpcPrefs: { blockExplorerUrl: 'https://block-explorer' },
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
await expect(() =>
|
||||
/* @ts-expect-error We are intentionally passing bad input. */
|
||||
controller.upsertNetworkConfiguration(newNetworkConfiguration, {});
|
||||
}).toThrow(
|
||||
controller.upsertNetworkConfiguration(newNetworkConfiguration, {}),
|
||||
).rejects.toThrow(
|
||||
'referrer and source are required arguments for adding or updating a network configuration',
|
||||
);
|
||||
},
|
||||
@ -7308,14 +7308,14 @@ describe('NetworkController', () => {
|
||||
});
|
||||
|
||||
describe('removeNetworkConfigurations', () => {
|
||||
it('should remove a network configuration', async () => {
|
||||
const networkConfigurationId = 'networkConfigurationId';
|
||||
it('removes a network configuration', async () => {
|
||||
const networkConfigurationId = 'testNetworkConfigurationId';
|
||||
await withController(
|
||||
{
|
||||
state: {
|
||||
networkConfigurations: {
|
||||
[networkConfigurationId]: {
|
||||
id: 'aaaaaa',
|
||||
id: networkConfigurationId,
|
||||
rpcUrl: 'https://test-rpc-url',
|
||||
ticker: 'old_rpc_ticker',
|
||||
nickname: 'old_rpc_chainName',
|
||||
@ -7326,25 +7326,44 @@ describe('NetworkController', () => {
|
||||
},
|
||||
},
|
||||
async ({ controller }) => {
|
||||
expect(
|
||||
Object.values(controller.store.getState().networkConfigurations),
|
||||
).toStrictEqual([
|
||||
{
|
||||
id: 'aaaaaa',
|
||||
rpcUrl: 'https://test-rpc-url',
|
||||
ticker: 'old_rpc_ticker',
|
||||
nickname: 'old_rpc_chainName',
|
||||
rpcPrefs: { blockExplorerUrl: 'testchainscan.io' },
|
||||
chainId: '0x1',
|
||||
},
|
||||
]);
|
||||
controller.removeNetworkConfiguration(networkConfigurationId);
|
||||
|
||||
expect(
|
||||
controller.store.getState().networkConfigurations,
|
||||
).toStrictEqual({});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('throws if the networkConfigurationId it is passed does not correspond to a network configuration in state', async () => {
|
||||
const testNetworkConfigurationId = 'testNetworkConfigurationId';
|
||||
const invalidNetworkConfigurationId = 'invalidNetworkConfigurationId';
|
||||
await withController(
|
||||
{
|
||||
state: {
|
||||
networkConfigurations: {
|
||||
[testNetworkConfigurationId]: {
|
||||
rpcUrl: 'https://rpc-url.com',
|
||||
ticker: 'old_rpc_ticker',
|
||||
nickname: 'old_rpc_nickname',
|
||||
rpcPrefs: { blockExplorerUrl: 'testchainscan.io' },
|
||||
chainId: '0x1',
|
||||
id: testNetworkConfigurationId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
async ({ controller }) => {
|
||||
expect(() =>
|
||||
controller.removeNetworkConfiguration(
|
||||
invalidNetworkConfigurationId,
|
||||
),
|
||||
).toThrow(
|
||||
`networkConfigurationId ${invalidNetworkConfigurationId} does not match a configured networkConfiguration`,
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1034,7 +1034,7 @@ export class NetworkController extends EventEmitter {
|
||||
* @throws if `rpcUrl` is not a valid URL.
|
||||
* @returns The ID for the added or updated network configuration.
|
||||
*/
|
||||
upsertNetworkConfiguration(
|
||||
async upsertNetworkConfiguration(
|
||||
{
|
||||
rpcUrl,
|
||||
chainId,
|
||||
@ -1051,7 +1051,7 @@ export class NetworkController extends EventEmitter {
|
||||
referrer: string;
|
||||
source: string;
|
||||
},
|
||||
): NetworkConfigurationId {
|
||||
): Promise<NetworkConfigurationId> {
|
||||
assert.ok(
|
||||
isPrefixedFormattedHexString(chainId),
|
||||
`Invalid chain ID "${chainId}": invalid hex string.`,
|
||||
@ -1129,7 +1129,7 @@ export class NetworkController extends EventEmitter {
|
||||
}
|
||||
|
||||
if (setActive) {
|
||||
this.setActiveNetwork(newNetworkConfigurationId);
|
||||
await this.setActiveNetwork(newNetworkConfigurationId);
|
||||
}
|
||||
|
||||
return newNetworkConfigurationId;
|
||||
@ -1141,9 +1141,12 @@ export class NetworkController extends EventEmitter {
|
||||
* @param networkConfigurationId - The unique id for the network configuration
|
||||
* to remove.
|
||||
*/
|
||||
removeNetworkConfiguration(
|
||||
networkConfigurationId: NetworkConfigurationId,
|
||||
): void {
|
||||
removeNetworkConfiguration(networkConfigurationId: NetworkConfigurationId) {
|
||||
if (!this.store.getState().networkConfigurations[networkConfigurationId]) {
|
||||
throw new Error(
|
||||
`networkConfigurationId ${networkConfigurationId} does not match a configured networkConfiguration`,
|
||||
);
|
||||
}
|
||||
const networkConfigurations = {
|
||||
...this.store.getState().networkConfigurations,
|
||||
};
|
||||
|
@ -113,7 +113,7 @@ export default class SwapsController {
|
||||
fetchTradesInfo = defaultFetchTradesInfo,
|
||||
getCurrentChainId,
|
||||
getEIP1559GasFeeEstimates,
|
||||
onNetworkDidChange,
|
||||
onNetworkStateChange,
|
||||
}) {
|
||||
this.store = new ObservableStore({
|
||||
swapsState: { ...initialState.swapsState },
|
||||
@ -137,7 +137,7 @@ export default class SwapsController {
|
||||
|
||||
this.ethersProvider = new Web3Provider(provider);
|
||||
this._currentNetworkId = networkController.store.getState().networkId;
|
||||
onNetworkDidChange(() => {
|
||||
onNetworkStateChange(() => {
|
||||
const { networkId, networkStatus } = networkController.store.getState();
|
||||
if (
|
||||
networkStatus === NetworkStatus.Available &&
|
||||
|
@ -160,7 +160,7 @@ describe('SwapsController', function () {
|
||||
return new SwapsController({
|
||||
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
|
||||
networkController: getMockNetworkController(),
|
||||
onNetworkDidChange: sinon.stub(),
|
||||
onNetworkStateChange: sinon.stub(),
|
||||
provider: _provider,
|
||||
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
|
||||
getTokenRatesState: MOCK_TOKEN_RATES_STORE,
|
||||
@ -208,11 +208,11 @@ describe('SwapsController', function () {
|
||||
|
||||
it('should replace ethers instance when network changes', function () {
|
||||
const networkController = getMockNetworkController();
|
||||
const onNetworkDidChange = sinon.stub();
|
||||
const onNetworkStateChange = sinon.stub();
|
||||
const swapsController = new SwapsController({
|
||||
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
|
||||
networkController,
|
||||
onNetworkDidChange,
|
||||
onNetworkStateChange,
|
||||
provider,
|
||||
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
|
||||
getTokenRatesState: MOCK_TOKEN_RATES_STORE,
|
||||
@ -220,7 +220,7 @@ describe('SwapsController', function () {
|
||||
getCurrentChainId: getCurrentChainIdStub,
|
||||
});
|
||||
const currentEthersInstance = swapsController.ethersProvider;
|
||||
const changeNetwork = onNetworkDidChange.getCall(0).args[0];
|
||||
const changeNetwork = onNetworkStateChange.getCall(0).args[0];
|
||||
|
||||
networkController.store.getState.returns({
|
||||
networkId: NETWORK_IDS.MAINNET,
|
||||
@ -238,11 +238,11 @@ describe('SwapsController', function () {
|
||||
|
||||
it('should not replace ethers instance when network changes to loading', function () {
|
||||
const networkController = getMockNetworkController();
|
||||
const onNetworkDidChange = sinon.stub();
|
||||
const onNetworkStateChange = sinon.stub();
|
||||
const swapsController = new SwapsController({
|
||||
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
|
||||
networkController,
|
||||
onNetworkDidChange,
|
||||
onNetworkStateChange,
|
||||
provider,
|
||||
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
|
||||
getTokenRatesState: MOCK_TOKEN_RATES_STORE,
|
||||
@ -250,7 +250,7 @@ describe('SwapsController', function () {
|
||||
getCurrentChainId: getCurrentChainIdStub,
|
||||
});
|
||||
const currentEthersInstance = swapsController.ethersProvider;
|
||||
const changeNetwork = onNetworkDidChange.getCall(0).args[0];
|
||||
const changeNetwork = onNetworkStateChange.getCall(0).args[0];
|
||||
|
||||
networkController.store.getState.returns({
|
||||
networkId: null,
|
||||
@ -268,11 +268,11 @@ describe('SwapsController', function () {
|
||||
|
||||
it('should not replace ethers instance when network changes to the same network', function () {
|
||||
const networkController = getMockNetworkController();
|
||||
const onNetworkDidChange = sinon.stub();
|
||||
const onNetworkStateChange = sinon.stub();
|
||||
const swapsController = new SwapsController({
|
||||
getBufferedGasLimit: MOCK_GET_BUFFERED_GAS_LIMIT,
|
||||
networkController,
|
||||
onNetworkDidChange,
|
||||
onNetworkStateChange,
|
||||
provider,
|
||||
getProviderConfig: MOCK_GET_PROVIDER_CONFIG,
|
||||
getTokenRatesState: MOCK_TOKEN_RATES_STORE,
|
||||
@ -280,7 +280,7 @@ describe('SwapsController', function () {
|
||||
getCurrentChainId: getCurrentChainIdStub,
|
||||
});
|
||||
const currentEthersInstance = swapsController.ethersProvider;
|
||||
const changeNetwork = onNetworkDidChange.getCall(0).args[0];
|
||||
const changeNetwork = onNetworkStateChange.getCall(0).args[0];
|
||||
|
||||
networkController.store.getState.returns({
|
||||
networkId: NETWORK_IDS.GOERLI,
|
||||
|
@ -1195,10 +1195,8 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.txController.txGasUtil,
|
||||
),
|
||||
networkController: this.networkController,
|
||||
onNetworkDidChange: networkControllerMessenger.subscribe.bind(
|
||||
networkControllerMessenger,
|
||||
NetworkControllerEventType.NetworkDidChange,
|
||||
),
|
||||
onNetworkStateChange: (listener) =>
|
||||
this.networkController.store.subscribe(listener),
|
||||
provider: this.provider,
|
||||
getProviderConfig: () => this.networkController.store.getState().provider,
|
||||
getTokenRatesState: () => this.tokenRatesController.state,
|
||||
|
@ -1,103 +1,254 @@
|
||||
import { migrate } from './083';
|
||||
import { v4 } from 'uuid';
|
||||
import { migrate, version } from './083';
|
||||
|
||||
describe('migration #83', () => {
|
||||
it('updates the version metadata', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
meta: {
|
||||
version: 9999999,
|
||||
},
|
||||
});
|
||||
jest.mock('uuid', () => {
|
||||
const actual = jest.requireActual('uuid');
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.meta).toStrictEqual({
|
||||
version: 83,
|
||||
});
|
||||
});
|
||||
|
||||
it('does not change the state if the network controller state does not exist', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
test: '123',
|
||||
},
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
|
||||
const nonObjects = [undefined, null, 'test', 1, ['test']];
|
||||
for (const invalidState of nonObjects) {
|
||||
it(`does not change the state if the network controller state is ${invalidState}`, async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: invalidState,
|
||||
},
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
}
|
||||
|
||||
it('does not change the state if the network controller state does not include "network"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: {
|
||||
test: '123',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
|
||||
it('replaces "network" in the network controller state with "networkId": null, "networkStatus": "unknown" if it is "loading"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: {
|
||||
network: 'loading',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual({
|
||||
NetworkController: {
|
||||
networkId: null,
|
||||
networkStatus: 'unknown',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('replaces "network" in the network controller state with "networkId": network, "networkStatus": "available" if it is not "loading"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: {
|
||||
network: '12345',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual({
|
||||
NetworkController: {
|
||||
networkId: '12345',
|
||||
networkStatus: 'available',
|
||||
},
|
||||
});
|
||||
});
|
||||
return {
|
||||
...actual,
|
||||
v4: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
function buildOriginalVersionedData({ meta = {}, data = {} } = {}) {
|
||||
return {
|
||||
meta: { version: 999999, ...meta },
|
||||
data: { ...data },
|
||||
};
|
||||
}
|
||||
describe('migration #83', () => {
|
||||
beforeEach(() => {
|
||||
v4.mockImplementationOnce(() => 'network-configuration-id-1')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-2')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-3')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-4');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
it('should update the version metadata', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version: 82,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
expect(newStorage.meta).toStrictEqual({
|
||||
version,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the key of the networkConfigurations object to set the id of each network configuration', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
networkConfigurations: {
|
||||
'network-configuration-id-1': {
|
||||
chainId: '0x539',
|
||||
nickname: 'Localhost 8545',
|
||||
rpcPrefs: {},
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
ticker: 'ETH',
|
||||
},
|
||||
'network-configuration-id-2': {
|
||||
chainId: '0xa4b1',
|
||||
nickname: 'Arbitrum One',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.arbitrum.io',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://arbitrum-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'ETH',
|
||||
},
|
||||
'network-configuration-id-3': {
|
||||
chainId: '0x4e454152',
|
||||
nickname: 'Aurora Mainnet',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://aurorascan.dev/',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://aurora-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'Aurora ETH',
|
||||
},
|
||||
'network-configuration-id-4': {
|
||||
chainId: '0x38',
|
||||
nickname:
|
||||
'BNB Smart Chain (previously Binance Smart Chain Mainnet)',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://bscscan.com/',
|
||||
},
|
||||
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||
ticker: 'BNB',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
networkConfigurations: {
|
||||
'network-configuration-id-1': {
|
||||
chainId: '0x539',
|
||||
nickname: 'Localhost 8545',
|
||||
rpcPrefs: {},
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
ticker: 'ETH',
|
||||
id: 'network-configuration-id-1',
|
||||
},
|
||||
'network-configuration-id-2': {
|
||||
chainId: '0xa4b1',
|
||||
nickname: 'Arbitrum One',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.arbitrum.io',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://arbitrum-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'ETH',
|
||||
id: 'network-configuration-id-2',
|
||||
},
|
||||
'network-configuration-id-3': {
|
||||
chainId: '0x4e454152',
|
||||
nickname: 'Aurora Mainnet',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://aurorascan.dev/',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://aurora-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'Aurora ETH',
|
||||
id: 'network-configuration-id-3',
|
||||
},
|
||||
'network-configuration-id-4': {
|
||||
chainId: '0x38',
|
||||
nickname:
|
||||
'BNB Smart Chain (previously Binance Smart Chain Mainnet)',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://bscscan.com/',
|
||||
},
|
||||
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||
ticker: 'BNB',
|
||||
id: 'network-configuration-id-4',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController is undefined', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController is not an object', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: false,
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: false,
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController.networkConfigurations is undefined', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: undefined,
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: undefined,
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController.networkConfigurations is an empty object', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: {},
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: {},
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { hasProperty, isObject } from '@metamask/utils';
|
||||
import { isObject } from '@metamask/utils';
|
||||
|
||||
export const version = 83;
|
||||
|
||||
/**
|
||||
* The `network` property in state was replaced with `networkId` and `networkStatus`.
|
||||
* Ensure that each networkConfigurations object in state.NetworkController.networkConfigurations has an
|
||||
* `id` property which matches the key pointing that object
|
||||
*
|
||||
* @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist.
|
||||
* @param originalVersionedData.meta - State metadata.
|
||||
@ -23,25 +24,35 @@ export async function migrate(originalVersionedData: {
|
||||
}
|
||||
|
||||
function transformState(state: Record<string, unknown>) {
|
||||
if (
|
||||
!hasProperty(state, 'NetworkController') ||
|
||||
!isObject(state.NetworkController) ||
|
||||
!hasProperty(state.NetworkController, 'network')
|
||||
) {
|
||||
if (!isObject(state.NetworkController)) {
|
||||
return state;
|
||||
}
|
||||
const { NetworkController } = state;
|
||||
|
||||
if (!isObject(NetworkController.networkConfigurations)) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const NetworkController = { ...state.NetworkController };
|
||||
const { networkConfigurations } = NetworkController;
|
||||
|
||||
if (NetworkController.network === 'loading') {
|
||||
NetworkController.networkId = null;
|
||||
NetworkController.networkStatus = 'unknown';
|
||||
} else {
|
||||
NetworkController.networkId = NetworkController.network;
|
||||
NetworkController.networkStatus = 'available';
|
||||
const newNetworkConfigurations: Record<string, Record<string, unknown>> = {};
|
||||
|
||||
for (const networkConfigurationId of Object.keys(networkConfigurations)) {
|
||||
const networkConfiguration = networkConfigurations[networkConfigurationId];
|
||||
if (!isObject(networkConfiguration)) {
|
||||
return state;
|
||||
}
|
||||
newNetworkConfigurations[networkConfigurationId] = {
|
||||
...networkConfiguration,
|
||||
id: networkConfigurationId,
|
||||
};
|
||||
}
|
||||
|
||||
delete NetworkController.network;
|
||||
|
||||
return { ...state, NetworkController };
|
||||
return {
|
||||
...state,
|
||||
NetworkController: {
|
||||
...NetworkController,
|
||||
networkConfigurations: newNetworkConfigurations,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1,254 +1,103 @@
|
||||
import { v4 } from 'uuid';
|
||||
import { migrate, version } from './084';
|
||||
|
||||
jest.mock('uuid', () => {
|
||||
const actual = jest.requireActual('uuid');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
v4: jest.fn(),
|
||||
};
|
||||
});
|
||||
import { migrate } from './084';
|
||||
|
||||
describe('migration #84', () => {
|
||||
beforeEach(() => {
|
||||
v4.mockImplementationOnce(() => 'network-configuration-id-1')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-2')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-3')
|
||||
.mockImplementationOnce(() => 'network-configuration-id-4');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
it('should update the version metadata', async () => {
|
||||
const oldStorage = {
|
||||
it('updates the version metadata', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
meta: {
|
||||
version: 83,
|
||||
version: 9999999,
|
||||
},
|
||||
data: {},
|
||||
};
|
||||
});
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
expect(newStorage.meta).toStrictEqual({
|
||||
version,
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.meta).toStrictEqual({
|
||||
version: 84,
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the key of the networkConfigurations object to set the id of each network configuration', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
it('does not change the state if the network controller state does not exist', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: {
|
||||
networkConfigurations: {
|
||||
'network-configuration-id-1': {
|
||||
chainId: '0x539',
|
||||
nickname: 'Localhost 8545',
|
||||
rpcPrefs: {},
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
ticker: 'ETH',
|
||||
},
|
||||
'network-configuration-id-2': {
|
||||
chainId: '0xa4b1',
|
||||
nickname: 'Arbitrum One',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.arbitrum.io',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://arbitrum-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'ETH',
|
||||
},
|
||||
'network-configuration-id-3': {
|
||||
chainId: '0x4e454152',
|
||||
nickname: 'Aurora Mainnet',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://aurorascan.dev/',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://aurora-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'Aurora ETH',
|
||||
},
|
||||
'network-configuration-id-4': {
|
||||
chainId: '0x38',
|
||||
nickname:
|
||||
'BNB Smart Chain (previously Binance Smart Chain Mainnet)',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://bscscan.com/',
|
||||
},
|
||||
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||
ticker: 'BNB',
|
||||
},
|
||||
},
|
||||
},
|
||||
test: '123',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
networkConfigurations: {
|
||||
'network-configuration-id-1': {
|
||||
chainId: '0x539',
|
||||
nickname: 'Localhost 8545',
|
||||
rpcPrefs: {},
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
ticker: 'ETH',
|
||||
id: 'network-configuration-id-1',
|
||||
},
|
||||
'network-configuration-id-2': {
|
||||
chainId: '0xa4b1',
|
||||
nickname: 'Arbitrum One',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://explorer.arbitrum.io',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://arbitrum-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'ETH',
|
||||
id: 'network-configuration-id-2',
|
||||
},
|
||||
'network-configuration-id-3': {
|
||||
chainId: '0x4e454152',
|
||||
nickname: 'Aurora Mainnet',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://aurorascan.dev/',
|
||||
},
|
||||
rpcUrl:
|
||||
'https://aurora-mainnet.infura.io/v3/373266a93aab4acda48f89d4fe77c748',
|
||||
ticker: 'Aurora ETH',
|
||||
id: 'network-configuration-id-3',
|
||||
},
|
||||
'network-configuration-id-4': {
|
||||
chainId: '0x38',
|
||||
nickname:
|
||||
'BNB Smart Chain (previously Binance Smart Chain Mainnet)',
|
||||
rpcPrefs: {
|
||||
blockExplorerUrl: 'https://bscscan.com/',
|
||||
},
|
||||
rpcUrl: 'https://bsc-dataseed.binance.org/',
|
||||
ticker: 'BNB',
|
||||
id: 'network-configuration-id-4',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController is undefined', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
const nonObjects = [undefined, null, 'test', 1, ['test']];
|
||||
for (const invalidState of nonObjects) {
|
||||
it(`does not change the state if the network controller state is ${invalidState}`, async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: invalidState,
|
||||
},
|
||||
});
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
}
|
||||
|
||||
it('does not change the state if the network controller state does not include "network"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
testProperty: 'testValue',
|
||||
NetworkController: {
|
||||
test: '123',
|
||||
},
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
expect(newVersionedData.data).toStrictEqual(originalVersionedData.data);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController is not an object', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
it('replaces "network" in the network controller state with "networkId": null, "networkStatus": "unknown" if it is "loading"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: false,
|
||||
testProperty: 'testValue',
|
||||
NetworkController: {
|
||||
network: 'loading',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
expect(newVersionedData.data).toStrictEqual({
|
||||
NetworkController: {
|
||||
networkId: null,
|
||||
networkStatus: 'unknown',
|
||||
},
|
||||
data: {
|
||||
NetworkController: false,
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController.networkConfigurations is undefined', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
it('replaces "network" in the network controller state with "networkId": network, "networkStatus": "available" if it is not "loading"', async () => {
|
||||
const originalVersionedData = buildOriginalVersionedData({
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: undefined,
|
||||
network: '12345',
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
const newVersionedData = await migrate(originalVersionedData);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
expect(newVersionedData.data).toStrictEqual({
|
||||
NetworkController: {
|
||||
networkId: '12345',
|
||||
networkStatus: 'available',
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: undefined,
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
|
||||
it('should not modify state if state.NetworkController.networkConfigurations is an empty object', async () => {
|
||||
const oldStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: {},
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
const expectedNewStorage = {
|
||||
meta: {
|
||||
version,
|
||||
},
|
||||
data: {
|
||||
NetworkController: {
|
||||
testNetworkControllerProperty: 'testNetworkControllerValue',
|
||||
networkConfigurations: {},
|
||||
},
|
||||
testProperty: 'testValue',
|
||||
},
|
||||
};
|
||||
expect(newStorage).toStrictEqual(expectedNewStorage);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function buildOriginalVersionedData({ meta = {}, data = {} } = {}) {
|
||||
return {
|
||||
meta: { version: 999999, ...meta },
|
||||
data: { ...data },
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { isObject } from '@metamask/utils';
|
||||
import { hasProperty, isObject } from '@metamask/utils';
|
||||
|
||||
export const version = 84;
|
||||
|
||||
/**
|
||||
* Ensure that each networkConfigurations object in state.NetworkController.networkConfigurations has an
|
||||
* `id` property which matches the key pointing that object
|
||||
* The `network` property in state was replaced with `networkId` and `networkStatus`.
|
||||
*
|
||||
* @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist.
|
||||
* @param originalVersionedData.meta - State metadata.
|
||||
@ -24,35 +23,25 @@ export async function migrate(originalVersionedData: {
|
||||
}
|
||||
|
||||
function transformState(state: Record<string, unknown>) {
|
||||
if (!isObject(state.NetworkController)) {
|
||||
return state;
|
||||
}
|
||||
const { NetworkController } = state;
|
||||
|
||||
if (!isObject(NetworkController.networkConfigurations)) {
|
||||
if (
|
||||
!hasProperty(state, 'NetworkController') ||
|
||||
!isObject(state.NetworkController) ||
|
||||
!hasProperty(state.NetworkController, 'network')
|
||||
) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const { networkConfigurations } = NetworkController;
|
||||
const NetworkController = { ...state.NetworkController };
|
||||
|
||||
const newNetworkConfigurations: Record<string, Record<string, unknown>> = {};
|
||||
|
||||
for (const networkConfigurationId of Object.keys(networkConfigurations)) {
|
||||
const networkConfiguration = networkConfigurations[networkConfigurationId];
|
||||
if (!isObject(networkConfiguration)) {
|
||||
return state;
|
||||
}
|
||||
newNetworkConfigurations[networkConfigurationId] = {
|
||||
...networkConfiguration,
|
||||
id: networkConfigurationId,
|
||||
};
|
||||
if (NetworkController.network === 'loading') {
|
||||
NetworkController.networkId = null;
|
||||
NetworkController.networkStatus = 'unknown';
|
||||
} else {
|
||||
NetworkController.networkId = NetworkController.network;
|
||||
NetworkController.networkStatus = 'available';
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
NetworkController: {
|
||||
...NetworkController,
|
||||
networkConfigurations: newNetworkConfigurations,
|
||||
},
|
||||
};
|
||||
delete NetworkController.network;
|
||||
|
||||
return { ...state, NetworkController };
|
||||
}
|
||||
|
@ -6,10 +6,10 @@
|
||||
// subset of files to check against these targets.
|
||||
module.exports = {
|
||||
global: {
|
||||
lines: 67.8,
|
||||
branches: 55.84,
|
||||
statements: 67.13,
|
||||
functions: 59.66,
|
||||
lines: 68.5,
|
||||
branches: 56.34,
|
||||
statements: 67.86,
|
||||
functions: 60.69,
|
||||
},
|
||||
transforms: {
|
||||
branches: 100,
|
||||
|
@ -72,6 +72,7 @@ const scuttlingConfigBase = {
|
||||
Date: '',
|
||||
JSON: '',
|
||||
encodeURIComponent: '',
|
||||
console: '',
|
||||
crypto: '',
|
||||
// {clear/set}Timeout are "this sensitive"
|
||||
clearTimeout: 'window',
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metamask-crx",
|
||||
"version": "10.28.1",
|
||||
"version": "10.28.3",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -221,7 +221,7 @@ export const CURRENCY_SYMBOLS = {
|
||||
OPTIMISM: 'OP',
|
||||
} as const;
|
||||
|
||||
export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.svg';
|
||||
export const ETH_TOKEN_IMAGE_URL = './images/eth_logo.png';
|
||||
export const TEST_ETH_TOKEN_IMAGE_URL = './images/black-eth-logo.svg';
|
||||
export const BNB_TOKEN_IMAGE_URL = './images/bnb.png';
|
||||
export const MATIC_TOKEN_IMAGE_URL = './images/matic-token.png';
|
||||
|
@ -102,6 +102,10 @@ export const UI_NOTIFICATIONS = {
|
||||
width: '100%',
|
||||
},
|
||||
},
|
||||
20: {
|
||||
id: 20,
|
||||
date: null,
|
||||
},
|
||||
};
|
||||
|
||||
export const getTranslatedUINotifications = (t, locale) => {
|
||||
@ -279,5 +283,16 @@ export const getTranslatedUINotifications = (t, locale) => {
|
||||
)
|
||||
: '',
|
||||
},
|
||||
20: {
|
||||
...UI_NOTIFICATIONS[20],
|
||||
title: t('notifications20Title'),
|
||||
description: [t('notifications20Description')],
|
||||
actionText: t('notifications20ActionText'),
|
||||
date: UI_NOTIFICATIONS[20].date
|
||||
? new Intl.DateTimeFormat(formattedLocale).format(
|
||||
new Date(UI_NOTIFICATIONS[20].date),
|
||||
)
|
||||
: '',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ async function withFixtures(options, testSuite) {
|
||||
});
|
||||
}
|
||||
}
|
||||
await setupMocking(mockServer, testSpecificMock);
|
||||
const mockedEndpoint = await setupMocking(mockServer, testSpecificMock);
|
||||
await mockServer.start(8000);
|
||||
if (
|
||||
process.env.SELENIUM_BROWSER === 'chrome' &&
|
||||
@ -143,10 +143,10 @@ async function withFixtures(options, testSuite) {
|
||||
|
||||
await testSuite({
|
||||
driver: driverProxy ?? driver,
|
||||
mockServer,
|
||||
contractRegistry,
|
||||
ganacheServer,
|
||||
secondaryGanacheServer,
|
||||
mockedEndpoint,
|
||||
});
|
||||
} catch (error) {
|
||||
failed = true;
|
||||
|
@ -32,6 +32,11 @@ async function setupMocking(server, testSpecificMock) {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
|
||||
const mockedEndpoint = await testSpecificMock(server);
|
||||
|
||||
// Mocks below this line can be overridden by test-specific mocks
|
||||
|
||||
await server
|
||||
.forPost(
|
||||
'https://arbitrum-mainnet.infura.io/v3/00000000000000000000000000000000',
|
||||
@ -369,10 +374,6 @@ async function setupMocking(server, testSpecificMock) {
|
||||
};
|
||||
});
|
||||
|
||||
testSpecificMock(server);
|
||||
|
||||
// Mocks below this line can be overridden by test-specific mocks
|
||||
|
||||
await server.forGet(STALELIST_URL).thenCallback(() => {
|
||||
return {
|
||||
statusCode: 200,
|
||||
@ -399,6 +400,8 @@ async function setupMocking(server, testSpecificMock) {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return mockedEndpoint;
|
||||
}
|
||||
|
||||
module.exports = { setupMocking };
|
||||
|
@ -9,8 +9,6 @@ describe('ENS', function () {
|
||||
'https://mainnet.infura.io/v3/00000000000000000000000000000000';
|
||||
|
||||
async function mockInfura(mockServer) {
|
||||
await mockServer.reset();
|
||||
await mockServer.forAnyRequest().thenPassThrough();
|
||||
await mockServer
|
||||
.forPost(infuraUrl)
|
||||
.withJsonBodyIncluding({ method: 'eth_blockNumber' })
|
||||
@ -103,7 +101,7 @@ describe('ENS', function () {
|
||||
|
||||
await driver.clickElement('[data-testid="eth-overview-send"]');
|
||||
|
||||
await driver.fill(
|
||||
await driver.pasteIntoField(
|
||||
'input[placeholder="Search, public address (0x), or ENS"]',
|
||||
sampleEnsDomain,
|
||||
);
|
||||
|
@ -3,9 +3,7 @@ const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
const FixtureBuilder = require('../fixture-builder');
|
||||
|
||||
describe('Sentry errors', function () {
|
||||
async function mockSegment(mockServer) {
|
||||
mockServer.reset();
|
||||
await mockServer.forAnyRequest().thenPassThrough();
|
||||
async function mockSentry(mockServer) {
|
||||
return await mockServer
|
||||
.forPost('https://sentry.io/api/0000000/store/')
|
||||
.thenCallback(() => {
|
||||
@ -36,9 +34,9 @@ describe('Sentry errors', function () {
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
failOnConsoleError: false,
|
||||
testSpecificMock: mockSentry,
|
||||
},
|
||||
async ({ driver, mockServer }) => {
|
||||
const mockedEndpoint = await mockSegment(mockServer);
|
||||
async ({ driver, mockedEndpoint }) => {
|
||||
await driver.navigate();
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
|
@ -4,8 +4,6 @@ const FixtureBuilder = require('../fixture-builder');
|
||||
|
||||
describe('Segment metrics', function () {
|
||||
async function mockSegment(mockServer) {
|
||||
mockServer.reset();
|
||||
await mockServer.forAnyRequest().thenPassThrough();
|
||||
return await mockServer
|
||||
.forPost('https://api.segment.io/v1/batch')
|
||||
.withJsonBodyIncluding({ batch: [{ type: 'page' }] })
|
||||
@ -36,18 +34,17 @@ describe('Segment metrics', function () {
|
||||
.build(),
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
failOnConsoleError: false,
|
||||
testSpecificMock: mockSegment,
|
||||
},
|
||||
async ({ driver, mockServer }) => {
|
||||
const mockedEndpoints = await mockSegment(mockServer);
|
||||
async ({ driver, mockedEndpoint }) => {
|
||||
await driver.navigate();
|
||||
await driver.fill('#password', 'correct horse battery staple');
|
||||
await driver.press('#password', driver.Key.ENTER);
|
||||
await driver.wait(async () => {
|
||||
const isPending = await mockedEndpoints.isPending();
|
||||
const isPending = await mockedEndpoint.isPending();
|
||||
return isPending === false;
|
||||
}, 10000);
|
||||
const mockedRequests = await mockedEndpoints.getSeenRequests();
|
||||
const mockedRequests = await mockedEndpoint.getSeenRequests();
|
||||
assert.equal(mockedRequests.length, 3);
|
||||
const [firstMock, secondMock, thirdMock] = mockedRequests;
|
||||
let [mockJson] = firstMock.body.json.batch;
|
||||
|
@ -8,6 +8,7 @@ describe('Gas API fallback', function () {
|
||||
.forGet(
|
||||
'https://gas-api.metaswap.codefi.network/networks/1/suggestedGasFees',
|
||||
)
|
||||
.always()
|
||||
.thenCallback(() => {
|
||||
return {
|
||||
statusCode: 200,
|
||||
|
@ -1,6 +1,6 @@
|
||||
const { strict: assert } = require('assert');
|
||||
const { SMART_CONTRACTS } = require('../seeder/smart-contracts');
|
||||
const { convertToHexValue, withFixtures, tinyDelayMs } = require('../helpers');
|
||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
const FixtureBuilder = require('../fixture-builder');
|
||||
|
||||
describe('Send ETH from inside MetaMask using default gas', function () {
|
||||
@ -334,7 +334,15 @@ describe('Send ETH from dapp using advanced gas controls', function () {
|
||||
await priorityFeeInput.fill('1');
|
||||
|
||||
await driver.clickElement({ text: 'Save', tag: 'button' });
|
||||
await driver.delay(tinyDelayMs);
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-detail-item:nth-of-type(1) h6:nth-of-type(2)',
|
||||
text: '0.02367237 ETH',
|
||||
});
|
||||
await driver.waitForSelector({
|
||||
css: '.transaction-detail-item:nth-of-type(2) h6:nth-of-type(2)',
|
||||
text: '0.02367237 ETH',
|
||||
});
|
||||
|
||||
await driver.clickElement({ text: 'Confirm', tag: 'button' });
|
||||
await driver.waitUntilXWindowHandles(2);
|
||||
await driver.switchToWindow(extension);
|
||||
|
@ -37,11 +37,7 @@ import Button from '../../ui/button';
|
||||
import SearchIcon from '../../ui/icon/search-icon';
|
||||
import { SUPPORT_LINK } from '../../../../shared/lib/ui-utils';
|
||||
import { IconColor } from '../../../helpers/constants/design-system';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
import KeyRingLabel from './keyring-label';
|
||||
|
||||
export function AccountMenuItem(props) {
|
||||
@ -229,8 +225,8 @@ export default class AccountMenu extends Component {
|
||||
{isSelected ? (
|
||||
<Icon
|
||||
color={IconColor.successDefault}
|
||||
name={ICON_NAMES.CHECK}
|
||||
size={ICON_SIZES.LG}
|
||||
name={IconName.Check}
|
||||
size={IconSize.Lg}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
@ -374,9 +370,7 @@ export default class AccountMenu extends Component {
|
||||
});
|
||||
history.push(NEW_ACCOUNT_ROUTE);
|
||||
}}
|
||||
icon={
|
||||
<Icon name={ICON_NAMES.ADD} color={IconColor.iconAlternative} />
|
||||
}
|
||||
icon={<Icon name={IconName.Add} color={IconColor.iconAlternative} />}
|
||||
text={t('createAccount')}
|
||||
/>
|
||||
<AccountMenuItem
|
||||
@ -393,7 +387,7 @@ export default class AccountMenu extends Component {
|
||||
history.push(IMPORT_ACCOUNT_ROUTE);
|
||||
}}
|
||||
icon={
|
||||
<Icon name={ICON_NAMES.IMPORT} color={IconColor.iconAlternative} />
|
||||
<Icon name={IconName.Import} color={IconColor.iconAlternative} />
|
||||
}
|
||||
text={t('importAccount')}
|
||||
/>
|
||||
@ -415,10 +409,7 @@ export default class AccountMenu extends Component {
|
||||
}
|
||||
}}
|
||||
icon={
|
||||
<Icon
|
||||
name={ICON_NAMES.HARDWARE}
|
||||
color={IconColor.iconAlternative}
|
||||
/>
|
||||
<Icon name={IconName.Hardware} color={IconColor.iconAlternative} />
|
||||
}
|
||||
text={t('connectHardwareWallet')}
|
||||
/>
|
||||
@ -433,7 +424,7 @@ export default class AccountMenu extends Component {
|
||||
}}
|
||||
icon={
|
||||
<div className="account-menu__notifications">
|
||||
<Icon name={ICON_NAMES.NOTIFICATION} size={ICON_SIZES.LG} />
|
||||
<Icon name={IconName.Notification} size={IconSize.Lg} />
|
||||
{unreadNotificationsCount > 0 && (
|
||||
<div className="account-menu__notifications__count">
|
||||
{unreadNotificationsCount}
|
||||
@ -466,10 +457,7 @@ export default class AccountMenu extends Component {
|
||||
global.platform.openTab({ url: supportLink });
|
||||
}}
|
||||
icon={
|
||||
<Icon
|
||||
name={ICON_NAMES.MESSAGES}
|
||||
color={IconColor.iconAlternative}
|
||||
/>
|
||||
<Icon name={IconName.Messages} color={IconColor.iconAlternative} />
|
||||
}
|
||||
text={supportText}
|
||||
/>
|
||||
@ -488,7 +476,7 @@ export default class AccountMenu extends Component {
|
||||
}}
|
||||
icon={
|
||||
<Icon
|
||||
name={ICON_NAMES.SETTING}
|
||||
name={IconName.Setting}
|
||||
color={IconColor.iconAlternative}
|
||||
ariaLabel={t('settings')}
|
||||
/>
|
||||
|
@ -36,12 +36,7 @@ import { FEATURED_RPCS } from '../../../../shared/constants/network';
|
||||
import { ADD_NETWORK_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { getEnvironmentType } from '../../../../app/scripts/lib/util';
|
||||
import ZENDESK_URLS from '../../../helpers/constants/zendesk-url';
|
||||
import { Text } from '../../component-library';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Text, Icon, IconName, IconSize } from '../../component-library';
|
||||
import { MetaMetricsNetworkEventSource } from '../../../../shared/constants/metametrics';
|
||||
|
||||
const AddNetwork = () => {
|
||||
@ -249,9 +244,9 @@ const AddNetwork = () => {
|
||||
>
|
||||
<Icon
|
||||
className="add-network__warning-icon"
|
||||
name={ICON_NAMES.DANGER}
|
||||
name={IconName.Danger}
|
||||
color={IconColor.iconMuted}
|
||||
size={ICON_SIZES.SM}
|
||||
size={IconSize.Sm}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../component-library';
|
||||
import ApproveContentCard from './approve-content-card';
|
||||
|
||||
export default {
|
||||
@ -72,7 +72,7 @@ export default {
|
||||
},
|
||||
args: {
|
||||
showHeader: true,
|
||||
symbol: <Icon name={ICON_NAMES.TAG} />,
|
||||
symbol: <Icon name={IconName.Tag} />,
|
||||
title: 'Transaction fee',
|
||||
showEdit: true,
|
||||
showAdvanceGasFeeOptions: true,
|
||||
|
@ -16,11 +16,7 @@ import { INVALID_ASSET_TYPE } from '../../../helpers/constants/error-keys';
|
||||
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
|
||||
import { AssetType } from '../../../../shared/constants/transaction';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
import Box from '../../ui/box/box';
|
||||
|
||||
const AssetListItem = ({
|
||||
@ -35,7 +31,6 @@ const AssetListItem = ({
|
||||
warning,
|
||||
primary,
|
||||
secondary,
|
||||
identiconBorder,
|
||||
isERC721,
|
||||
}) => {
|
||||
const t = useI18nContext();
|
||||
@ -137,7 +132,6 @@ const AssetListItem = ({
|
||||
address={tokenAddress}
|
||||
image={tokenImage}
|
||||
alt={`${primary} ${tokenSymbol}`}
|
||||
imageBorder={identiconBorder}
|
||||
/>
|
||||
}
|
||||
midContent={midContent}
|
||||
@ -145,9 +139,9 @@ const AssetListItem = ({
|
||||
!isERC721 && (
|
||||
<Box>
|
||||
<Icon
|
||||
name={ICON_NAMES.ARROW_RIGHT}
|
||||
name={IconName.ArrowRight}
|
||||
color={Color.iconDefault}
|
||||
size={ICON_SIZES.SM}
|
||||
size={IconSize.Sm}
|
||||
style={{ verticalAlign: 'middle' }}
|
||||
/>
|
||||
{sendTokenButton}
|
||||
@ -170,7 +164,6 @@ AssetListItem.propTypes = {
|
||||
warning: PropTypes.node,
|
||||
primary: PropTypes.string,
|
||||
secondary: PropTypes.string,
|
||||
identiconBorder: PropTypes.bool,
|
||||
isERC721: PropTypes.bool,
|
||||
};
|
||||
|
||||
|
@ -34,9 +34,6 @@ export default {
|
||||
secondary: {
|
||||
control: 'text',
|
||||
},
|
||||
identiconBorder: {
|
||||
control: 'boolean',
|
||||
},
|
||||
isERC721: {
|
||||
control: 'boolean',
|
||||
},
|
||||
@ -44,7 +41,7 @@ export default {
|
||||
args: {
|
||||
tokenAddress: '0x2170ed0880ac9a755fd29b2688956bd959f933f8',
|
||||
tokenSymbol: 'ETH',
|
||||
tokenImage: './images/eth_logo.svg',
|
||||
tokenImage: './images/eth_logo.png',
|
||||
identiconBorder: true,
|
||||
},
|
||||
};
|
||||
|
@ -14,11 +14,7 @@ import {
|
||||
import { BETA_BUGS_URL } from '../../../helpers/constants/beta';
|
||||
|
||||
import { hideBetaHeader } from '../../../store/actions';
|
||||
import { ButtonIcon } from '../../component-library/button-icon/deprecated';
|
||||
import {
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, ButtonIconSize, IconName } from '../../component-library';
|
||||
|
||||
const BetaHeader = () => {
|
||||
const t = useI18nContext();
|
||||
@ -51,8 +47,8 @@ const BetaHeader = () => {
|
||||
])}
|
||||
</Typography>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.CLOSE}
|
||||
size={ICON_SIZES.SM}
|
||||
iconName={IconName.Close}
|
||||
size={ButtonIconSize.Sm}
|
||||
color={IconColor.warningInverse}
|
||||
className="beta-header__button"
|
||||
data-testid="beta-header-close"
|
||||
|
@ -10,7 +10,7 @@ import Identicon from '../../../ui/identicon';
|
||||
import { shortenAddress } from '../../../../helpers/utils/util';
|
||||
import AccountMismatchWarning from '../../../ui/account-mismatch-warning/account-mismatch-warning.component';
|
||||
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
||||
import { Icon, ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../../component-library';
|
||||
|
||||
export default function ConfirmPageContainerHeader({
|
||||
onEdit,
|
||||
@ -54,7 +54,7 @@ export default function ConfirmPageContainerHeader({
|
||||
visibility: showEdit ? 'initial' : 'hidden',
|
||||
}}
|
||||
>
|
||||
<Icon name={ICON_NAMES.ARROW_LEFT} />
|
||||
<Icon name={IconName.ArrowLeft} />
|
||||
<span
|
||||
data-testid="confirm-page-back-edit-button"
|
||||
className="confirm-page-container-header__back-button"
|
||||
|
@ -14,12 +14,7 @@ import {
|
||||
AlignItems,
|
||||
IconColor,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Text } from '../../component-library';
|
||||
import { Icon, IconName, IconSize, Text } from '../../component-library';
|
||||
|
||||
const ConfirmationWarningModal = ({ onSubmit, onCancel }) => {
|
||||
const t = useI18nContext();
|
||||
@ -60,10 +55,10 @@ const ConfirmationWarningModal = ({ onSubmit, onCancel }) => {
|
||||
className="confirmation-warning-modal__content__header"
|
||||
>
|
||||
<Icon
|
||||
name={ICON_NAMES.DANGER}
|
||||
name={IconName.Danger}
|
||||
color={IconColor.errorDefault}
|
||||
className="confirmation-warning-modal__content__header__warning-icon"
|
||||
size={ICON_SIZES.XL}
|
||||
size={IconSize.Xl}
|
||||
/>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { useRef } from 'react';
|
||||
import { Menu } from '../../../ui/menu';
|
||||
import { ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import { IconName, ButtonIcon } from '../../../component-library';
|
||||
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
||||
|
||||
const ConnectedAccountsListOptions = ({
|
||||
@ -17,7 +16,7 @@ const ConnectedAccountsListOptions = ({
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.MORE_VERTICAL}
|
||||
iconName={IconName.MoreVertical}
|
||||
className="connected-accounts-options__button"
|
||||
onClick={onShowOptions}
|
||||
ariaLabel={t('options')}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { IconName } from '../../component-library';
|
||||
import { MenuItem } from '../../ui/menu';
|
||||
import ConnectedAccountsListItem from './connected-accounts-list-item';
|
||||
import ConnectedAccountsListOptions from './connected-accounts-list-options';
|
||||
@ -105,7 +105,7 @@ export default class ConnectedAccountsList extends PureComponent {
|
||||
onShowOptions={this.showAccountOptions.bind(null, address)}
|
||||
show={accountWithOptionsShown === address}
|
||||
>
|
||||
<MenuItem iconName={ICON_NAMES.LOGOUT} onClick={this.disconnectAccount}>
|
||||
<MenuItem iconName={IconName.Logout} onClick={this.disconnectAccount}>
|
||||
{t('disconnectThisAccount')}
|
||||
</MenuItem>
|
||||
</ConnectedAccountsListOptions>
|
||||
|
@ -42,7 +42,7 @@ exports[`CustomSpendingCap should match snapshot 1`] = `
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="box mm-icon mm-icon--size-md box--display-inline-block box--flex-direction-row box--color-inherit"
|
||||
class="box mm-icon mm-icon--size-inherit box--display-inline-block box--flex-direction-row box--color-inherit"
|
||||
style="mask-image: url('./images/icons/question.svg');"
|
||||
/>
|
||||
</div>
|
||||
|
@ -8,11 +8,7 @@ import {
|
||||
DISPLAY,
|
||||
TypographyVariant,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
|
||||
export const CustomSpendingCapTooltip = ({
|
||||
tooltipContentText,
|
||||
@ -35,13 +31,15 @@ export const CustomSpendingCapTooltip = ({
|
||||
>
|
||||
{tooltipIcon ? (
|
||||
<Icon
|
||||
name={ICON_NAMES.DANGER}
|
||||
name={IconName.Danger}
|
||||
className="form-field__heading-title__tooltip__warning-icon"
|
||||
size={ICON_SIZES.AUTO}
|
||||
size={IconSize.Auto}
|
||||
style={{ 'vertical-align': 'bottom' }}
|
||||
/>
|
||||
) : (
|
||||
tooltipIcon !== '' && <Icon name={ICON_NAMES.QUESTION} />
|
||||
tooltipIcon !== '' && (
|
||||
<Icon name={IconName.Question} size={IconSize.Inherit} />
|
||||
)
|
||||
)}
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
@ -8,8 +8,7 @@ import { addHexPrefix } from 'ethereumjs-util';
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import Box from '../../ui/box';
|
||||
import FormField from '../../ui/form-field';
|
||||
import { Text, ButtonLink } from '../../component-library';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Text, ButtonLink, Icon, IconName } from '../../component-library';
|
||||
import {
|
||||
AlignItems,
|
||||
DISPLAY,
|
||||
@ -196,7 +195,7 @@ export default function CustomSpendingCap({
|
||||
as="h6"
|
||||
color={TextColor.errorDefault}
|
||||
>
|
||||
<Icon name={ICON_NAMES.WARNING} /> {t('beCareful')}
|
||||
<Icon name={IconName.Warning} /> {t('beCareful')}
|
||||
</Text>,
|
||||
])
|
||||
: t('inputLogicEmptyState');
|
||||
|
@ -32,7 +32,7 @@ import {
|
||||
ADD_POPULAR_CUSTOM_NETWORK,
|
||||
ADVANCED_ROUTE,
|
||||
} from '../../../helpers/constants/routes';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../component-library';
|
||||
|
||||
import { Dropdown, DropdownMenuItem } from './dropdown';
|
||||
|
||||
@ -186,7 +186,7 @@ class NetworkDropdown extends Component {
|
||||
}}
|
||||
>
|
||||
{isCurrentRpcTarget ? (
|
||||
<Icon name={ICON_NAMES.CHECK} color={IconColor.successDefault} />
|
||||
<Icon name={IconName.Check} color={IconColor.successDefault} />
|
||||
) : (
|
||||
<div className="network-check__transparent">✓</div>
|
||||
)}
|
||||
@ -245,7 +245,7 @@ class NetworkDropdown extends Component {
|
||||
style={DROP_DOWN_MENU_ITEM_STYLE}
|
||||
>
|
||||
{providerType === network ? (
|
||||
<Icon name={ICON_NAMES.CHECK} color={IconColor.successDefault} />
|
||||
<Icon name={IconName.Check} color={IconColor.successDefault} />
|
||||
) : (
|
||||
<div className="network-check__transparent">✓</div>
|
||||
)}
|
||||
@ -314,7 +314,7 @@ class NetworkDropdown extends Component {
|
||||
style={DROP_DOWN_MENU_ITEM_STYLE}
|
||||
>
|
||||
{isCurrentRpcTarget ? (
|
||||
<Icon name={ICON_NAMES.CHECK} color={IconColor.successDefault} />
|
||||
<Icon name={IconName.Check} color={IconColor.successDefault} />
|
||||
) : (
|
||||
<div className="network-check__transparent">✓</div>
|
||||
)}
|
||||
|
@ -14,11 +14,7 @@ import { useTransactionEventFragment } from '../../../hooks/useTransactionEventF
|
||||
import { useTransactionModalContext } from '../../../contexts/transaction-modal';
|
||||
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
||||
import Typography from '../../ui/typography/typography';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
|
||||
export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
||||
const t = useI18nContext();
|
||||
@ -78,9 +74,9 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
|
||||
)}
|
||||
<span className="edit-gas-fee-button__label">{t(title)}</span>
|
||||
<Icon
|
||||
name={ICON_NAMES.ARROW_RIGHT}
|
||||
name={IconName.ArrowRight}
|
||||
color={Color.primaryDefault}
|
||||
size={ICON_SIZES.XS}
|
||||
size={IconSize.Xs}
|
||||
/>
|
||||
</button>
|
||||
{estimateUsed === 'custom' && (
|
||||
|
@ -14,11 +14,7 @@ import {
|
||||
Color,
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../../component-library';
|
||||
|
||||
export const Copyable = ({ text }) => {
|
||||
const [copied, handleCopy] = useCopyToClipboard();
|
||||
@ -51,14 +47,14 @@ export const Copyable = ({ text }) => {
|
||||
>
|
||||
{copied ? (
|
||||
<Icon
|
||||
name={ICON_NAMES.COPY_SUCCESS}
|
||||
size={ICON_SIZES.LG}
|
||||
name={IconName.CopySuccess}
|
||||
size={IconSize.Lg}
|
||||
color={Color.iconAlternative}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
name={ICON_NAMES.COPY}
|
||||
size={ICON_SIZES.LG}
|
||||
name={IconName.Copy}
|
||||
size={IconSize.Lg}
|
||||
color={Color.iconAlternative}
|
||||
onClick={() => handleCopy(text)}
|
||||
/>
|
||||
|
@ -20,12 +20,8 @@ import {
|
||||
getSnapName,
|
||||
removeSnapIdPrefix,
|
||||
} from '../../../../helpers/utils/util';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import { Text } from '../../../component-library';
|
||||
import {
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName, Text } from '../../../component-library';
|
||||
|
||||
import { getTargetSubjectMetadata } from '../../../../selectors';
|
||||
import SnapAvatar from '../snap-avatar';
|
||||
|
||||
@ -85,9 +81,8 @@ const SnapAuthorship = ({ snapId, className }) => {
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href={url}
|
||||
iconName={ICON_NAMES.EXPORT}
|
||||
iconName={IconName.Export}
|
||||
color={IconColor.infoDefault}
|
||||
size={ICON_SIZES.MD}
|
||||
style={{ marginLeft: 'auto' }}
|
||||
/>
|
||||
</Box>
|
||||
|
@ -17,11 +17,9 @@ import {
|
||||
BadgeWrapperPosition,
|
||||
AvatarIcon,
|
||||
AvatarBase,
|
||||
IconName,
|
||||
IconSize,
|
||||
} from '../../../component-library';
|
||||
import {
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
import { getTargetSubjectMetadata } from '../../../../selectors';
|
||||
|
||||
const SnapAvatar = ({ snapId, className }) => {
|
||||
@ -40,11 +38,11 @@ const SnapAvatar = ({ snapId, className }) => {
|
||||
className={classnames('snap-avatar', className)}
|
||||
badge={
|
||||
<AvatarIcon
|
||||
iconName={ICON_NAMES.SNAPS}
|
||||
size={ICON_SIZES.XS}
|
||||
iconName={IconName.Snaps}
|
||||
size={IconSize.Xs}
|
||||
backgroundColor={IconColor.infoDefault}
|
||||
iconProps={{
|
||||
size: ICON_SIZES.XS,
|
||||
size: IconSize.Xs,
|
||||
color: IconColor.infoInverse,
|
||||
}}
|
||||
/>
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import Button from '../../../ui/button';
|
||||
import Box from '../../../ui/box/box';
|
||||
import { Icon, ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../../component-library';
|
||||
|
||||
export default function SnapContentFooter({ snapName, snapId }) {
|
||||
const t = useI18nContext();
|
||||
@ -36,7 +36,7 @@ export default function SnapContentFooter({ snapName, snapId }) {
|
||||
className="snap-content-footer"
|
||||
>
|
||||
<Icon
|
||||
name={ICON_NAMES.WARNING}
|
||||
name={IconName.Warning}
|
||||
size={Size.SM}
|
||||
color={IconColor.iconMuted}
|
||||
paddingRight={1}
|
||||
|
@ -12,11 +12,12 @@ import {
|
||||
TextColor,
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import Box from '../../../ui/box';
|
||||
import { AvatarIcon, Text } from '../../../component-library';
|
||||
import {
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
AvatarIcon,
|
||||
Text,
|
||||
IconName,
|
||||
IconSize,
|
||||
} from '../../../component-library';
|
||||
import {
|
||||
DelineatorType,
|
||||
getDelineatorTitle,
|
||||
@ -45,14 +46,14 @@ export const SnapDelineator = ({
|
||||
padding={1}
|
||||
>
|
||||
<AvatarIcon
|
||||
iconName={ICON_NAMES.SNAPS}
|
||||
size={ICON_SIZES.XS}
|
||||
iconName={IconName.Snaps}
|
||||
size={IconSize.Xs}
|
||||
backgroundColor={
|
||||
isError ? IconColor.errorDefault : IconColor.infoDefault
|
||||
}
|
||||
margin={1}
|
||||
iconProps={{
|
||||
size: ICON_SIZES.XS,
|
||||
size: IconSize.Xs,
|
||||
color: IconColor.infoInverse,
|
||||
}}
|
||||
/>
|
||||
|
@ -15,8 +15,7 @@ import {
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import Popover from '../../../ui/popover';
|
||||
import Button from '../../../ui/button';
|
||||
import { AvatarIcon, Text } from '../../../component-library';
|
||||
import { ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { AvatarIcon, Text, IconName } from '../../../component-library';
|
||||
import Box from '../../../ui/box/box';
|
||||
|
||||
/**
|
||||
@ -79,7 +78,7 @@ export default function SnapInstallWarning({ onCancel, onSubmit, warnings }) {
|
||||
>
|
||||
<Box justifyContent={JustifyContent.center} marginBottom={6}>
|
||||
<AvatarIcon
|
||||
iconName={ICON_NAMES.DANGER}
|
||||
iconName={IconName.Danger}
|
||||
backgroundColor={BackgroundColor.warningMuted}
|
||||
color={IconColor.warningDefault}
|
||||
size={Size.LG}
|
||||
|
@ -28,7 +28,7 @@ import {
|
||||
MetaMetricsEventName,
|
||||
} from '../../../../shared/constants/metametrics';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { IconName } from '../../component-library';
|
||||
|
||||
export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
const t = useI18nContext();
|
||||
@ -87,7 +87,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
</span>
|
||||
) : null
|
||||
}
|
||||
iconName={ICON_NAMES.EXPORT}
|
||||
iconName={IconName.Export}
|
||||
>
|
||||
{t(
|
||||
blockExplorerLinkText.firstPart,
|
||||
@ -109,7 +109,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
global.platform.openExtensionInBrowser();
|
||||
onClose();
|
||||
}}
|
||||
iconName={ICON_NAMES.EXPAND}
|
||||
iconName={IconName.Expand}
|
||||
>
|
||||
{t('expandView')}
|
||||
</MenuItem>
|
||||
@ -127,7 +127,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
});
|
||||
onClose();
|
||||
}}
|
||||
iconName={ICON_NAMES.SCAN_BARCODE}
|
||||
iconName={IconName.ScanBarcode}
|
||||
>
|
||||
{t('accountDetails')}
|
||||
</MenuItem>
|
||||
@ -144,7 +144,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
history.push(CONNECTED_ROUTE);
|
||||
onClose();
|
||||
}}
|
||||
iconName={ICON_NAMES.CONNECT}
|
||||
iconName={IconName.Connect}
|
||||
>
|
||||
{t('connectedSites')}
|
||||
</MenuItem>
|
||||
@ -160,7 +160,7 @@ export default function AccountOptionsMenu({ anchorElement, onClose }) {
|
||||
);
|
||||
onClose();
|
||||
}}
|
||||
iconName={ICON_NAMES.TRASH}
|
||||
iconName={IconName.Trash}
|
||||
>
|
||||
{t('removeAccount')}
|
||||
</MenuItem>
|
||||
|
@ -14,8 +14,7 @@ import { CONNECTED_ACCOUNTS_ROUTE } from '../../../helpers/constants/routes';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { getOriginOfCurrentTab } from '../../../selectors';
|
||||
import { MetaMetricsContext } from '../../../contexts/metametrics';
|
||||
import { ButtonIcon } from '../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName } from '../../component-library';
|
||||
import AccountOptionsMenu from './account-options-menu';
|
||||
|
||||
export default function MenuBar() {
|
||||
@ -41,7 +40,7 @@ export default function MenuBar() {
|
||||
<SelectedAccount />
|
||||
<span style={{ display: 'inherit' }} ref={ref}>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.MORE_VERTICAL}
|
||||
iconName={IconName.MoreVertical}
|
||||
className="menu-bar__account-options"
|
||||
data-testid="account-options-menu-button"
|
||||
ariaLabel={t('accountOptions')}
|
||||
|
@ -25,8 +25,7 @@ import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard';
|
||||
import { getAddressBookEntry } from '../../../../selectors';
|
||||
import { TokenStandard } from '../../../../../shared/constants/transaction';
|
||||
import NftCollectionImage from '../../../ui/nft-collection-image/nft-collection-image';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName } from '../../../component-library';
|
||||
|
||||
export default function ContractDetailsModal({
|
||||
onClose,
|
||||
@ -147,9 +146,7 @@ export default function ContractDetailsModal({
|
||||
<ButtonIcon
|
||||
display={DISPLAY.FLEX}
|
||||
iconName={
|
||||
copiedTokenAddress
|
||||
? ICON_NAMES.COPY_SUCCESS
|
||||
: ICON_NAMES.COPY
|
||||
copiedTokenAddress ? IconName.CopySuccess : IconName.Copy
|
||||
}
|
||||
onClick={() => handleCopyTokenAddress(tokenAddress)}
|
||||
color={Color.iconMuted}
|
||||
@ -163,7 +160,7 @@ export default function ContractDetailsModal({
|
||||
<Tooltip position="top" title={t('openInBlockExplorer')}>
|
||||
<ButtonIcon
|
||||
display={DISPLAY.FLEX}
|
||||
iconName={ICON_NAMES.EXPORT}
|
||||
iconName={IconName.Export}
|
||||
color={Color.iconMuted}
|
||||
onClick={() => {
|
||||
const blockExplorerTokenLink = getAccountLink(
|
||||
@ -244,7 +241,7 @@ export default function ContractDetailsModal({
|
||||
<ButtonIcon
|
||||
display={DISPLAY.FLEX}
|
||||
iconName={
|
||||
copiedToAddress ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY
|
||||
copiedToAddress ? IconName.CopySuccess : IconName.Copy
|
||||
}
|
||||
onClick={() => handleCopyToAddress(toAddress)}
|
||||
color={Color.iconMuted}
|
||||
@ -258,7 +255,7 @@ export default function ContractDetailsModal({
|
||||
<Tooltip position="top" title={t('openInBlockExplorer')}>
|
||||
<ButtonIcon
|
||||
display={DISPLAY.FLEX}
|
||||
iconName={ICON_NAMES.EXPORT}
|
||||
iconName={IconName.Export}
|
||||
color={Color.iconMuted}
|
||||
onClick={() => {
|
||||
const blockExplorerTokenLink = getAccountLink(
|
||||
|
@ -15,11 +15,11 @@ import Box from '../../../ui/box';
|
||||
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
|
||||
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
||||
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import {
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
ButtonIcon,
|
||||
ButtonIconSize,
|
||||
IconName,
|
||||
} from '../../../component-library';
|
||||
|
||||
const CustomizeNonce = ({
|
||||
hideModal,
|
||||
@ -58,9 +58,9 @@ const CustomizeNonce = ({
|
||||
{t('editNonceField')}
|
||||
</Typography>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.CLOSE}
|
||||
iconName={IconName.Close}
|
||||
className="customize-nonce-modal__close"
|
||||
size={ICON_SIZES.SM}
|
||||
size={ButtonIconSize.Sm}
|
||||
ariaLabel={t('close')}
|
||||
onClick={hideModal}
|
||||
/>
|
||||
|
@ -10,11 +10,11 @@ import {
|
||||
calcTokenAmount,
|
||||
toPrecisionWithoutTrailingZeros,
|
||||
} from '../../../../../shared/lib/transactions-controller-utils';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import {
|
||||
ICON_SIZES,
|
||||
ICON_NAMES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
ButtonIcon,
|
||||
ButtonIconSize,
|
||||
IconName,
|
||||
} from '../../../component-library';
|
||||
|
||||
const MAX_UNSIGNED_256_INT = new BigNumber(2).pow(256).minus(1).toString(10);
|
||||
|
||||
@ -63,8 +63,8 @@ export default class EditApprovalPermission extends PureComponent {
|
||||
{t('editPermission')}
|
||||
</div>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.CLOSE}
|
||||
size={ICON_SIZES.LG}
|
||||
iconName={IconName.Close}
|
||||
size={ButtonIconSize.Lg}
|
||||
className="edit-approval-permission__header__close"
|
||||
onClick={hideModal}
|
||||
/>
|
||||
|
@ -2,9 +2,13 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
|
||||
import Box from '../../../ui/box';
|
||||
import { Text, Button, BUTTON_TYPES } from '../../../component-library';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import {
|
||||
Text,
|
||||
Button,
|
||||
BUTTON_TYPES,
|
||||
ButtonIcon,
|
||||
IconName,
|
||||
} from '../../../component-library';
|
||||
import {
|
||||
AlignItems,
|
||||
DISPLAY,
|
||||
@ -47,7 +51,7 @@ const HoldToRevealModal = ({ onLongPressed, hideModal }) => {
|
||||
<Text variant={TextVariant.headingSm}>{t('holdToRevealTitle')}</Text>
|
||||
<ButtonIcon
|
||||
className="hold-to-reveal-modal__close"
|
||||
iconName={ICON_NAMES.CLOSE}
|
||||
iconName={IconName.Close}
|
||||
size={Size.SM}
|
||||
onClick={handleCancel}
|
||||
ariaLabel={t('close')}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Button from '../../../ui/button/button.component';
|
||||
import { ButtonIcon } from '../../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName } from '../../../component-library';
|
||||
|
||||
export default class NewAccountModal extends Component {
|
||||
static contextTypes = {
|
||||
@ -49,7 +48,7 @@ export default class NewAccountModal extends Component {
|
||||
className="new-account-modal__content__header-close"
|
||||
ariaLabel={t('close')}
|
||||
onClick={this.props.hideModal}
|
||||
iconName={ICON_NAMES.CLOSE}
|
||||
iconName={IconName.Close}
|
||||
/>
|
||||
</div>
|
||||
<div className="new-account-modal__input-label">
|
||||
|
@ -1,11 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Modal from '../../modal';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../../component-library';
|
||||
import { IconColor } from '../../../../helpers/constants/design-system';
|
||||
|
||||
export default class TransactionConfirmed extends PureComponent {
|
||||
@ -35,9 +31,9 @@ export default class TransactionConfirmed extends PureComponent {
|
||||
<Modal onSubmit={this.handleSubmit} submitText={t('ok')}>
|
||||
<div className="transaction-confirmed__content">
|
||||
<Icon
|
||||
name={ICON_NAMES.CHECK}
|
||||
name={IconName.Check}
|
||||
color={IconColor.successDefault}
|
||||
size={ICON_SIZES.XL}
|
||||
size={IconSize.Xl}
|
||||
/>
|
||||
<div className="transaction-confirmed__title">
|
||||
{`${t('confirmed')}!`}
|
||||
|
@ -18,11 +18,7 @@ import {
|
||||
import Chip from '../../ui/chip/chip';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { isNetworkLoading } from '../../../selectors';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
|
||||
export default function NetworkDisplay({
|
||||
indicatorSize,
|
||||
@ -70,9 +66,7 @@ export default function NetworkDisplay({
|
||||
</LoadingIndicator>
|
||||
}
|
||||
rightIcon={
|
||||
onClick ? (
|
||||
<Icon name={ICON_NAMES.ARROW_DOWN} size={ICON_SIZES.XS} />
|
||||
) : null
|
||||
onClick ? <Icon name={IconName.ArrowDown} size={IconSize.Xs} /> : null
|
||||
}
|
||||
label={
|
||||
networkType === NETWORK_TYPES.RPC
|
||||
|
@ -53,8 +53,7 @@ import {
|
||||
TokenStandard,
|
||||
} from '../../../../shared/constants/transaction';
|
||||
import NftDefaultImage from '../nft-default-image';
|
||||
import { ButtonIcon } from '../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName } from '../../component-library';
|
||||
import Tooltip from '../../ui/tooltip';
|
||||
import { decWEIToDecETH } from '../../../../shared/modules/conversion.utils';
|
||||
|
||||
@ -427,7 +426,7 @@ export default function NftDetails({ nft }) {
|
||||
handleAddressCopy(address);
|
||||
}}
|
||||
iconName={
|
||||
addressCopied ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY
|
||||
addressCopied ? IconName.CopySuccess : IconName.Copy
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import { I18nContext } from '../../../contexts/i18n';
|
||||
import { Menu, MenuItem } from '../../ui/menu';
|
||||
import { ButtonIcon } from '../../component-library/button-icon/deprecated';
|
||||
import { ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { ButtonIcon, IconName } from '../../component-library';
|
||||
import { Color } from '../../../helpers/constants/design-system';
|
||||
|
||||
const NftOptions = ({ onRemove, onViewOnOpensea }) => {
|
||||
@ -15,7 +14,7 @@ const NftOptions = ({ onRemove, onViewOnOpensea }) => {
|
||||
return (
|
||||
<div ref={ref}>
|
||||
<ButtonIcon
|
||||
iconName={ICON_NAMES.MORE_VERTICAL}
|
||||
iconName={IconName.MoreVertical}
|
||||
className="nft-options__button"
|
||||
data-testid="nft-options__button"
|
||||
onClick={() => setNftOptionsOpen(true)}
|
||||
@ -31,7 +30,7 @@ const NftOptions = ({ onRemove, onViewOnOpensea }) => {
|
||||
>
|
||||
{onViewOnOpensea ? (
|
||||
<MenuItem
|
||||
iconName={ICON_NAMES.EXPORT}
|
||||
iconName={IconName.Export}
|
||||
data-testid="nft-options__view-on-opensea"
|
||||
onClick={() => {
|
||||
setNftOptionsOpen(false);
|
||||
@ -42,7 +41,7 @@ const NftOptions = ({ onRemove, onViewOnOpensea }) => {
|
||||
</MenuItem>
|
||||
) : null}
|
||||
<MenuItem
|
||||
iconName={ICON_NAMES.TRASH}
|
||||
iconName={IconName.Trash}
|
||||
data-testid="nft-item-remove"
|
||||
onClick={() => {
|
||||
setNftOptionsOpen(false);
|
||||
|
@ -30,7 +30,7 @@ import { updateNftDropDownState } from '../../../store/actions';
|
||||
import { usePrevious } from '../../../hooks/usePrevious';
|
||||
import { getNftsDropdownState } from '../../../ducks/metamask/metamask';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../component-library';
|
||||
import NftDefaultImage from '../nft-default-image';
|
||||
|
||||
const width =
|
||||
@ -158,9 +158,7 @@ export default function NftsItems({
|
||||
</Box>
|
||||
<Box alignItems={AlignItems.flexEnd}>
|
||||
<Icon
|
||||
name={
|
||||
isExpanded ? ICON_NAMES.ARROW_DOWN : ICON_NAMES.ARROW_RIGHT
|
||||
}
|
||||
name={isExpanded ? IconName.ArrowDown : IconName.ArrowRight}
|
||||
color={Color.iconDefault}
|
||||
/>
|
||||
</Box>
|
||||
|
@ -11,12 +11,13 @@ import {
|
||||
TextColor,
|
||||
TextVariant,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { AvatarIcon, Text } from '../../component-library';
|
||||
import {
|
||||
AvatarIcon,
|
||||
Text,
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
IconName,
|
||||
IconSize,
|
||||
} from '../../component-library';
|
||||
import { formatDate } from '../../../helpers/utils/util';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import Tooltip from '../../ui/tooltip';
|
||||
@ -32,24 +33,24 @@ const PermissionCell = ({
|
||||
const t = useI18nContext();
|
||||
|
||||
let infoIconColor = IconColor.iconMuted;
|
||||
let infoIcon = ICON_NAMES.INFO;
|
||||
let iconColor = Color.primaryDefault;
|
||||
let infoIcon = IconName.Info;
|
||||
let iconColor = IconColor.primaryDefault;
|
||||
let iconBackgroundColor = Color.primaryMuted;
|
||||
|
||||
if (!revoked && weight === 1) {
|
||||
iconColor = Color.warningDefault;
|
||||
iconColor = IconColor.warningDefault;
|
||||
iconBackgroundColor = Color.warningMuted;
|
||||
infoIconColor = IconColor.warningDefault;
|
||||
infoIcon = ICON_NAMES.DANGER;
|
||||
infoIcon = IconName.Danger;
|
||||
}
|
||||
|
||||
if (dateApproved) {
|
||||
iconColor = Color.iconMuted;
|
||||
iconColor = IconColor.iconMuted;
|
||||
iconBackgroundColor = Color.backgroundAlternative;
|
||||
}
|
||||
|
||||
if (revoked) {
|
||||
iconColor = Color.iconMuted;
|
||||
iconColor = IconColor.iconMuted;
|
||||
iconBackgroundColor = Color.backgroundAlternative;
|
||||
}
|
||||
|
||||
@ -72,9 +73,9 @@ const PermissionCell = ({
|
||||
{typeof permissionIcon === 'string' ? (
|
||||
<AvatarIcon
|
||||
iconName={permissionIcon}
|
||||
size={ICON_SIZES.MD}
|
||||
size={IconSize.Md}
|
||||
iconProps={{
|
||||
size: ICON_SIZES.SM,
|
||||
size: IconSize.Sm,
|
||||
}}
|
||||
color={iconColor}
|
||||
backgroundColor={iconBackgroundColor}
|
||||
@ -108,7 +109,7 @@ const PermissionCell = ({
|
||||
</Box>
|
||||
<Box>
|
||||
<Tooltip html={<div>{description}</div>} position="bottom">
|
||||
<Icon color={infoIconColor} name={infoIcon} size={ICON_SIZES.SM} />
|
||||
<Icon color={infoIconColor} name={infoIcon} size={IconSize.Sm} />
|
||||
</Tooltip>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -16,7 +16,7 @@ import {
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import Identicon from '../../ui/identicon';
|
||||
import { shortenAddress } from '../../../helpers/utils/util';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../component-library';
|
||||
|
||||
const SetApproveForAllWarning = ({
|
||||
collectionName,
|
||||
@ -62,7 +62,7 @@ const SetApproveForAllWarning = ({
|
||||
className="set-approval-for-all-warning__content__header"
|
||||
>
|
||||
<Icon
|
||||
name={ICON_NAMES.DANGER}
|
||||
name={IconName.Danger}
|
||||
className="set-approval-for-all-warning__content__header__warning-icon"
|
||||
/>
|
||||
<Typography
|
||||
|
@ -17,7 +17,7 @@ import {
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import Identicon from '../../../ui/identicon';
|
||||
import { shortenAddress } from '../../../../helpers/utils/util';
|
||||
import { Icon, ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../../component-library';
|
||||
|
||||
const SignatureRequestOriginalWarning = ({
|
||||
senderAddress,
|
||||
@ -36,7 +36,7 @@ const SignatureRequestOriginalWarning = ({
|
||||
className="signature-request-warning__content__header"
|
||||
>
|
||||
<Icon
|
||||
name={ICON_NAMES.DANGER}
|
||||
name={IconName.Danger}
|
||||
color={IconColor.errorDefault}
|
||||
className="signature-request-warning__content__header__warning-icon"
|
||||
/>
|
||||
|
@ -6,7 +6,7 @@ import {
|
||||
JustifyContent,
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import Box from '../../../ui/box';
|
||||
import { Icon, ICON_NAMES } from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../../component-library';
|
||||
|
||||
const SignatureRequestSIWEIcon = () => {
|
||||
return (
|
||||
@ -17,7 +17,7 @@ const SignatureRequestSIWEIcon = () => {
|
||||
backgroundColor={Color.errorDefault}
|
||||
justifyContent={JustifyContent.center}
|
||||
>
|
||||
<Icon name={ICON_NAMES.DANGER} color={Color.errorInverse} />
|
||||
<Icon name={IconName.Danger} color={Color.errorInverse} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -2,11 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../component-library';
|
||||
|
||||
const TabBar = (props) => {
|
||||
const { tabs = [], onSelect, isActive } = props;
|
||||
@ -26,8 +22,8 @@ const TabBar = (props) => {
|
||||
<div className="tab-bar__tab__content__title">{content}</div>
|
||||
</div>
|
||||
<Icon
|
||||
name={ICON_NAMES.ARROW_RIGHT}
|
||||
size={ICON_SIZES.SM}
|
||||
name={IconName.ArrowRight}
|
||||
size={IconSize.Sm}
|
||||
className="tab-bar__tab__caret"
|
||||
/>
|
||||
</button>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Icon, ICON_NAMES } from '../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../component-library';
|
||||
import TabBar from '.';
|
||||
|
||||
export default {
|
||||
@ -19,12 +19,12 @@ export default {
|
||||
args: {
|
||||
tabs: [
|
||||
{
|
||||
icon: <Icon name={ICON_NAMES.SETTING} />,
|
||||
icon: <Icon name={IconName.Setting} />,
|
||||
content: 'General',
|
||||
key: 'general',
|
||||
},
|
||||
{
|
||||
icon: <Icon name={ICON_NAMES.BOOK} />,
|
||||
icon: <Icon name={IconName.Book} />,
|
||||
content: 'Contacts',
|
||||
key: 'contacts',
|
||||
},
|
||||
@ -39,7 +39,7 @@ export default {
|
||||
key: 'securityAndPrivacy',
|
||||
},
|
||||
{
|
||||
icon: <Icon name={ICON_NAMES.NOTIFICATION} />,
|
||||
icon: <Icon name={IconName.Notification} />,
|
||||
content: 'Alerts',
|
||||
key: 'alerts',
|
||||
},
|
||||
|
@ -12,22 +12,18 @@ import {
|
||||
TRANSACTION_CANCEL_ATTEMPTED_EVENT,
|
||||
TRANSACTION_CANCEL_SUCCESS_EVENT,
|
||||
} from '../transaction-activity-log.constants';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
ICON_SIZES,
|
||||
} from '../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName, IconSize } from '../../../component-library';
|
||||
import { Color } from '../../../../helpers/constants/design-system';
|
||||
|
||||
export const ACTIVITY_ICONS = {
|
||||
[TRANSACTION_CREATED_EVENT]: ICON_NAMES.ADD,
|
||||
[TRANSACTION_SUBMITTED_EVENT]: ICON_NAMES.ARROW_UP,
|
||||
[TRANSACTION_RESUBMITTED_EVENT]: ICON_NAMES.PROGRAMMING_ARROWS,
|
||||
[TRANSACTION_CONFIRMED_EVENT]: ICON_NAMES.CHECK,
|
||||
[TRANSACTION_DROPPED_EVENT]: ICON_NAMES.CLOSE,
|
||||
[TRANSACTION_ERRORED_EVENT]: ICON_NAMES.DANGER,
|
||||
[TRANSACTION_CANCEL_ATTEMPTED_EVENT]: ICON_NAMES.CLOSE,
|
||||
[TRANSACTION_CANCEL_SUCCESS_EVENT]: ICON_NAMES.CLOSE,
|
||||
[TRANSACTION_CREATED_EVENT]: IconName.Add,
|
||||
[TRANSACTION_SUBMITTED_EVENT]: IconName.ArrowUp,
|
||||
[TRANSACTION_RESUBMITTED_EVENT]: IconName.ProgrammingArrows,
|
||||
[TRANSACTION_CONFIRMED_EVENT]: IconName.Check,
|
||||
[TRANSACTION_DROPPED_EVENT]: IconName.Close,
|
||||
[TRANSACTION_ERRORED_EVENT]: IconName.Danger,
|
||||
[TRANSACTION_CANCEL_ATTEMPTED_EVENT]: IconName.Close,
|
||||
[TRANSACTION_CANCEL_SUCCESS_EVENT]: IconName.Close,
|
||||
};
|
||||
|
||||
export default class TransactionActivityLogIcon extends PureComponent {
|
||||
@ -47,7 +43,7 @@ export default class TransactionActivityLogIcon extends PureComponent {
|
||||
return (
|
||||
<div className={classnames('transaction-activity-log-icon', className)}>
|
||||
{icon ? (
|
||||
<Icon name={icon} color={Color.iconDefault} size={ICON_SIZES.SM} />
|
||||
<Icon name={icon} color={Color.iconDefault} size={IconSize.Sm} />
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
|
@ -4,10 +4,7 @@ import Tooltip from '../../../../../ui/tooltip/tooltip';
|
||||
import { I18nContext } from '../../../../../../contexts/i18n';
|
||||
|
||||
import { useCopyToClipboard } from '../../../../../../hooks/useCopyToClipboard';
|
||||
import {
|
||||
Icon,
|
||||
ICON_NAMES,
|
||||
} from '../../../../../component-library/icon/deprecated';
|
||||
import { Icon, IconName } from '../../../../../component-library';
|
||||
import { IconColor } from '../../../../../../helpers/constants/design-system';
|
||||
|
||||
const CopyRawData = ({ data }) => {
|
||||
@ -25,7 +22,7 @@ const CopyRawData = ({ data }) => {
|
||||
>
|
||||
<div className="copy-raw-data__icon">
|
||||
<Icon
|
||||
name={copied ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY}
|
||||
name={copied ? IconName.CopySuccess : IconName.Copy}
|
||||
color={IconColor.iconDefault}
|
||||
/>
|
||||
</div>
|
||||
|
@ -95,7 +95,7 @@ const EthOverview = ({ className }) => {
|
||||
/>
|
||||
}
|
||||
className={className}
|
||||
icon={<Identicon diameter={32} image={primaryTokenImage} imageBorder />}
|
||||
icon={<Identicon diameter={32} image={primaryTokenImage} />}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -73,6 +73,12 @@ function getActionFunctionById(id, history) {
|
||||
updateViewedNotifications({ 19: true });
|
||||
history.push(`${EXPERIMENTAL_ROUTE}#autodetect-nfts`);
|
||||
},
|
||||
20: () => {
|
||||
updateViewedNotifications({ 20: true });
|
||||
global.platform.openTab({
|
||||
url: ZENDESK_URLS.LEDGER_FIREFOX_U2F_GUIDE,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
return actionFunctions[id];
|
||||
|
@ -1,8 +1,38 @@
|
||||
# Component Library
|
||||
|
||||
**⚠️ THESE COMPONENTS HAVE BREAKING CHANGES ⚠️**
|
||||
This folder contains design system components that are built 1:1 with the Figma [DS Components](https://www.figma.com/file/HKpPKij9V3TpsyMV1TpV7C/DS-Components?node-id=16-6) UI kit and should be used where possible in all UI feature work.
|
||||
|
||||
This folder contains new design system(`DS 2.0`) components that will be used for the IA/Nav redesign work. They are currently a WIP and should not be used for feature work. That should change in the near future but for the time being please use existing UI components in `ui/components/ui`
|
||||
## Architecture
|
||||
|
||||
All components are built on top of the `Box` component and accept all `Box` [component props](https://metamask.github.io/metamask-storybook/?path=/docs/components-ui-box--default-story#props)
|
||||
|
||||
#### Layout
|
||||
|
||||
`component-library` components accept all utility props for layout
|
||||
|
||||
```
|
||||
import { Text } from '../../component-library'
|
||||
|
||||
<Text marginBottom={4}>This text has a margin-bottom of 16px</Text>
|
||||
```
|
||||
|
||||
#### Polymorphic `as` prop
|
||||
|
||||
`component-library` components accept a polymorphic as prop to change the root html element of a component
|
||||
|
||||
```
|
||||
import { Text } from '../../component-library'
|
||||
|
||||
<ul>
|
||||
<Text as="li">This renders as list item html element</Text>
|
||||
</ul>
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
We are currently in the process of migrating all component-library components to TypeScript. Feel free to contribute by creating a PR against one of [these issues](https://github.com/MetaMask/metamask-extension/issues?q=is%3Aissue+is%3Aopen+DS%2FExtension%2F2023%2FQ2%2FO1%2FKR3)
|
||||
|
||||
## Support
|
||||
|
||||
If internal folks have any questions please reach out the design system team via the internal slack channel [#metamask-design-system](https://consensys.slack.com/archives/C0354T27M5M) 💁
|
||||
|
||||
|
@ -59,7 +59,7 @@ The `AvatarBase` component can contain images, icons or text
|
||||
```jsx
|
||||
import { AvatarBase } from '../../component-library';
|
||||
<AvatarBase>
|
||||
<img src="./images/eth_logo.svg" />
|
||||
<img src="./images/eth_logo.png" />
|
||||
</AvatarBase>
|
||||
<AvatarBase>
|
||||
<img width="100%" src="./images/arbitrum.svg" />
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
BackgroundColor,
|
||||
BorderColor,
|
||||
TextColor,
|
||||
IconColor,
|
||||
DISPLAY,
|
||||
JustifyContent,
|
||||
AlignItems,
|
||||
@ -81,7 +82,10 @@ AvatarBase.propTypes = {
|
||||
* The color of the text inside the AvatarBase
|
||||
* Defaults to TextColor.textDefault
|
||||
*/
|
||||
color: PropTypes.oneOf(Object.values(TextColor)),
|
||||
color: PropTypes.oneOf([
|
||||
...Object.values(TextColor),
|
||||
...Object.values(IconColor),
|
||||
]),
|
||||
/**
|
||||
* Additional classNames to be added to the AvatarToken
|
||||
*/
|
||||
|
@ -110,7 +110,7 @@ export const Size = (args) => (
|
||||
export const Children = (args) => (
|
||||
<Box display={DISPLAY.FLEX} gap={1}>
|
||||
<AvatarBase {...args}>
|
||||
<img src="./images/eth_logo.svg" />
|
||||
<img src="./images/eth_logo.png" />
|
||||
</AvatarBase>
|
||||
<AvatarBase {...args}>
|
||||
<img width="100%" src="./images/arbitrum.svg" />
|
||||
|
@ -6,7 +6,7 @@ import { AvatarFavicon, AVATAR_FAVICON_SIZES } from '.';
|
||||
|
||||
describe('AvatarFavicon', () => {
|
||||
const args = {
|
||||
src: './images/eth_logo.svg',
|
||||
src: './images/eth_logo.png',
|
||||
name: 'test',
|
||||
};
|
||||
|
||||
|
@ -73,7 +73,10 @@ AvatarIcon.propTypes = {
|
||||
* The color of the text inside the AvatarIcon
|
||||
* Defaults to TextColor.primaryDefault
|
||||
*/
|
||||
color: PropTypes.oneOf(Object.values(TextColor)),
|
||||
color: PropTypes.oneOf([
|
||||
...Object.values(TextColor),
|
||||
...Object.values(IconColor),
|
||||
]),
|
||||
/**
|
||||
* Additional classNames to be added to the AvatarIcon
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ import { AvatarNetwork } from './avatar-network';
|
||||
describe('AvatarNetwork', () => {
|
||||
const args = {
|
||||
name: 'ethereum',
|
||||
src: './images/eth_logo.svg',
|
||||
src: './images/eth_logo.png',
|
||||
showHalo: false,
|
||||
};
|
||||
|
||||
|
@ -72,7 +72,7 @@ Use the `src` prop to set the image to be rendered of the `AvatarToken`.
|
||||
```jsx
|
||||
import { AvatarToken } from '../../component-library';
|
||||
|
||||
<AvatarToken src="./images/eth_logo.svg" />
|
||||
<AvatarToken src="./images/eth_logo.png" />
|
||||
<AvatarToken src="./images/arbitrum.svg" />
|
||||
<AvatarToken src="./images/bnb.png" />
|
||||
<AvatarToken src="https://static.metaswap.codefi.network/api/v1/tokenIcons/1/0x6b175474e89094c44da98b954eedeac495271d0f.png" />
|
||||
@ -92,7 +92,7 @@ Use the `showHalo` prop to display the component with halo effect. Only works if
|
||||
```jsx
|
||||
import { AvatarToken } from '../../component-library';
|
||||
|
||||
<AvatarToken src="./images/eth_logo.svg" showHalo />;
|
||||
<AvatarToken src="./images/eth_logo.png" showHalo />;
|
||||
```
|
||||
|
||||
### Color, Background Color And Border Color
|
||||
|
@ -61,7 +61,7 @@ export default {
|
||||
},
|
||||
args: {
|
||||
name: 'eth',
|
||||
src: './images/eth_logo.svg',
|
||||
src: './images/eth_logo.png',
|
||||
size: Size.MD,
|
||||
showHalo: false,
|
||||
},
|
||||
@ -126,7 +126,7 @@ export const SizeStory = (args) => (
|
||||
<BadgeWrapper
|
||||
badge={
|
||||
<AvatarNetwork
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
name="ETH"
|
||||
size={Size.XS}
|
||||
borderColor={BackgroundColor.backgroundDefault}
|
||||
@ -139,7 +139,7 @@ export const SizeStory = (args) => (
|
||||
<BadgeWrapper
|
||||
badge={
|
||||
<AvatarNetwork
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
name="ETH"
|
||||
size={Size.XS}
|
||||
borderColor={BackgroundColor.backgroundDefault}
|
||||
@ -152,7 +152,7 @@ export const SizeStory = (args) => (
|
||||
<BadgeWrapper
|
||||
badge={
|
||||
<AvatarNetwork
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
name="ETH"
|
||||
size={Size.XS}
|
||||
borderColor={BackgroundColor.backgroundDefault}
|
||||
@ -165,7 +165,7 @@ export const SizeStory = (args) => (
|
||||
<BadgeWrapper
|
||||
badge={
|
||||
<AvatarNetwork
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
name="ETH"
|
||||
size={Size.XS}
|
||||
borderColor={BackgroundColor.backgroundDefault}
|
||||
@ -178,7 +178,7 @@ export const SizeStory = (args) => (
|
||||
<BadgeWrapper
|
||||
badge={
|
||||
<AvatarNetwork
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
name="ETH"
|
||||
size={Size.SM}
|
||||
borderColor={BackgroundColor.backgroundDefault}
|
||||
@ -297,7 +297,7 @@ Name.args = {
|
||||
|
||||
export const Src = (args) => (
|
||||
<Box display={DISPLAY.FLEX} gap={1}>
|
||||
<AvatarToken {...args} src="./images/eth_logo.svg" />
|
||||
<AvatarToken {...args} src="./images/eth_logo.png" />
|
||||
<AvatarToken {...args} src="./images/arbitrum.svg" />
|
||||
<AvatarToken {...args} src="./images/bnb.png" />
|
||||
<AvatarToken
|
||||
|
@ -62,7 +62,7 @@ import {
|
||||
>
|
||||
<AvatarToken
|
||||
name="Eth"
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
borderColor={BorderColor.borderMuted}
|
||||
/>
|
||||
</BadgeWrapper>
|
||||
|
@ -114,7 +114,7 @@ export const Children: ComponentStory<typeof BadgeWrapper> = () => (
|
||||
>
|
||||
<AvatarToken
|
||||
name="Eth"
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
borderColor={BorderColor.borderMuted}
|
||||
/>
|
||||
</BadgeWrapper>
|
||||
|
@ -14,7 +14,7 @@ import {
|
||||
AlignItems,
|
||||
BackgroundColor,
|
||||
TextVariant,
|
||||
TEXT_ALIGN,
|
||||
TextAlign,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { HeaderBase } from './header-base';
|
||||
import README from './README.mdx';
|
||||
@ -37,7 +37,7 @@ export const DefaultStory = Template.bind({});
|
||||
|
||||
DefaultStory.args = {
|
||||
children: (
|
||||
<Text variant={TextVariant.headingSm} textAlign={TEXT_ALIGN.CENTER}>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TextAlign.Center}>
|
||||
Title is sentence case no period
|
||||
</Text>
|
||||
),
|
||||
@ -62,7 +62,7 @@ DefaultStory.storyName = 'Default';
|
||||
export const Children = (args) => {
|
||||
return (
|
||||
<HeaderBase {...args}>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TEXT_ALIGN.CENTER}>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TextAlign.Center}>
|
||||
Title is sentence case no period
|
||||
</Text>
|
||||
</HeaderBase>
|
||||
@ -82,7 +82,7 @@ export const StartAccessory = (args) => {
|
||||
}
|
||||
{...args}
|
||||
>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TEXT_ALIGN.CENTER}>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TextAlign.Center}>
|
||||
Title is sentence case no period
|
||||
</Text>
|
||||
</HeaderBase>
|
||||
@ -102,7 +102,7 @@ export const EndAccessory = (args) => {
|
||||
}
|
||||
{...args}
|
||||
>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TEXT_ALIGN.CENTER}>
|
||||
<Text variant={TextVariant.headingSm} textAlign={TextAlign.Center}>
|
||||
Title is sentence case no period
|
||||
</Text>
|
||||
</HeaderBase>
|
||||
@ -116,7 +116,7 @@ export const UseCaseDemos = (args) => (
|
||||
<HeaderBase marginBottom={4} {...args}>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
@ -139,7 +139,7 @@ export const UseCaseDemos = (args) => (
|
||||
>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
@ -162,7 +162,7 @@ export const UseCaseDemos = (args) => (
|
||||
>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
@ -193,7 +193,7 @@ export const UseCaseDemos = (args) => (
|
||||
>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
@ -225,7 +225,7 @@ export const UseCaseDemos = (args) => (
|
||||
>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
@ -260,7 +260,7 @@ export const UseCaseDemos = (args) => (
|
||||
>
|
||||
<Text
|
||||
variant={TextVariant.headingSm}
|
||||
textAlign={TEXT_ALIGN.CENTER}
|
||||
textAlign={TextAlign.Center}
|
||||
backgroundColor={BackgroundColor.primaryAlternative}
|
||||
>
|
||||
Title is sentence case no period
|
||||
|
@ -39,3 +39,4 @@ export { ModalOverlay } from './modal-overlay';
|
||||
export { BannerBase } from './banner-base';
|
||||
export { BannerAlert, BANNER_ALERT_SEVERITIES } from './banner-alert';
|
||||
export { BannerTip, BannerTipLogoType } from './banner-tip';
|
||||
export { PopoverHeader } from './popover-header';
|
||||
|
98
ui/components/component-library/popover-header/README.mdx
Normal file
98
ui/components/component-library/popover-header/README.mdx
Normal file
@ -0,0 +1,98 @@
|
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
|
||||
import { PopoverHeader } from './popover-header';
|
||||
|
||||
# PopoverHeader
|
||||
|
||||
PopoverHeader is built on top of [HeaderBase](/docs/components-componentlibrary-headerbase--default-story) component with the most common use case of a back button in the startAccessory position, title, and close button in the endAccessory position.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--default-story" />
|
||||
</Canvas>
|
||||
|
||||
## Props
|
||||
|
||||
The `PopoverHeader` accepts all props below as well as all [Box](/docs/ui-components-ui-box-box-stories-js--default-story#props) component props
|
||||
|
||||
<ArgsTable of={PopoverHeader} />
|
||||
|
||||
### Children
|
||||
|
||||
Wrapping string content in the `PopoverHeader` component will be rendered in the center of the header with the default title `Text` component.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--children" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { PopoverHeader } from '../../component-library';
|
||||
|
||||
<PopoverHeader>Title is sentence case no period</PopoverHeader>;
|
||||
```
|
||||
|
||||
### onBack
|
||||
|
||||
Use the onClick handler `onBack` prop to render the `ButtonIcon` back button in the startAccessory position.
|
||||
|
||||
Use the `backButtonProps` prop to pass additional props to the `ButtonIcon` back button.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--on-back" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { PopoverHeader } from '../../component-library';
|
||||
|
||||
<PopoverHeader onBack={() => console.log('Back button click')}>
|
||||
OnBack Demo
|
||||
</PopoverHeader>;
|
||||
```
|
||||
|
||||
### onClose
|
||||
|
||||
Use the onClick handler `onClose` prop to render the `ButtonIcon` back button in the endAccessory position.
|
||||
|
||||
Use the `backButtonProps` prop to pass additional props to the `ButtonIcon` back button.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--on-close" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { PopoverHeader } from '../../component-library';
|
||||
|
||||
<PopoverHeader onClose={() => console.log('Back button click')}>
|
||||
OnClose Demo
|
||||
</PopoverHeader>;
|
||||
```
|
||||
|
||||
### startAccessory
|
||||
|
||||
Use the `startAccessory` prop to render a component in the startAccessory position. This will override the default back `ButtonIcon`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--start-accessory" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { PopoverHeader, Button, BUTTON_SIZES } from '../../component-library';
|
||||
|
||||
<PopoverHeader startAccessory={<Button size={BUTTON_SIZES.SM}>Demo</Button>}>
|
||||
StartAccessory
|
||||
</PopoverHeader>;
|
||||
```
|
||||
|
||||
### endAccessory
|
||||
|
||||
Use the `endAccessory` prop to render a component in the endAccessory position. This will override the default close `ButtonIcon`.
|
||||
|
||||
<Canvas>
|
||||
<Story id="components-componentlibrary-popoverheader--end-accessory" />
|
||||
</Canvas>
|
||||
|
||||
```jsx
|
||||
import { PopoverHeader, Button, BUTTON_SIZES } from '../../component-library';
|
||||
|
||||
<PopoverHeader endAccessory={<Button size={BUTTON_SIZES.SM}>Demo</Button>}>
|
||||
EndAccessory
|
||||
</PopoverHeader>;
|
||||
```
|
@ -0,0 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`PopoverHeader should render PopoverHeader correctly 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="box mm-header-base mm-popover-header box--display-flex box--flex-direction-row box--justify-content-space-between"
|
||||
data-testid="popover-header"
|
||||
>
|
||||
<div
|
||||
class="box mm-header-base__children box--flex-direction-row box--width-full"
|
||||
>
|
||||
<h4
|
||||
class="box mm-text mm-text--heading-sm mm-text--text-align-center box--flex-direction-row box--color-text-default"
|
||||
>
|
||||
Popover Header
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
2
ui/components/component-library/popover-header/index.ts
Normal file
2
ui/components/component-library/popover-header/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { PopoverHeader } from './popover-header';
|
||||
export type { PopoverHeaderProps } from './popover-header.types';
|
@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||
import { BUTTON_SIZES, Button } from '..';
|
||||
import { PopoverHeader } from './popover-header';
|
||||
import README from './README.mdx';
|
||||
|
||||
export default {
|
||||
title: 'Components/ComponentLibrary/PopoverHeader',
|
||||
component: PopoverHeader,
|
||||
parameters: {
|
||||
docs: {
|
||||
page: README,
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
children: { control: 'text' },
|
||||
className: { control: 'text' },
|
||||
onBack: { action: 'onBack' },
|
||||
onClose: { action: 'onClose' },
|
||||
},
|
||||
args: {
|
||||
children: 'PopoverHeader',
|
||||
},
|
||||
} as ComponentMeta<typeof PopoverHeader>;
|
||||
|
||||
const Template: ComponentStory<typeof PopoverHeader> = (args) => {
|
||||
return <PopoverHeader {...args}>PopoverHeader</PopoverHeader>;
|
||||
};
|
||||
|
||||
export const DefaultStory = Template.bind({});
|
||||
DefaultStory.storyName = 'Default';
|
||||
|
||||
export const Children: ComponentStory<typeof PopoverHeader> = (args) => (
|
||||
<PopoverHeader {...args} />
|
||||
);
|
||||
|
||||
Children.args = {
|
||||
children: 'PopoverHeader Title',
|
||||
};
|
||||
|
||||
export const OnBack: ComponentStory<typeof PopoverHeader> = (args) => (
|
||||
<PopoverHeader {...args}>OnBack Demo</PopoverHeader>
|
||||
);
|
||||
|
||||
export const OnClose: ComponentStory<typeof PopoverHeader> = (args) => (
|
||||
<PopoverHeader {...args}>OnClose Demo</PopoverHeader>
|
||||
);
|
||||
|
||||
export const StartAccessory: ComponentStory<typeof PopoverHeader> = (args) => (
|
||||
<PopoverHeader
|
||||
startAccessory={<Button size={BUTTON_SIZES.SM}>Demo</Button>}
|
||||
{...args}
|
||||
>
|
||||
StartAccessory
|
||||
</PopoverHeader>
|
||||
);
|
||||
|
||||
export const EndAccessory: ComponentStory<typeof PopoverHeader> = (args) => (
|
||||
<PopoverHeader
|
||||
endAccessory={<Button size={BUTTON_SIZES.SM}>Demo</Button>}
|
||||
{...args}
|
||||
>
|
||||
EndAccessory
|
||||
</PopoverHeader>
|
||||
);
|
@ -0,0 +1,61 @@
|
||||
/* eslint-disable jest/require-top-level-describe */
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { PopoverHeader } from './popover-header';
|
||||
|
||||
describe('PopoverHeader', () => {
|
||||
it('should render PopoverHeader correctly', () => {
|
||||
const { getByTestId, container } = render(
|
||||
<PopoverHeader data-testid="popover-header">
|
||||
Popover Header
|
||||
</PopoverHeader>,
|
||||
);
|
||||
expect(getByTestId('popover-header')).toHaveClass('mm-popover-header');
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render popover header title', () => {
|
||||
const { getByText } = render(
|
||||
<PopoverHeader data-testid="popover-header">
|
||||
Popover Header Test
|
||||
</PopoverHeader>,
|
||||
);
|
||||
expect(getByText('Popover Header Test')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should render popover header back button', () => {
|
||||
const onBackTest = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<PopoverHeader
|
||||
data-testid="popover"
|
||||
onBack={onBackTest}
|
||||
backButtonProps={{ 'data-testid': 'back' }}
|
||||
>
|
||||
Popover
|
||||
</PopoverHeader>,
|
||||
);
|
||||
|
||||
const backButton = getByTestId('back');
|
||||
fireEvent.click(backButton);
|
||||
|
||||
expect(onBackTest).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should render popover header close button', () => {
|
||||
const onCloseTest = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<PopoverHeader
|
||||
data-testid="popover"
|
||||
onClose={onCloseTest}
|
||||
closeButtonProps={{ 'data-testid': 'close' }}
|
||||
>
|
||||
Popover
|
||||
</PopoverHeader>,
|
||||
);
|
||||
|
||||
const closeButton = getByTestId('close');
|
||||
fireEvent.click(closeButton);
|
||||
|
||||
expect(onCloseTest).toHaveBeenCalled();
|
||||
});
|
||||
});
|
@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { HeaderBase, Text, ButtonIcon, ButtonIconSize, IconName } from '..';
|
||||
import {
|
||||
TextVariant,
|
||||
TextAlign,
|
||||
} from '../../../helpers/constants/design-system';
|
||||
import { useI18nContext } from '../../../hooks/useI18nContext';
|
||||
import { PopoverHeaderProps } from '.';
|
||||
|
||||
export const PopoverHeader: React.FC<PopoverHeaderProps> = ({
|
||||
children,
|
||||
className = '',
|
||||
startAccessory,
|
||||
endAccessory,
|
||||
onClose,
|
||||
closeButtonProps,
|
||||
onBack,
|
||||
backButtonProps,
|
||||
...props
|
||||
}) => {
|
||||
const t = useI18nContext();
|
||||
return (
|
||||
<HeaderBase
|
||||
className={classnames('mm-popover-header', className)}
|
||||
startAccessory={
|
||||
startAccessory ||
|
||||
(onBack && (
|
||||
<ButtonIcon
|
||||
iconName={IconName.ArrowLeft}
|
||||
ariaLabel={t('back')}
|
||||
size={ButtonIconSize.Sm}
|
||||
onClick={onBack}
|
||||
{...backButtonProps}
|
||||
/>
|
||||
))
|
||||
}
|
||||
endAccessory={
|
||||
endAccessory ||
|
||||
(onClose && (
|
||||
<ButtonIcon
|
||||
iconName={IconName.Close}
|
||||
ariaLabel={t('close')}
|
||||
size={ButtonIconSize.Sm}
|
||||
onClick={onClose}
|
||||
{...closeButtonProps}
|
||||
/>
|
||||
))
|
||||
}
|
||||
{...props}
|
||||
>
|
||||
{typeof children === 'string' ? (
|
||||
<Text variant={TextVariant.headingSm} textAlign={TextAlign.Center}>
|
||||
{children}
|
||||
</Text>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</HeaderBase>
|
||||
);
|
||||
};
|
@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
import type { ButtonIconProps } from '../button-icon/button-icon.types';
|
||||
import type { HeaderBaseProps } from '../header-base';
|
||||
|
||||
export interface PopoverHeaderProps extends HeaderBaseProps {
|
||||
/**
|
||||
* The contents within the PopoverHeader positioned middle (popular for title use case)
|
||||
*/
|
||||
children?: React.ReactNode;
|
||||
/**
|
||||
* Additional classNames to be added to the Popover component
|
||||
*/
|
||||
className?: string;
|
||||
/**
|
||||
* The onClick handler for the back `ButtonIcon`
|
||||
* When passed this will allow for the back `ButtonIcon` to show
|
||||
*/
|
||||
onBack?: () => void;
|
||||
/**
|
||||
* The props to pass to the back `ButtonIcon`
|
||||
*/
|
||||
backButtonProps?: ButtonIconProps;
|
||||
/**
|
||||
* The start (left) content area of PopoverHeader
|
||||
* Default to have the back `ButtonIcon` when `onBack` is passed, but passing a `startAccessory` will override this
|
||||
*/
|
||||
startAccessory?: React.ReactNode;
|
||||
/**
|
||||
* The onClick handler for the close `ButtonIcon`
|
||||
* When passed this will allow for the close `ButtonIcon` to show
|
||||
*/
|
||||
onClose?: () => void;
|
||||
/**
|
||||
* The props to pass to the close `ButtonIcon`
|
||||
*/
|
||||
closeButtonProps?: ButtonIconProps;
|
||||
/**
|
||||
* The end (right) content area of PopoverHeader
|
||||
* Default to have the close `ButtonIcon` when `onClose` is passed, but passing a `endAccessory` will override this
|
||||
*/
|
||||
endAccessory?: React.ReactNode;
|
||||
}
|
@ -277,7 +277,7 @@ export const StartAccessoryEndAccessory = (args) => {
|
||||
>
|
||||
<AvatarToken
|
||||
name="eth"
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
size={Size.SM}
|
||||
/>
|
||||
<Text>ETH</Text>
|
||||
|
@ -28,7 +28,7 @@ exports[`MultichainTokenListItem should render correctly 1`] = `
|
||||
<img
|
||||
alt="undefined logo"
|
||||
class="mm-avatar-network__network-image"
|
||||
src="./images/eth_logo.svg"
|
||||
src="./images/eth_logo.png"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,7 +30,7 @@ export default {
|
||||
args: {
|
||||
secondary: '$9.80 USD',
|
||||
primary: '88.00687889',
|
||||
tokenImage: './images/eth_logo.svg',
|
||||
tokenImage: './images/eth_logo.png',
|
||||
tokenSymbol: 'ETH',
|
||||
title: 'Ethereum',
|
||||
},
|
||||
|
@ -40,7 +40,7 @@ WithImage.args = {
|
||||
addBorder: false,
|
||||
diameter: 32,
|
||||
useBlockie: false,
|
||||
image: './images/eth_logo.svg',
|
||||
image: './images/eth_logo.png',
|
||||
alt: 'Ethereum',
|
||||
imageBorder: true,
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ DefaultStory.storyName = 'Default';
|
||||
|
||||
DefaultStory.args = {
|
||||
name: 'eth',
|
||||
icon: './images/eth_logo.svg',
|
||||
icon: './images/eth_logo.png',
|
||||
size: 24,
|
||||
};
|
||||
|
||||
|
@ -6,7 +6,7 @@ describe('SiteIcon', () => {
|
||||
const args = {
|
||||
size: 32,
|
||||
name: 'Snap name',
|
||||
icon: './images/eth_logo.svg',
|
||||
icon: './images/eth_logo.png',
|
||||
className: 'classname-test',
|
||||
fallbackClassName: 'fallback-classname-test',
|
||||
};
|
||||
|
@ -15,6 +15,8 @@ const ZENDESK_URLS = {
|
||||
'https://metamask.zendesk.com/hc/en-us/articles/360015289932',
|
||||
INFURA_BLOCKAGE:
|
||||
'https://metamask.zendesk.com/hc/en-us/articles/360059386712',
|
||||
LEDGER_FIREFOX_U2F_GUIDE:
|
||||
'https://support.ledger.com/hc/en-us/articles/10371387758493-MetaMask-Firefox-Ledger-Integration-Issue?support=true',
|
||||
LEGACY_WEB3: 'https://metamask.zendesk.com/hc/en-us/articles/360053147012',
|
||||
NFT_TOKENS:
|
||||
'https://metamask.zendesk.com/hc/en-us/articles/360058238591-NFT-tokens-in-MetaMask-wallet',
|
||||
|
@ -261,17 +261,15 @@ export async function getAssetDetails(
|
||||
// if we can't determine any token standard or details return the data we can extract purely from the parsed transaction data
|
||||
return { toAddress, tokenId };
|
||||
}
|
||||
|
||||
const tokenValue = getTokenValueParam(tokenData);
|
||||
const tokenDecimals = tokenDetails?.decimals;
|
||||
const tokenAmount =
|
||||
tokenData &&
|
||||
tokenDetails?.decimals &&
|
||||
calcTokenAmount(
|
||||
getTokenValueParam(tokenData),
|
||||
tokenDetails?.decimals,
|
||||
).toString(10);
|
||||
tokenValue &&
|
||||
tokenDecimals &&
|
||||
calcTokenAmount(tokenValue, tokenDecimals).toString(10);
|
||||
|
||||
const decimals =
|
||||
tokenDetails?.decimals && Number(tokenDetails.decimals?.toString(10));
|
||||
const decimals = tokenDecimals && Number(tokenDecimals?.toString(10));
|
||||
|
||||
if (tokenDetails?.standard === TokenStandard.ERC20) {
|
||||
tokenId = undefined;
|
||||
|
@ -37,12 +37,16 @@ describe('useAssetDetails', () => {
|
||||
let getTokenStandardAndDetailsStub;
|
||||
|
||||
beforeEach(() => {
|
||||
getTokenStandardAndDetailsStub = jest
|
||||
.spyOn(Actions, 'getTokenStandardAndDetails')
|
||||
.mockImplementation(() => Promise.resolve({}));
|
||||
getTokenStandardAndDetailsStub = jest.spyOn(
|
||||
Actions,
|
||||
'getTokenStandardAndDetails',
|
||||
);
|
||||
});
|
||||
|
||||
it('should return object with tokenSymbol set to an empty string, when getAssetDetails returns and empty object', async () => {
|
||||
getTokenStandardAndDetailsStub.mockImplementation(() =>
|
||||
Promise.resolve({}),
|
||||
);
|
||||
const toAddress = '000000000000000000000000000000000000dead';
|
||||
const tokenAddress = '0x1';
|
||||
|
||||
@ -106,6 +110,46 @@ describe('useAssetDetails', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should return object with correct tokenValues for an ERC20 token with no decimals', async () => {
|
||||
const userAddress = '0xf04a5cc80b1e94c69b48f5ee68a08cd2f09a7c3e';
|
||||
const tokenAddress = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
|
||||
const toAddress = '000000000000000000000000000000000000dead';
|
||||
const transactionData = `0xa9059cbb000000000000000000000000${toAddress}00000000000000000000000000000000000000000000000000000000000001f4`;
|
||||
|
||||
const standard = TokenStandard.ERC20;
|
||||
const symbol = 'WETH';
|
||||
const balance = '1';
|
||||
|
||||
getTokenStandardAndDetailsStub.mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
standard,
|
||||
balance,
|
||||
symbol,
|
||||
}),
|
||||
);
|
||||
|
||||
const { result, waitForNextUpdate } = renderUseAssetDetails({
|
||||
tokenAddress,
|
||||
userAddress,
|
||||
transactionData,
|
||||
});
|
||||
|
||||
await waitForNextUpdate();
|
||||
|
||||
expect(result.current).toStrictEqual({
|
||||
assetAddress: tokenAddress,
|
||||
assetName: undefined,
|
||||
assetStandard: standard,
|
||||
toAddress: `0x${toAddress}`,
|
||||
tokenAmount: undefined,
|
||||
tokenId: undefined,
|
||||
tokenImage: undefined,
|
||||
tokenSymbol: symbol,
|
||||
userBalance: balance,
|
||||
decimals: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('should return object with correct tokenValues for an ERC721 token', async () => {
|
||||
const tokenAddress = '0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D';
|
||||
const toAddress = '000000000000000000000000000000000000dead';
|
||||
|
@ -1,107 +1,65 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React, { useEffect } from 'react';
|
||||
import { text } from '@storybook/addon-knobs';
|
||||
import { store, getNewState } from '../../../.storybook/preview';
|
||||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { suggestedAssets as mockSuggestedAssets } from '../../../.storybook/initial-states/approval-screens/add-suggested-token';
|
||||
import { updateMetamaskState } from '../../store/actions';
|
||||
|
||||
import configureStore from '../../store/store';
|
||||
|
||||
import mockState from '../../../.storybook/test-data';
|
||||
|
||||
import ConfirmAddSuggestedToken from '.';
|
||||
|
||||
const store = configureStore({
|
||||
metamask: {
|
||||
...mockState.metamask,
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [],
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
title: 'Pages/ConfirmAddSuggestedToken',
|
||||
|
||||
argTypes: {
|
||||
tokens: {
|
||||
control: 'array',
|
||||
table: { category: 'Data' },
|
||||
},
|
||||
suggestedAssets: {
|
||||
control: 'array',
|
||||
table: { category: 'Data' },
|
||||
},
|
||||
},
|
||||
decorators: [(story) => <Provider store={store}>{story()}</Provider>],
|
||||
};
|
||||
|
||||
const { metamask: state } = store.getState();
|
||||
|
||||
const PageSet = ({ children, suggestedAssets, tokens }) => {
|
||||
const symbol = text('symbol', 'META');
|
||||
const image = text('Icon URL', 'metamark.svg');
|
||||
|
||||
useEffect(() => {
|
||||
if (!suggestedAssets?.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
suggestedAssets[0].asset.image = image;
|
||||
suggestedAssets[0].asset.symbol = symbol;
|
||||
|
||||
store.dispatch(
|
||||
updateMetamaskState(
|
||||
getNewState(state, {
|
||||
suggestedAssets,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}, [image, suggestedAssets, symbol]);
|
||||
|
||||
useEffect(() => {
|
||||
store.dispatch(
|
||||
updateMetamaskState(
|
||||
getNewState(state, {
|
||||
tokens,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}, [tokens]);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
export const DefaultStory = ({ suggestedAssets, tokens }) => {
|
||||
return (
|
||||
<PageSet suggestedAssets={suggestedAssets} tokens={tokens}>
|
||||
<ConfirmAddSuggestedToken />
|
||||
</PageSet>
|
||||
);
|
||||
};
|
||||
export const DefaultStory = () => <ConfirmAddSuggestedToken />;
|
||||
DefaultStory.storyName = 'Default';
|
||||
DefaultStory.args = {
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [],
|
||||
};
|
||||
|
||||
export const WithDuplicateAddress = ({ suggestedAssets, tokens }) => {
|
||||
return (
|
||||
<PageSet suggestedAssets={suggestedAssets} tokens={tokens}>
|
||||
<ConfirmAddSuggestedToken />
|
||||
</PageSet>
|
||||
);
|
||||
};
|
||||
WithDuplicateAddress.args = {
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [
|
||||
{
|
||||
...mockSuggestedAssets[0].asset,
|
||||
},
|
||||
],
|
||||
};
|
||||
export const WithDuplicateAddress = () => <ConfirmAddSuggestedToken />;
|
||||
const WithDuplicateAddressStore = configureStore({
|
||||
metamask: {
|
||||
...mockState.metamask,
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [
|
||||
{
|
||||
...mockSuggestedAssets[0].asset,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
WithDuplicateAddress.decorators = [
|
||||
(story) => <Provider store={WithDuplicateAddressStore}>{story()}</Provider>,
|
||||
];
|
||||
|
||||
export const WithDuplicateSymbolAndDifferentAddress = ({
|
||||
suggestedAssets,
|
||||
tokens,
|
||||
}) => {
|
||||
return (
|
||||
<PageSet suggestedAssets={suggestedAssets} tokens={tokens}>
|
||||
<ConfirmAddSuggestedToken />
|
||||
</PageSet>
|
||||
);
|
||||
};
|
||||
WithDuplicateSymbolAndDifferentAddress.args = {
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [
|
||||
{
|
||||
...mockSuggestedAssets[0].asset,
|
||||
address: '0xNonSuggestedAddress',
|
||||
},
|
||||
],
|
||||
};
|
||||
export const WithDuplicateSymbolAndDifferentAddress = () => (
|
||||
<ConfirmAddSuggestedToken />
|
||||
);
|
||||
const WithDuplicateSymbolAndDifferentAddressStore = configureStore({
|
||||
metamask: {
|
||||
...mockState.metamask,
|
||||
suggestedAssets: [...mockSuggestedAssets],
|
||||
tokens: [
|
||||
{
|
||||
...mockSuggestedAssets[0].asset,
|
||||
address: '0xNonSuggestedAddress',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
WithDuplicateSymbolAndDifferentAddress.decorators = [
|
||||
(story) => (
|
||||
<Provider store={WithDuplicateSymbolAndDifferentAddressStore}>
|
||||
{story()}
|
||||
</Provider>
|
||||
),
|
||||
];
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user