diff --git a/.eslintrc.js b/.eslintrc.js
index 677ca3d98..3cc83ee1f 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -23,6 +23,7 @@ module.exports = {
'@metamask/eslint-config/config/nodejs',
'@metamask/eslint-config/config/mocha',
'plugin:react/recommended',
+ 'plugin:react-hooks/recommended',
],
plugins: [
diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json
index 7d30ec452..c279f5f17 100644
--- a/app/_locales/am/messages.json
+++ b/app/_locales/am/messages.json
@@ -648,9 +648,6 @@
"metamaskVersion": {
"message": "የ MetaMask ስሪት"
},
- "missingYourTokens": {
- "message": "ተለዋጭ ስሞችዎን አላዩም?"
- },
"mobileSyncText": {
"message": "እርስዎ መሆንዎትን ለማረጋገጥ እባከዎ የይለፍ ቃልዎን ያስገቡ!"
},
diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json
index a4ff5b403..46f240e2c 100644
--- a/app/_locales/ar/messages.json
+++ b/app/_locales/ar/messages.json
@@ -644,9 +644,6 @@
"metamaskVersion": {
"message": "إصدار MetaMask "
},
- "missingYourTokens": {
- "message": "لا تجد رموزك؟"
- },
"mobileSyncText": {
"message": "يرجى إدخال كلمة مرورك لتأكيد هويتك!"
},
diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json
index 44feb5321..668960321 100644
--- a/app/_locales/bg/messages.json
+++ b/app/_locales/bg/messages.json
@@ -647,9 +647,6 @@
"metamaskVersion": {
"message": "Версия на MetaMask"
},
- "missingYourTokens": {
- "message": "Не виждате жетоните си?"
- },
"mobileSyncText": {
"message": "Моля, въведете вашата парола, за да потвърдите, че сте вие!"
},
diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json
index 1b98f11c2..0b24f07a4 100644
--- a/app/_locales/bn/messages.json
+++ b/app/_locales/bn/messages.json
@@ -651,9 +651,6 @@
"metamaskVersion": {
"message": "MetaMask সংস্করণ"
},
- "missingYourTokens": {
- "message": "আপনার টোকেনগুলি দেখতে পাচ্ছেন না?"
- },
"mobileSyncText": {
"message": "এটি যে আপনি তা নিশ্চিত করতে অনুগ্রহ করে আপনার পাসওয়ার্ড লিখুন!"
},
diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json
index 11c658aa8..1d5eed571 100644
--- a/app/_locales/ca/messages.json
+++ b/app/_locales/ca/messages.json
@@ -635,9 +635,6 @@
"metamaskVersion": {
"message": "Versió MetaMask"
},
- "missingYourTokens": {
- "message": "No veus els teus tokens?"
- },
"mobileSyncText": {
"message": "Si us plau, introdueix la teva contrasenya per confirmar que ets tu!"
},
diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json
index 92867354d..136dd6a55 100644
--- a/app/_locales/da/messages.json
+++ b/app/_locales/da/messages.json
@@ -635,9 +635,6 @@
"metamaskDescription": {
"message": "Som forbinder dig til Ethereum og de decentraliserede internet."
},
- "missingYourTokens": {
- "message": "Kan du ikke se dine tokens?"
- },
"mobileSyncText": {
"message": "Indtast din adgangskode for at bekræfte, at det er dig!"
},
diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json
index 8778d28fc..14192b687 100644
--- a/app/_locales/de/messages.json
+++ b/app/_locales/de/messages.json
@@ -627,9 +627,6 @@
"metamaskVersion": {
"message": "MetaMask-Version"
},
- "missingYourTokens": {
- "message": "Sie können Ihre Token nicht sehen?"
- },
"mobileSyncText": {
"message": "Bitte geben Sie Ihr Passwort ein, um Ihre Identität zu verifizieren!"
},
diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json
index f0ca2ba3b..7d021f7ab 100644
--- a/app/_locales/el/messages.json
+++ b/app/_locales/el/messages.json
@@ -648,9 +648,6 @@
"metamaskVersion": {
"message": "Έκδοση MetaMask "
},
- "missingYourTokens": {
- "message": "Δεν βλέπετε τα διακριτικά σας;"
- },
"mobileSyncText": {
"message": "Παρακαλούμε δώστε τον κωδικό πρόσβασής σας για να επιβεβαιώσετε ότι είστε εσείς!"
},
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index f86498776..60c283a29 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -26,13 +26,10 @@
"description": "$1 is the number of accounts"
},
"connectedAccountsEmptyDescription": {
- "message": "MetaMask is not connected this site. To connect to a decentralized app (dapp), find the connect button on their site."
+ "message": "MetaMask is not connected this site. To connect to a web3 site, find the connect button on their site."
},
- "primary": {
- "message": "Primary"
- },
- "lastActive": {
- "message": "Last active"
+ "currentAccountNotConnected": {
+ "message": "Your current account is not connected"
},
"switchToThisAccount": {
"message": "Switch to this account"
@@ -73,12 +70,6 @@
"showIncomingTransactionsDescription": {
"message": "Select this to use Etherscan to show incoming transactions in the transactions list"
},
- "cancelling": {
- "message": "Cancelling..."
- },
- "cancelledConnectionWithMetaMask": {
- "message": "Cancelled Connection With MetaMask"
- },
"chartOnlyAvailableEth": {
"message": "Chart only available on Ethereum networks."
},
@@ -88,12 +79,9 @@
"connectWithMetaMask": {
"message": "Connect With MetaMask"
},
- "connectingWithMetaMask": {
- "message": "Connecting With MetaMask..."
- },
"connectTo": {
"message": "Connect to $1",
- "description": "$1 is the name/origin of a site/dapp that the user can connect to metamask"
+ "description": "$1 is the name/origin of a web3 site/application that the user can connect to metamask"
},
"connectToAll": {
"message": "Connect to all your $1",
@@ -109,7 +97,7 @@
},
"connectToMultipleNumberOfAccounts": {
"message": "$1 accounts",
- "description": "$1 is the number of accounts to which the site/dapp is asking to connect; this will substitute $1 in connectToMultiple"
+ "description": "$1 is the number of accounts to which the web3 site/application is asking to connect; this will substitute $1 in connectToMultiple"
},
"contractInteraction": {
"message": "Contract Interaction"
@@ -148,6 +136,12 @@
"accountSelectionRequired": {
"message": "You need to select an account!"
},
+ "active": {
+ "message": "Active"
+ },
+ "activity": {
+ "message": "Activity"
+ },
"activityLog": {
"message": "activity log"
},
@@ -193,17 +187,11 @@
"alertsSettingsDescription": {
"message": "Enable or disable each alert"
},
- "alertSettingsSwitchToConnected": {
- "message": "Opening popup with an unconnected account selected"
- },
- "alertSettingsSwitchToConnectedDescription": {
- "message": "This alert is shown when you open the popup with an unconnected account selected."
- },
- "alertSettingsUnconnectedAccount": {
- "message": "Switching to an unconnected account"
- },
- "alertSettingsUnconnectedAccountDescription": {
- "message": "This alert is shown in the popup when you switch from a connected account to an unconnected account."
+ "alertSettingsUnconnectedAccount": {
+ "message": "Browsing a website with an unconnected account selected"
+ },
+ "alertSettingsUnconnectedAccountDescription": {
+ "message": "This alert is shown in the popup when you are browsing a connected Web3 site, but the currently selected account is not connected."
},
"allowOriginSpendToken": {
"message": "Allow $1 to spend your $2?",
@@ -242,6 +230,9 @@
"asset": {
"message": "Asset"
},
+ "assets": {
+ "message": "Assets"
+ },
"attemptingConnect": {
"message": "Attempting to connect to blockchain."
},
@@ -370,7 +361,7 @@
"message": "Confirmed"
},
"confirmPassword": {
- "message": "Confirm Password"
+ "message": "Confirm password"
},
"confirmSecretBackupPhrase": {
"message": "Confirm your Secret Backup Phrase"
@@ -784,10 +775,10 @@
"message": " Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
},
"importAccountSeedPhrase": {
- "message": "Import an Account with Seed Phrase"
+ "message": "Import an account with seed phrase"
},
"importWallet": {
- "message": "Import Wallet"
+ "message": "Import wallet"
},
"importYourExisting": {
"message": "Import your existing wallet using a 12 word seed phrase"
@@ -929,9 +920,6 @@
"metamaskVersion": {
"message": "MetaMask Version"
},
- "missingYourTokens": {
- "message": "Don't see your tokens?"
- },
"mobileSyncText": {
"message": "Please enter your password to confirm it's you!"
},
@@ -986,7 +974,7 @@
"message": "New Contract"
},
"newPassword": {
- "message": "New Password (min 8 chars)"
+ "message": "New password (min 8 chars)"
},
"newNetwork": {
"message": "New Network"
@@ -997,9 +985,6 @@
"noAlreadyHaveSeed": {
"message": "No, I already have a seed phrase"
},
- "notConnected": {
- "message": "Not connected"
- },
"protectYourKeys": {
"message": "Protect Your Keys!"
},
@@ -1015,6 +1000,9 @@
"onlyConnectTrust": {
"message": "Only connect with sites you trust."
},
+ "onlyAddTrustedNetworks": {
+ "message": "A malicious Ethereum network provider can lie about the state of the blockchain and record your network activity. Only add custom networks you trust."
+ },
"optionalChainId": {
"message": "ChainID (optional)"
},
@@ -1090,7 +1078,7 @@
"description": "For importing an account from a private key"
},
"pending": {
- "message": "pending"
+ "message": "Pending"
},
"permissionCheckedIconDescription": {
"message": "You have approved this permission"
@@ -1281,6 +1269,12 @@
"seedPhrasePlaceholder": {
"message": "Separate each word with a single space"
},
+ "seedPhrasePlaceholderPaste": {
+ "message": "Paste seed phrase from clipboard"
+ },
+ "showSeedPhrase": {
+ "message": "Show seed phrase"
+ },
"seedPhraseReq": {
"message": "Seed phrases contain 12, 15, 18, 21, or 24 words"
},
@@ -1305,6 +1299,9 @@
"selectType": {
"message": "Select Type"
},
+ "buy": {
+ "message": "Buy"
+ },
"send": {
"message": "Send"
},
@@ -1455,10 +1452,10 @@
"message": "Select the account you want to view. You can only choose one at a time."
},
"step3HardwareWallet": {
- "message": "3. Start using dApps and more!"
+ "message": "3. Start using web3 sites and more!"
},
"step3HardwareWalletMsg": {
- "message": "Use your hardware account like you would with any Ethereum account. Connect to dApps, send ETH, buy and store ERC20 tokens and non-fungible tokens like CryptoKitties."
+ "message": "Use your hardware account like you would with any Ethereum account. Connect to web3 sites, send ETH, buy and store ERC20 tokens and non-fungible tokens like CryptoKitties."
},
"storePhrase": {
"message": "Store this phrase in a password manager like 1Password."
@@ -1472,16 +1469,6 @@
"supportCenter": {
"message": "Visit our Support Center"
},
- "switchAccounts": {
- "message": "Switch accounts"
- },
- "switchToConnectedAlertMultipleAccountsDescription": {
- "message": "This account is not connected. Switch to a connected account?"
- },
- "switchToConnectedAlertSingleAccountDescription": {
- "message": "This account is not connected. Switch to a connected account ($1)?",
- "description": "$1 will be replaced by the name of the connected account"
- },
"symbol": {
"message": "Symbol"
},
@@ -1600,6 +1587,9 @@
"transactionTime": {
"message": "Transaction Time"
},
+ "showTransactionTimeDescription": {
+ "message": "Select this to display pending transaction time estimates in the activity tab while on the Main Ethereum Network. Note: estimates are approximations based on network conditions."
+ },
"transfer": {
"message": "Transfer"
},
@@ -1626,10 +1616,7 @@
"unapproved": {
"message": "Unapproved"
},
- "unconnectedAccountAlertDescription": {
- "message": "$1 is not connected to $2."
- },
- "unconnectedAccountAlertDisableTooltip": {
+ "alertDisableTooltip": {
"message": "This can be changed in \"Settings > Alerts\""
},
"units": {
@@ -1702,7 +1689,7 @@
"message": "Visit our web site"
},
"walletSeed": {
- "message": "Wallet Seed"
+ "message": "Seed phrase"
},
"welcomeBack": {
"message": "Welcome Back!"
@@ -1746,7 +1733,7 @@
},
"decryptMessageNotice": {
"message": "$1 would like to read this message to complete your action",
- "description": "$1 is website or dapp name"
+ "description": "$1 is the web3 site name"
},
"decryptMetamask": {
"message": "Decrypt message"
@@ -1766,12 +1753,6 @@
},
"encryptionPublicKeyNotice": {
"message": "$1 would like your public encryption key. By consenting, this site will be able to compose encrypted messages to you.",
- "description": "$1 is website or dapp name"
- },
- "thisSite": {
- "message": "this site"
- },
- "thisAccount": {
- "message": "This account"
+ "description": "$1 is the web3 site name"
}
}
diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json
index 8c52642d6..d513a2f19 100644
--- a/app/_locales/es/messages.json
+++ b/app/_locales/es/messages.json
@@ -527,9 +527,6 @@
"metamaskVersion": {
"message": "Versión de MetaMask"
},
- "missingYourTokens": {
- "message": "¿No ves tus tokens?"
- },
"myAccounts": {
"message": "Mis cuentas"
},
diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json
index 88f08edd6..8a83b65e8 100644
--- a/app/_locales/es_419/messages.json
+++ b/app/_locales/es_419/messages.json
@@ -636,9 +636,6 @@
"metamaskVersion": {
"message": "Versión de MetaMask"
},
- "missingYourTokens": {
- "message": "¿No puedes ver tus tokens?"
- },
"mobileSyncText": {
"message": "Ingresa tu contraseña para confirmar que eres tú."
},
diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json
index cd2fd0611..5f1ca3132 100644
--- a/app/_locales/et/messages.json
+++ b/app/_locales/et/messages.json
@@ -641,9 +641,6 @@
"metamaskVersion": {
"message": "MetaMaski versioon"
},
- "missingYourTokens": {
- "message": "Te ei näe oma lube?"
- },
"mobileSyncText": {
"message": "Sisestage parool, et saaksime teid tuvastada!"
},
diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json
index 81570c579..d59bb3f32 100644
--- a/app/_locales/fa/messages.json
+++ b/app/_locales/fa/messages.json
@@ -651,9 +651,6 @@
"metamaskVersion": {
"message": "نسخه MetaMask"
},
- "missingYourTokens": {
- "message": "آیا رمزیاب های تان را نمیبیند؟"
- },
"mobileSyncText": {
"message": "لطفًا رمز عبور را وارد نمایید تا تأیید شود که خود شما هستید!"
},
diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json
index dad9c42b5..a67ef40ea 100644
--- a/app/_locales/fi/messages.json
+++ b/app/_locales/fi/messages.json
@@ -648,9 +648,6 @@
"metamaskVersion": {
"message": "MetaMask-versio"
},
- "missingYourTokens": {
- "message": "Etkö näe tietueitasi?"
- },
"mobileSyncText": {
"message": "Vahvista henkilöllisyytesi antamalla salasanasi!"
},
diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json
index 9f8cd1f2a..d925e9f63 100644
--- a/app/_locales/fil/messages.json
+++ b/app/_locales/fil/messages.json
@@ -589,9 +589,6 @@
"metamaskVersion": {
"message": "Bersyon ng MetaMask"
},
- "missingYourTokens": {
- "message": "Hindi mo ba nakikita ang iyong mga token?"
- },
"mobileSyncText": {
"message": "Pakilagay ang iyong password para kumpirmahing ikaw ito!"
},
diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json
index 76273f0d0..7d28b3a0a 100644
--- a/app/_locales/fr/messages.json
+++ b/app/_locales/fr/messages.json
@@ -633,9 +633,6 @@
"metamaskVersion": {
"message": "Version de MetaMask"
},
- "missingYourTokens": {
- "message": "Vous ne voyez pas vos jetons ?"
- },
"mobileSyncText": {
"message": "Veuillez entrer votre mot de passe pour confirmer que c'est bien vous !"
},
diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json
index 74f6fc9eb..7fdd31a89 100644
--- a/app/_locales/he/messages.json
+++ b/app/_locales/he/messages.json
@@ -648,9 +648,6 @@
"metamaskVersion": {
"message": "גרסת MetaMask"
},
- "missingYourTokens": {
- "message": "אין באפשרותך לראות את הטוקנים שלך?"
- },
"mobileSyncText": {
"message": "נא להזין את הססמה שלך כדי לאשר שזה/זו אכן את/ה!"
},
diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json
index 6df3a9cbd..1686b79df 100644
--- a/app/_locales/hi/messages.json
+++ b/app/_locales/hi/messages.json
@@ -648,9 +648,6 @@
"metamaskVersion": {
"message": "MetaMask का संस्करण"
},
- "missingYourTokens": {
- "message": "अपने टोकन को देख नहीं पा रहें हैं?"
- },
"mobileSyncText": {
"message": "यह आप ही हैं इसकी पुष्टि करने के लिए कृपया अपना पासवर्ड दर्ज करें!"
},
diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json
index df0e4af15..bc4d39ff4 100644
--- a/app/_locales/hr/messages.json
+++ b/app/_locales/hr/messages.json
@@ -644,9 +644,6 @@
"metamaskVersion": {
"message": "Inačica usluge MetaMask"
},
- "missingYourTokens": {
- "message": "Ne vidite svoje tokene?"
- },
"mobileSyncText": {
"message": "Upišite svoju lozinku kako biste potvrdili da ste to vi!"
},
diff --git a/app/_locales/ht/messages.json b/app/_locales/ht/messages.json
index a2526ad88..c60e60c5a 100644
--- a/app/_locales/ht/messages.json
+++ b/app/_locales/ht/messages.json
@@ -383,9 +383,6 @@
"metamaskVersion": {
"message": "MetaMask Vèsyon"
},
- "missingYourTokens": {
- "message": "Ou pa wè token ou a?"
- },
"myAccounts": {
"message": "Kont mwen"
},
diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json
index bbeb0710a..84be04277 100644
--- a/app/_locales/hu/messages.json
+++ b/app/_locales/hu/messages.json
@@ -644,9 +644,6 @@
"metamaskVersion": {
"message": "MetaMask verzió"
},
- "missingYourTokens": {
- "message": "Nem látja az érméit?"
- },
"mobileSyncText": {
"message": "Kérünk írd be jelszavad, hogy igazold kiléted!"
},
diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json
index 44c7416f4..7d942d231 100644
--- a/app/_locales/id/messages.json
+++ b/app/_locales/id/messages.json
@@ -632,9 +632,6 @@
"metamaskVersion": {
"message": "Versi MetaMask"
},
- "missingYourTokens": {
- "message": "Tidak melihat token Anda?"
- },
"mobileSyncText": {
"message": "Harap masukkan sandi untuk mengonfirmasi ini memang Anda!"
},
diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json
index 0e2b45233..a12481f1a 100644
--- a/app/_locales/it/messages.json
+++ b/app/_locales/it/messages.json
@@ -5,18 +5,12 @@
"showIncomingTransactionsDescription": {
"message": "Usa Etherscan per visualizzare le transazioni in ingresso nella lista delle transazioni"
},
- "cancelledConnectionWithMetaMask": {
- "message": "Transazioni Annullate con MetaMask"
- },
"chartOnlyAvailableEth": {
"message": "Grafico disponibile solo per le reti Ethereum."
},
"connectedSites": {
"message": "Siti connessi"
},
- "connectingWithMetaMask": {
- "message": "Connettendo con MetaMask..."
- },
"connectTo": {
"message": "Collegati a $1",
"description": "$1 is the name/origin of a site/dapp that the user can connect to metamask"
@@ -789,9 +783,6 @@
"metamaskVersion": {
"message": "versione di MetaMask"
},
- "missingYourTokens": {
- "message": "Non vedi i tuoi token?"
- },
"mobileSyncText": {
"message": "Per favore inserisci la password per confermare che sei te!"
},
diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json
index fd1b6110d..7b8f6253f 100644
--- a/app/_locales/kn/messages.json
+++ b/app/_locales/kn/messages.json
@@ -651,9 +651,6 @@
"metamaskVersion": {
"message": "MetaMask ಆವೃತ್ತಿ"
},
- "missingYourTokens": {
- "message": "ನಿಮ್ಮ ಟೋಕನ್ಗಳು ಕಾಣಿಸುತ್ತಿಲ್ಲವೇ?"
- },
"mobileSyncText": {
"message": "ಇದು ನೀವೇ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಲು ದಯವಿಟ್ಟು ನಿಮ್ಮ ಪಾಸ್ವರ್ಡ್ ಅನ್ನು ನಮೂದಿಸಿ!"
},
diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json
index 6fbe305be..18f302c7d 100644
--- a/app/_locales/ko/messages.json
+++ b/app/_locales/ko/messages.json
@@ -645,9 +645,6 @@
"metamaskVersion": {
"message": "메타마스크 버전"
},
- "missingYourTokens": {
- "message": "당신의 토큰이 보이지 않나요?"
- },
"mobileSyncText": {
"message": "본인 여부를 확인하기 위해 비밀번호를 입력해 주세요!"
},
diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json
index fcc5b33f6..30fa9dd23 100644
--- a/app/_locales/lt/messages.json
+++ b/app/_locales/lt/messages.json
@@ -651,9 +651,6 @@
"metamaskVersion": {
"message": "„MetaMask“ versija"
},
- "missingYourTokens": {
- "message": "Nematote savo žetonų?"
- },
"mobileSyncText": {
"message": "Įveskite savo slaptažodį, kad patvirtintumėte, jog tai tikrai jūs!"
},
diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json
index 38895f49e..f06839e6c 100644
--- a/app/_locales/lv/messages.json
+++ b/app/_locales/lv/messages.json
@@ -647,9 +647,6 @@
"metamaskVersion": {
"message": "MetaMask versija"
},
- "missingYourTokens": {
- "message": "Neredzat savus marķierus?"
- },
"mobileSyncText": {
"message": "Lūdzu, ievadiet paroli, lai apstiprinātu, ka tas esat jūs."
},
diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json
index 1071db2bd..1cc5cd6bb 100644
--- a/app/_locales/ms/messages.json
+++ b/app/_locales/ms/messages.json
@@ -625,9 +625,6 @@
"metamaskVersion": {
"message": "Versi MetaMask"
},
- "missingYourTokens": {
- "message": "Tidak nampak token anda?"
- },
"mobileSyncText": {
"message": "Sila masukkan kata laluan anda untuk mengesahkan ini memang anda!"
},
diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json
index b53fde4f6..f4352505d 100644
--- a/app/_locales/no/messages.json
+++ b/app/_locales/no/messages.json
@@ -641,9 +641,6 @@
"metamaskVersion": {
"message": "MetaMask-versjon "
},
- "missingYourTokens": {
- "message": "Ser du ikke sjetongene dine?"
- },
"mobileSyncText": {
"message": "Vennligst skriv inn passordet ditt for å bekrefte at det er deg!"
},
diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json
index 069aca5b9..a3d06bba8 100644
--- a/app/_locales/pl/messages.json
+++ b/app/_locales/pl/messages.json
@@ -645,9 +645,6 @@
"metamaskVersion": {
"message": "Wersja MetaMask"
},
- "missingYourTokens": {
- "message": "Nie widzisz swoich token?"
- },
"mobileSyncText": {
"message": "Wpisz hasło, aby potwierdzić, że to Ty!"
},
diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json
index 70dbed539..4a5b2efbe 100644
--- a/app/_locales/pt_BR/messages.json
+++ b/app/_locales/pt_BR/messages.json
@@ -639,9 +639,6 @@
"metamaskVersion": {
"message": "Versão do MetaMask"
},
- "missingYourTokens": {
- "message": "Não está vendo seus tokens?"
- },
"mobileSyncText": {
"message": "Insira sua senha para confirmar que é você!"
},
diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json
index 6e73bd0ab..40cc1f2d5 100644
--- a/app/_locales/ro/messages.json
+++ b/app/_locales/ro/messages.json
@@ -638,9 +638,6 @@
"metamaskVersion": {
"message": "Versiune MetaMask"
},
- "missingYourTokens": {
- "message": "Nu vă vedeți token-urile?"
- },
"mobileSyncText": {
"message": "Vă rugăm introduceți parola pentru a vă confirma identitatea!"
},
diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json
index 4739b0484..33d2e217e 100644
--- a/app/_locales/ru/messages.json
+++ b/app/_locales/ru/messages.json
@@ -868,9 +868,6 @@
"metamaskVersion": {
"message": "Версия MetaMask"
},
- "missingYourTokens": {
- "message": "Не видите свои токены?"
- },
"mobileSyncText": {
"message": "Пожалуйста, введите ваш пароль, чтобы подтвердить, что это вы!"
},
diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json
index dce4d6899..940c816ec 100644
--- a/app/_locales/sk/messages.json
+++ b/app/_locales/sk/messages.json
@@ -620,9 +620,6 @@
"metamaskVersion": {
"message": "Verzia MetaMask"
},
- "missingYourTokens": {
- "message": "Nevidíte svoje tokeny?"
- },
"mobileSyncText": {
"message": "Zadajte svoje heslo a potvrďte, že ste to vy!"
},
diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json
index 2605948e0..84fda7bb1 100644
--- a/app/_locales/sl/messages.json
+++ b/app/_locales/sl/messages.json
@@ -636,9 +636,6 @@
"metamaskVersion": {
"message": "Različica"
},
- "missingYourTokens": {
- "message": "Ne vidite vaših žetonov?"
- },
"mobileSyncText": {
"message": "Vnesite geslo in potrdite, da ste to vi."
},
diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json
index 24e855f88..fcbcb4cf9 100644
--- a/app/_locales/sr/messages.json
+++ b/app/_locales/sr/messages.json
@@ -642,9 +642,6 @@
"metamaskVersion": {
"message": "MetaMask verzija"
},
- "missingYourTokens": {
- "message": "Ne vidite svoje tokene?"
- },
"mobileSyncText": {
"message": "Molimo vas unesite šifru kako biste potvrdili da ste to vi!"
},
diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json
index 3efe883a1..944b710f1 100644
--- a/app/_locales/sv/messages.json
+++ b/app/_locales/sv/messages.json
@@ -635,9 +635,6 @@
"metamaskVersion": {
"message": "MetaMask-version"
},
- "missingYourTokens": {
- "message": "Ser du inte dina tokens?"
- },
"mobileSyncText": {
"message": "Var vänlig ange ditt lösenord för att bekräfta att det är du!"
},
diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json
index 3c757b81b..77e7268b5 100644
--- a/app/_locales/sw/messages.json
+++ b/app/_locales/sw/messages.json
@@ -629,9 +629,6 @@
"metamaskVersion": {
"message": "Toleo la MetaMask"
},
- "missingYourTokens": {
- "message": "Je, huoni vianzio vyako?"
- },
"mobileSyncText": {
"message": "Tafadhali ingiza nenosiri lako ili kuthibitisha kuwa ni wewe!"
},
diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json
index 6be7f6156..c9d389c78 100644
--- a/app/_locales/uk/messages.json
+++ b/app/_locales/uk/messages.json
@@ -651,9 +651,6 @@
"metamaskVersion": {
"message": "Версія MetaMask"
},
- "missingYourTokens": {
- "message": "Не бачите ваших токенів?"
- },
"mobileSyncText": {
"message": "Введіть пароль, щоб підтвердити свою особу!"
},
diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json
index 66fa5136c..05566ca8e 100644
--- a/app/_locales/zh_CN/messages.json
+++ b/app/_locales/zh_CN/messages.json
@@ -639,9 +639,6 @@
"metamaskVersion": {
"message": "MetaMask 版本"
},
- "missingYourTokens": {
- "message": "无法看到您的代币?"
- },
"mobileSyncText": {
"message": "请输入密码确认个人身份!"
},
diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json
index d05c038b4..532799252 100644
--- a/app/_locales/zh_TW/messages.json
+++ b/app/_locales/zh_TW/messages.json
@@ -645,9 +645,6 @@
"metamaskVersion": {
"message": "MetaMask 版本"
},
- "missingYourTokens": {
- "message": "看不到您的代幣?"
- },
"mobileSyncText": {
"message": "請輸入密碼確認身份!"
},
diff --git a/app/images/icons/connected-sites-black.svg b/app/images/icons/connected-sites.svg
similarity index 85%
rename from app/images/icons/connected-sites-black.svg
rename to app/images/icons/connected-sites.svg
index a2411b42b..4d90e233f 100644
--- a/app/images/icons/connected-sites-black.svg
+++ b/app/images/icons/connected-sites.svg
@@ -1,3 +1,3 @@
diff --git a/app/images/icons/disconnect.svg b/app/images/icons/disconnect.svg
index c51387353..146d6c727 100644
--- a/app/images/icons/disconnect.svg
+++ b/app/images/icons/disconnect.svg
@@ -1,3 +1,3 @@
diff --git a/app/scripts/background.js b/app/scripts/background.js
index cf273d31a..beaeb78c3 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -30,7 +30,6 @@ import NotificationManager from './lib/notification-manager.js'
import MetamaskController from './metamask-controller'
import rawFirstTimeState from './first-time-state'
import setupSentry from './lib/setupSentry'
-import reportFailedTxToSentry from './lib/reportFailedTxToSentry'
import getFirstPreferredLangCode from './lib/get-first-preferred-lang-code'
import getObjStructure from './lib/getObjStructure'
import setupEnsIpfsResolver from './lib/ens-ipfs/setup'
@@ -105,10 +104,8 @@ initialize().catch(log.error)
* @property {Object} contractExchangeRates - Info about current token prices.
* @property {Array} tokens - Tokens held by the current user, including their balances.
* @property {Object} send - TODO: Document
- * @property {Object} coinOptions - TODO: Document
* @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon.
* @property {Object} featureFlags - An object for optional feature flags.
- * @property {string} networkEndpointType - TODO: Document
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
* @property {string} currentLocale - A locale string matching the user's preferred display language.
* @property {Object} provider - The current selected network provider.
@@ -255,19 +252,6 @@ function setupController (initState, initLangCode) {
provider: controller.provider,
})
- // report failed transactions to Sentry
- controller.txController.on(`tx:status-update`, (txId, status) => {
- if (status !== 'failed') {
- return
- }
- const txMeta = controller.txController.txStateManager.getTx(txId)
- try {
- reportFailedTxToSentry({ sentry, txMeta })
- } catch (e) {
- console.error(e)
- }
- })
-
// setup state persistence
pump(
asStream(controller.store),
diff --git a/app/scripts/controllers/alert.js b/app/scripts/controllers/alert.js
index e2b477905..ff0d7fb89 100644
--- a/app/scripts/controllers/alert.js
+++ b/app/scripts/controllers/alert.js
@@ -12,7 +12,6 @@ import ObservableStore from 'obs-store'
*/
export const ALERT_TYPES = {
- switchToConnected: 'switchToConnected',
unconnectedAccount: 'unconnectedAccount',
}
@@ -25,7 +24,7 @@ const defaultState = {
},
{}
),
- switchToConnectedAlertShown: {},
+ unconnectedAccountAlertShownOrigins: {},
}
/**
@@ -44,7 +43,7 @@ export default class AlertController {
defaultState,
initState,
{
- switchToConnectedAlertShown: {},
+ unconnectedAccountAlertShownOrigins: {},
}
)
this.store = new ObservableStore(state)
@@ -54,9 +53,9 @@ export default class AlertController {
preferencesStore.subscribe(({ selectedAddress }) => {
const currentState = this.store.getState()
- if (currentState.switchToConnectedAlertShown && this.selectedAddress !== selectedAddress) {
+ if (currentState.unconnectedAccountAlertShownOrigins && this.selectedAddress !== selectedAddress) {
this.selectedAddress = selectedAddress
- this.store.updateState({ switchToConnectedAlertShown: {} })
+ this.store.updateState({ unconnectedAccountAlertShownOrigins: {} })
}
})
}
@@ -72,10 +71,10 @@ export default class AlertController {
* Sets the "switch to connected" alert as shown for the given origin
* @param {string} origin - The origin the alert has been shown for
*/
- setSwitchToConnectedAlertShown (origin) {
- let { switchToConnectedAlertShown } = this.store.getState()
- switchToConnectedAlertShown = { ...switchToConnectedAlertShown }
- switchToConnectedAlertShown[origin] = true
- this.store.updateState({ switchToConnectedAlertShown })
+ setUnconnectedAccountAlertShown (origin) {
+ let { unconnectedAccountAlertShownOrigins } = this.store.getState()
+ unconnectedAccountAlertShownOrigins = { ...unconnectedAccountAlertShownOrigins }
+ unconnectedAccountAlertShownOrigins[origin] = true
+ this.store.updateState({ unconnectedAccountAlertShownOrigins })
}
}
diff --git a/app/scripts/controllers/permissions/index.js b/app/scripts/controllers/permissions/index.js
index 876b2cd2f..4c55e7b8a 100644
--- a/app/scripts/controllers/permissions/index.js
+++ b/app/scripts/controllers/permissions/index.js
@@ -341,6 +341,24 @@ export class PermissionsController {
this.notifyAccountsChanged(origin, newPermittedAccounts)
}
+ /**
+ * Remove all permissions associated with a particular account. Any eth_accounts
+ * permissions left with no permitted accounts will be removed as well.
+ *
+ * Throws error if the account is invalid, or if the update fails.
+ *
+ * @param {string} account - The account to remove.
+ */
+ async removeAllAccountPermissions (account) {
+ this.validatePermittedAccounts([account])
+
+ const domains = this.permissions.getDomains()
+ const connectedOrigins = Object.keys(domains)
+ .filter((origin) => this._getPermittedAccounts(origin).includes(account))
+
+ await Promise.all(connectedOrigins.map((origin) => this.removePermittedAccount(origin, account)))
+ }
+
/**
* Finalizes a permissions request. Throws if request validation fails.
* Clones the passed-in parameters to prevent inadvertent modification.
diff --git a/app/scripts/controllers/token-rates.js b/app/scripts/controllers/token-rates.js
index 6724ede3d..4ef8b8ff8 100644
--- a/app/scripts/controllers/token-rates.js
+++ b/app/scripts/controllers/token-rates.js
@@ -27,9 +27,6 @@ export default class TokenRatesController {
* Updates exchange rates for all tokens
*/
async updateExchangeRates () {
- if (!this.isActive) {
- return
- }
const contractExchangeRates = {}
const nativeCurrency = this.currency ? this.currency.state.nativeCurrency.toLowerCase() : 'eth'
const pairs = this._tokens.map((token) => token.address).join(',')
diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js
index 87f9e9134..cdb922c7d 100644
--- a/app/scripts/controllers/transactions/tx-gas-utils.js
+++ b/app/scripts/controllers/transactions/tx-gas-utils.js
@@ -37,7 +37,7 @@ export default class TxGasUtil {
let estimatedGasHex = bnToHex(saferGasLimitBN)
let simulationFails
try {
- estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit)
+ estimatedGasHex = await this.estimateTxGas(txMeta)
} catch (error) {
log.warn(error)
simulationFails = {
diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js
deleted file mode 100644
index ecf832ce7..000000000
--- a/app/scripts/lib/reportFailedTxToSentry.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import extractEthjsErrorMessage from './extractEthjsErrorMessage'
-
-//
-// utility for formatting failed transaction messages
-// for sending to sentry
-//
-
-export default function reportFailedTxToSentry ({ sentry, txMeta }) {
- const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message)
- sentry.captureMessage(errorMessage, {
- // "extra" key is required by Sentry
- extra: { txMeta },
- })
-}
diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js
index dcc31207c..c41a4a5dc 100644
--- a/app/scripts/lib/setupSentry.js
+++ b/app/scripts/lib/setupSentry.js
@@ -8,8 +8,7 @@ const METAMASK_ENVIRONMENT = process.env.METAMASK_ENVIRONMENT
const SENTRY_DSN_PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
-export default function setupSentry (opts) {
- const { release, getState } = opts
+export default function setupSentry ({ release }) {
let sentryTarget
// detect brave
const isBrave = Boolean(window.chrome.ipcRenderer)
@@ -44,11 +43,6 @@ export default function setupSentry (opts) {
simplifyErrorMessages(report)
// modify report urls
rewriteReportUrls(report)
- // append app state
- if (getState) {
- const appState = getState()
- report.extra.appState = appState
- }
} catch (err) {
console.warn(err)
}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 5c36d8d23..6b2da2946 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -545,7 +545,7 @@ export default class MetamaskController extends EventEmitter {
// alert controller
setAlertEnabledness: nodeify(alertController.setAlertEnabledness, alertController),
- setSwitchToConnectedAlertShown: nodeify(this.alertController.setSwitchToConnectedAlertShown, this.alertController),
+ setUnconnectedAccountAlertShown: nodeify(this.alertController.setUnconnectedAccountAlertShown, this.alertController),
// 3Box
setThreeBoxSyncingPermission: nodeify(threeBoxController.setThreeBoxSyncingPermission, threeBoxController),
@@ -620,6 +620,10 @@ export default class MetamaskController extends EventEmitter {
// clear known identities
this.preferencesController.setAddresses([])
+
+ // clear permissions
+ this.permissionsController.clearPermissions()
+
// create new vault
const vault = await keyringController.createNewVaultAndRestore(password, seed)
@@ -993,6 +997,8 @@ export default class MetamaskController extends EventEmitter {
*
*/
async removeAccount (address) {
+ // Remove all associated permissions
+ await this.permissionsController.removeAllAccountPermissions(address)
// Remove account from the preferences controller
this.preferencesController.removeAddress(address)
// Remove account from the account tracker controller
diff --git a/app/scripts/ui.js b/app/scripts/ui.js
index 5a403828d..5e8cc8e66 100644
--- a/app/scripts/ui.js
+++ b/app/scripts/ui.js
@@ -4,6 +4,7 @@ import './lib/freezeGlobals'
// polyfills
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
+import '@formatjs/intl-relativetimeformat/polyfill'
import PortStream from 'extension-port-stream'
import { getEnvironmentType } from './lib/util'
@@ -35,18 +36,7 @@ async function start () {
// setup sentry error reporting
const release = global.platform.getVersion()
- setupSentry({ release, getState })
- // provide app state to append to error logs
- function getState () {
- // get app state
- const state = window.getCleanAppState
- ? window.getCleanAppState()
- : {}
- // remove unnecessary data
- delete state.localeMessages
- // return state to be added to request
- return state
- }
+ setupSentry({ release })
// identify window type (popup, notification)
const windowType = getEnvironmentType()
diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json
index a8eb67cdd..18a31a93f 100644
--- a/development/states/confirm-sig-requests.json
+++ b/development/states/confirm-sig-requests.json
@@ -522,9 +522,6 @@
"priceAndTimeEstimatesLastRetrieved": 1541527901281,
"errors": {}
},
- "switchToConnected": {
- "state": "CLOSED"
- },
"unconnectedAccount": {
"state": "CLOSED"
},
diff --git a/development/states/currency-localization.json b/development/states/currency-localization.json
index a61ab10ed..ca8ee7c42 100644
--- a/development/states/currency-localization.json
+++ b/development/states/currency-localization.json
@@ -473,9 +473,6 @@
"priceAndTimeEstimatesLastRetrieved": 1541527901281,
"errors": {}
},
- "switchToConnected": {
- "state": "CLOSED"
- },
"unconnectedAccount": {
"state": "CLOSED"
},
diff --git a/development/states/tx-list-items.json b/development/states/tx-list-items.json
index 969535180..17a2435d5 100644
--- a/development/states/tx-list-items.json
+++ b/development/states/tx-list-items.json
@@ -1295,9 +1295,6 @@
"errors": {}
},
"confirmTransaction": {},
- "switchToConnected": {
- "state": "CLOSED"
- },
"unconnectedAccount": {
"state": "CLOSED"
}
diff --git a/package.json b/package.json
index 1d27a3913..7901bbbaf 100644
--- a/package.json
+++ b/package.json
@@ -71,6 +71,7 @@
"3box": "^1.10.2",
"@babel/runtime": "^7.5.5",
"@download/blockies": "^1.0.3",
+ "@formatjs/intl-relativetimeformat": "^5.2.6",
"@fortawesome/fontawesome-free": "^5.13.0",
"@material-ui/core": "1.0.0",
"@metamask/controllers": "^2.0.0",
@@ -223,6 +224,7 @@
"eslint-plugin-json": "^1.2.0",
"eslint-plugin-mocha": "^6.2.2",
"eslint-plugin-react": "^7.18.3",
+ "eslint-plugin-react-hooks": "^4.0.4",
"fancy-log": "^1.3.3",
"fast-glob": "^3.2.2",
"file-loader": "^1.1.11",
diff --git a/test/e2e/address-book.spec.js b/test/e2e/address-book.spec.js
index 6d21eed6f..04ea4a14c 100644
--- a/test/e2e/address-book.spec.js
+++ b/test/e2e/address-book.spec.js
@@ -195,7 +195,7 @@ describe('MetaMask', function () {
})
it('finds the transaction in the transactions list', async function () {
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1
diff --git a/test/e2e/from-import-ui.spec.js b/test/e2e/from-import-ui.spec.js
index b65786629..cb8da4a45 100644
--- a/test/e2e/from-import-ui.spec.js
+++ b/test/e2e/from-import-ui.spec.js
@@ -63,7 +63,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('clicks the "Import Wallet" option', async function () {
- await driver.clickElement(By.xpath(`//button[contains(text(), 'Import Wallet')]`))
+ await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`))
await driver.delay(largeDelayMs)
})
@@ -73,7 +73,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('imports a seed phrase', async function () {
- const [seedTextArea] = await driver.findElements(By.css('textarea.first-time-flow__textarea'))
+ const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]'))
await seedTextArea.sendKeys(testSeedPhrase)
await driver.delay(regularDelayMs)
@@ -82,7 +82,7 @@ describe('Using MetaMask with an existing account', function () {
const [confirmPassword] = await driver.findElements(By.id('confirm-password'))
confirmPassword.sendKeys('correct horse battery staple')
- await driver.clickElement(By.css('.first-time-flow__checkbox'))
+ await driver.clickElement(By.css('.first-time-flow__terms'))
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`))
await driver.delay(regularDelayMs)
@@ -215,7 +215,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('finds the transaction in the transactions list', async function () {
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1
diff --git a/test/e2e/metamask-responsive-ui.spec.js b/test/e2e/metamask-responsive-ui.spec.js
index edd10758e..0969af53f 100644
--- a/test/e2e/metamask-responsive-ui.spec.js
+++ b/test/e2e/metamask-responsive-ui.spec.js
@@ -211,7 +211,7 @@ describe('MetaMask', function () {
})
it('finds the transaction in the transactions list', async function () {
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1
diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js
index 3a2677405..7f1517362 100644
--- a/test/e2e/metamask-ui.spec.js
+++ b/test/e2e/metamask-ui.spec.js
@@ -266,7 +266,7 @@ describe('MetaMask', function () {
})
it('finds the transaction in the transactions list', async function () {
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1
diff --git a/test/e2e/send-edit.spec.js b/test/e2e/send-edit.spec.js
index d5b9f8e55..48ee97cb0 100644
--- a/test/e2e/send-edit.spec.js
+++ b/test/e2e/send-edit.spec.js
@@ -61,7 +61,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('clicks the "Import Wallet" option', async function () {
- await driver.clickElement(By.xpath(`//button[contains(text(), 'Import Wallet')]`))
+ await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`))
await driver.delay(largeDelayMs)
})
@@ -71,7 +71,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('imports a seed phrase', async function () {
- const [seedTextArea] = await driver.findElements(By.css('textarea.first-time-flow__textarea'))
+ const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]'))
await seedTextArea.sendKeys(testSeedPhrase)
await driver.delay(regularDelayMs)
@@ -80,7 +80,7 @@ describe('Using MetaMask with an existing account', function () {
const [confirmPassword] = await driver.findElements(By.id('confirm-password'))
confirmPassword.sendKeys('correct horse battery staple')
- await driver.clickElement(By.css('.first-time-flow__checkbox'))
+ await driver.clickElement(By.css('.first-time-flow__terms'))
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`))
await driver.delay(regularDelayMs)
@@ -197,7 +197,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('finds the transaction in the transactions list', async function () {
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.wait(async () => {
const confirmedTxes = await driver.findElements(By.css('.transaction-list__completed-transactions .transaction-list-item'))
return confirmedTxes.length === 1
diff --git a/test/e2e/tests/simple-send.spec.js b/test/e2e/tests/simple-send.spec.js
index d40ee8e8d..0b48916a7 100644
--- a/test/e2e/tests/simple-send.spec.js
+++ b/test/e2e/tests/simple-send.spec.js
@@ -22,7 +22,7 @@ describe('MetaMask Browser Extension', function () {
await amountField.sendKeys('1')
await driver.clickElement(By.css('[data-testid="page-container-footer-next"]'))
await driver.clickElement(By.css('[data-testid="page-container-footer-next"]'))
- await driver.clickElement(By.css('[data-testid="home__history-tab"]'))
+ await driver.clickElement(By.css('[data-testid="home__activity-tab"]'))
await driver.findElement(By.css('.transaction-list-item'))
})
})
diff --git a/test/e2e/threebox.spec.js b/test/e2e/threebox.spec.js
index 33b5b1ff7..46669f1df 100644
--- a/test/e2e/threebox.spec.js
+++ b/test/e2e/threebox.spec.js
@@ -64,7 +64,7 @@ describe('MetaMask', function () {
})
it('clicks the "Import Wallet" option', async function () {
- await driver.clickElement(By.xpath(`//button[contains(text(), 'Import Wallet')]`))
+ await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`))
await driver.delay(largeDelayMs)
})
@@ -74,7 +74,7 @@ describe('MetaMask', function () {
})
it('imports a seed phrase', async function () {
- const [seedTextArea] = await driver.findElements(By.css('textarea.first-time-flow__textarea'))
+ const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]'))
await seedTextArea.sendKeys(testSeedPhrase)
await driver.delay(regularDelayMs)
@@ -83,7 +83,7 @@ describe('MetaMask', function () {
const [confirmPassword] = await driver.findElements(By.id('confirm-password'))
confirmPassword.sendKeys('correct horse battery staple')
- await driver.clickElement(By.css('.first-time-flow__checkbox'))
+ await driver.clickElement(By.css('.first-time-flow__terms'))
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`))
await driver.delay(regularDelayMs)
@@ -170,7 +170,7 @@ describe('MetaMask', function () {
})
it('clicks the "Import Wallet" option', async function () {
- await driver2.clickElement(By.xpath(`//button[contains(text(), 'Import Wallet')]`))
+ await driver2.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`))
await driver2.delay(largeDelayMs)
})
@@ -180,7 +180,7 @@ describe('MetaMask', function () {
})
it('imports a seed phrase', async function () {
- const [seedTextArea] = await driver2.findElements(By.css('textarea.first-time-flow__textarea'))
+ const [seedTextArea] = await driver2.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]'))
await seedTextArea.sendKeys(testSeedPhrase)
await driver2.delay(regularDelayMs)
@@ -189,7 +189,7 @@ describe('MetaMask', function () {
const [confirmPassword] = await driver2.findElements(By.id('confirm-password'))
confirmPassword.sendKeys('correct horse battery staple')
- await driver2.clickElement(By.css('.first-time-flow__checkbox'))
+ await driver2.clickElement(By.css('.first-time-flow__terms'))
await driver2.clickElement(By.xpath(`//button[contains(text(), 'Import')]`))
await driver2.delay(regularDelayMs)
diff --git a/test/e2e/web3.spec.js b/test/e2e/web3.spec.js
index 2aae92bc1..7c2c4c5e5 100644
--- a/test/e2e/web3.spec.js
+++ b/test/e2e/web3.spec.js
@@ -60,7 +60,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('clicks the "Import Wallet" option', async function () {
- await driver.clickElement(By.xpath(`//button[contains(text(), 'Import Wallet')]`))
+ await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`))
await driver.delay(largeDelayMs)
})
@@ -70,7 +70,7 @@ describe('Using MetaMask with an existing account', function () {
})
it('imports a seed phrase', async function () {
- const [seedTextArea] = await driver.findElements(By.css('textarea.first-time-flow__textarea'))
+ const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]'))
await seedTextArea.sendKeys(testSeedPhrase)
await driver.delay(regularDelayMs)
@@ -79,7 +79,7 @@ describe('Using MetaMask with an existing account', function () {
const [confirmPassword] = await driver.findElements(By.id('confirm-password'))
confirmPassword.sendKeys('correct horse battery staple')
- await driver.clickElement(By.css('.first-time-flow__checkbox'))
+ await driver.clickElement(By.css('.first-time-flow__terms'))
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`))
await driver.delay(regularDelayMs)
diff --git a/test/unit/app/controllers/metamask-controller-test.js b/test/unit/app/controllers/metamask-controller-test.js
index 3201e695c..262202419 100644
--- a/test/unit/app/controllers/metamask-controller-test.js
+++ b/test/unit/app/controllers/metamask-controller-test.js
@@ -599,6 +599,7 @@ describe('MetaMaskController', function () {
sinon.stub(metamaskController.preferencesController, 'removeAddress')
sinon.stub(metamaskController.accountTracker, 'removeAccount')
sinon.stub(metamaskController.keyringController, 'removeAccount')
+ sinon.stub(metamaskController.permissionsController, 'removeAllAccountPermissions')
ret = await metamaskController.removeAccount(addressToRemove)
@@ -608,6 +609,7 @@ describe('MetaMaskController', function () {
metamaskController.keyringController.removeAccount.restore()
metamaskController.accountTracker.removeAccount.restore()
metamaskController.preferencesController.removeAddress.restore()
+ metamaskController.permissionsController.removeAllAccountPermissions.restore()
})
it('should call preferencesController.removeAddress', async function () {
@@ -619,6 +621,9 @@ describe('MetaMaskController', function () {
it('should call keyringController.removeAccount', async function () {
assert(metamaskController.keyringController.removeAccount.calledWith(addressToRemove))
})
+ it('should call permissionsController.removeAllAccountPermissions', async function () {
+ assert(metamaskController.permissionsController.removeAllAccountPermissions.calledWith(addressToRemove))
+ })
it('should return address', async function () {
assert.equal(ret, '0x1')
})
diff --git a/test/unit/app/controllers/permissions/permissions-controller-test.js b/test/unit/app/controllers/permissions/permissions-controller-test.js
index b5958baa5..f2272e311 100644
--- a/test/unit/app/controllers/permissions/permissions-controller-test.js
+++ b/test/unit/app/controllers/permissions/permissions-controller-test.js
@@ -660,6 +660,112 @@ describe('permissions controller', function () {
})
})
+
+ describe('removeAllAccountPermissions', function () {
+ let permController, notifications
+
+ beforeEach(function () {
+ notifications = initNotifications()
+ permController = initPermController(notifications)
+ grantPermissions(
+ permController, DOMAINS.a.origin,
+ PERMS.finalizedRequests.eth_accounts(ACCOUNTS.a.permitted)
+ )
+ grantPermissions(
+ permController, DOMAINS.b.origin,
+ PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted)
+ )
+ grantPermissions(
+ permController, DOMAINS.c.origin,
+ PERMS.finalizedRequests.eth_accounts(ACCOUNTS.b.permitted)
+ )
+ })
+
+ it('should throw if account is not a string', async function () {
+ await assert.rejects(
+ () => permController.removeAllAccountPermissions({}),
+ ERRORS.validatePermittedAccounts.nonKeyringAccount({}),
+ 'should throw on non-string account param'
+ )
+ })
+
+ it('should throw if given account is not in keyring', async function () {
+ await assert.rejects(
+ () => permController.removeAllAccountPermissions(DUMMY_ACCOUNT),
+ ERRORS.validatePermittedAccounts.nonKeyringAccount(DUMMY_ACCOUNT),
+ 'should throw on non-keyring account'
+ )
+ })
+
+ it('should remove permitted account from single origin', async function () {
+ await permController.removeAllAccountPermissions(ACCOUNTS.a.permitted[1])
+
+ const accounts = await permController._getPermittedAccounts(DOMAINS.a.origin)
+
+ assert.deepEqual(
+ accounts, ACCOUNTS.a.permitted.filter((acc) => acc !== ACCOUNTS.a.permitted[1]),
+ 'origin should have correct accounts'
+ )
+
+ assert.deepEqual(
+ notifications[DOMAINS.a.origin][0],
+ NOTIFICATIONS.newAccounts([ACCOUNTS.a.primary]),
+ 'origin should have correct notification'
+ )
+ })
+
+ it('should permitted account from multiple origins', async function () {
+ await permController.removeAllAccountPermissions(ACCOUNTS.b.permitted[0])
+
+ const bAccounts = await permController.getAccounts(DOMAINS.b.origin)
+ assert.deepEqual(
+ bAccounts, [],
+ 'first origin should no accounts'
+ )
+
+ const cAccounts = await permController.getAccounts(DOMAINS.c.origin)
+ assert.deepEqual(
+ cAccounts, [],
+ 'second origin no accounts'
+ )
+
+ assert.deepEqual(
+ notifications[DOMAINS.b.origin][0],
+ NOTIFICATIONS.removedAccounts(),
+ 'first origin should have correct notification'
+ )
+
+ assert.deepEqual(
+ notifications[DOMAINS.c.origin][0],
+ NOTIFICATIONS.removedAccounts(),
+ 'second origin should have correct notification'
+ )
+ })
+
+ it('should remove eth_accounts permission if removing only permitted account', async function () {
+ await permController.removeAllAccountPermissions(ACCOUNTS.b.permitted[0])
+
+ const accounts = await permController.getAccounts(DOMAINS.b.origin)
+
+ assert.deepEqual(
+ accounts, [],
+ 'origin should have no accounts'
+ )
+
+ const permission = await permController.permissions.getPermission(
+ DOMAINS.b.origin, PERM_NAMES.eth_accounts
+ )
+
+ assert.equal(permission, undefined, 'origin should not have eth_accounts permission')
+
+ assert.deepEqual(
+ notifications[DOMAINS.b.origin][0],
+ NOTIFICATIONS.removedAccounts(),
+ 'origin should have correct notification'
+ )
+ })
+ })
+
describe('finalizePermissionsRequest', function () {
let permController
diff --git a/test/unit/app/controllers/permissions/permissions-log-controller-test.js b/test/unit/app/controllers/permissions/permissions-log-controller-test.js
index ea99fcd2d..fa2e32889 100644
--- a/test/unit/app/controllers/permissions/permissions-log-controller-test.js
+++ b/test/unit/app/controllers/permissions/permissions-log-controller-test.js
@@ -58,6 +58,8 @@ const initMiddleware = (permLog) => {
}
const initClock = () => {
+ // useFakeTimers, is in fact, not a react-hook
+ // eslint-disable-next-line
clock = useFakeTimers(1)
}
diff --git a/test/unit/app/controllers/token-rates-controller.js b/test/unit/app/controllers/token-rates-controller.js
index 8802c5c6e..2bc341d22 100644
--- a/test/unit/app/controllers/token-rates-controller.js
+++ b/test/unit/app/controllers/token-rates-controller.js
@@ -6,18 +6,20 @@ import ObservableStore from 'obs-store'
describe('TokenRatesController', function () {
it('should listen for preferences store updates', function () {
const preferences = new ObservableStore({ tokens: [] })
- const controller = new TokenRatesController({ preferences })
preferences.putState({ tokens: ['foo'] })
+ const controller = new TokenRatesController({ preferences })
assert.deepEqual(controller._tokens, ['foo'])
})
it('should poll on correct interval', async function () {
const stub = sinon.stub(global, 'setInterval')
- const rateController = new TokenRatesController() // eslint-disable-line no-new
- rateController.start(1337)
+ const preferences = new ObservableStore({ tokens: [] })
+ preferences.putState({ tokens: ['foo'] })
+ const controller = new TokenRatesController({ preferences })
+ controller.start(1337)
assert.strictEqual(stub.getCall(0).args[1], 1337)
stub.restore()
- rateController.stop()
+ controller.stop()
})
})
diff --git a/test/unit/ui/app/actions.spec.js b/test/unit/ui/app/actions.spec.js
index b9cdd5716..0affebe46 100644
--- a/test/unit/ui/app/actions.spec.js
+++ b/test/unit/ui/app/actions.spec.js
@@ -221,10 +221,10 @@ describe('Actions', function () {
})
describe('#removeAccount', function () {
- let removeAccountSpy
+ let removeAccountStub
afterEach(function () {
- removeAccountSpy.restore()
+ removeAccountStub.restore()
})
it('calls removeAccount in background and expect actions to show account', async function () {
@@ -238,10 +238,11 @@ describe('Actions', function () {
'SHOW_ACCOUNTS_PAGE',
]
- removeAccountSpy = sinon.spy(background, 'removeAccount')
+ removeAccountStub = sinon.stub(background, 'removeAccount')
+ removeAccountStub.callsFake((_, callback) => callback())
await store.dispatch(actions.removeAccount('0xe18035bf8712672935fdb4e5e431b1a0183d2dfc'))
- assert(removeAccountSpy.calledOnce)
+ assert(removeAccountStub.calledOnce)
const actionTypes = store
.getActions()
.map((action) => action.type)
@@ -257,8 +258,8 @@ describe('Actions', function () {
'HIDE_LOADING_INDICATION',
]
- removeAccountSpy = sinon.stub(background, 'removeAccount')
- removeAccountSpy.callsFake((_, callback) => {
+ removeAccountStub = sinon.stub(background, 'removeAccount')
+ removeAccountStub.callsFake((_, callback) => {
callback(new Error('error'))
})
diff --git a/ui/app/components/app/account-menu/account-menu.component.js b/ui/app/components/app/account-menu/account-menu.component.js
index f6245f304..6409a9cd6 100644
--- a/ui/app/components/app/account-menu/account-menu.component.js
+++ b/ui/app/components/app/account-menu/account-menu.component.js
@@ -8,7 +8,7 @@ import { Menu, Item, Divider, CloseArea } from '../dropdowns/components/menu'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import Identicon from '../../ui/identicon'
-import IconWithFallBack from '../../ui/icon-with-fallback'
+import SiteIcon from '../../ui/site-icon'
import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'
import { PRIMARY } from '../../../helpers/constants/common'
import {
@@ -178,7 +178,7 @@ export default class AccountMenu extends Component {
{ iconAndNameForOpenDomain
? (
-
+
)
: null
diff --git a/ui/app/components/app/add-token-button/add-token-button.component.js b/ui/app/components/app/add-token-button/add-token-button.component.js
index 373c6b116..e1a40d563 100644
--- a/ui/app/components/app/add-token-button/add-token-button.component.js
+++ b/ui/app/components/app/add-token-button/add-token-button.component.js
@@ -1,33 +1,35 @@
-import PropTypes from 'prop-types'
-import React, { PureComponent } from 'react'
+import React from 'react'
+import { useMetricEvent } from '../../../hooks/useMetricEvent'
+import { useI18nContext } from '../../../hooks/useI18nContext'
+import { useHistory } from 'react-router-dom'
+import { ADD_TOKEN_ROUTE } from '../../../helpers/constants/routes'
+import Button from '../../ui/button'
-export default class AddTokenButton extends PureComponent {
- static contextTypes = {
- t: PropTypes.func.isRequired,
- }
- static defaultProps = {
- onClick: () => {},
- }
+export default function AddTokenButton () {
+ const addTokenEvent = useMetricEvent({
+ eventOpts: {
+ category: 'Navigation',
+ action: 'Token Menu',
+ name: 'Clicked "Add Token"',
+ },
+ })
+ const t = useI18nContext()
+ const history = useHistory()
- static propTypes = {
- onClick: PropTypes.func,
- }
-
- render () {
- const { t } = this.context
- const { onClick } = this.props
-
- return (
-
- {t('missingYourTokens')}
-
-
- )
- }
+ return (
+
+
+
+ )
}
diff --git a/ui/app/components/app/add-token-button/index.scss b/ui/app/components/app/add-token-button/index.scss
index 9f13d9f9e..e8b2c1a43 100644
--- a/ui/app/components/app/add-token-button/index.scss
+++ b/ui/app/components/app/add-token-button/index.scss
@@ -1,22 +1,6 @@
.add-token-button {
- width: 100%;
- height: 90px;
- padding: 20px;
- text-align: center;
- font-size: 1rem;
-
&__button {
- background-color: transparent;
- color: $Blue-500;
- display: inline-block;
- font-size: 1rem;
-
- &:hover {
- color: $Blue-400;
- }
-
- &:active {
- color: $Blue-600;
- }
+ max-width: 200px;
+ margin: 16px auto;
}
}
diff --git a/ui/app/components/app/alerts/alerts.js b/ui/app/components/app/alerts/alerts.js
index 9f804d7d9..5d376494c 100644
--- a/ui/app/components/app/alerts/alerts.js
+++ b/ui/app/components/app/alerts/alerts.js
@@ -2,22 +2,15 @@ import React from 'react'
import { useSelector } from 'react-redux'
import UnconnectedAccountAlert from './unconnected-account-alert'
-import SwitchToConnectedAlert from './switch-to-connected-alert'
import { alertIsOpen as unconnectedAccountAlertIsOpen } from '../../../ducks/alerts/unconnected-account'
-import { alertIsOpen as switchToConnectedAlertIsOpen } from '../../../ducks/alerts/switch-to-connected'
const Alerts = () => {
const _unconnectedAccountAlertIsOpen = useSelector(unconnectedAccountAlertIsOpen)
- const _switchToConnectedAlertIsOpen = useSelector(switchToConnectedAlertIsOpen)
if (_unconnectedAccountAlertIsOpen) {
return (
)
- } else if (_switchToConnectedAlertIsOpen) {
- return (
-
- )
}
return null
diff --git a/ui/app/components/app/alerts/alerts.scss b/ui/app/components/app/alerts/alerts.scss
index 82ec8ead0..280171f5e 100644
--- a/ui/app/components/app/alerts/alerts.scss
+++ b/ui/app/components/app/alerts/alerts.scss
@@ -1,3 +1 @@
@import './unconnected-account-alert/unconnected-account-alert';
-
-@import './switch-to-connected-alert/switch-to-connected-alert';
diff --git a/ui/app/components/app/alerts/switch-to-connected-alert/index.js b/ui/app/components/app/alerts/switch-to-connected-alert/index.js
deleted file mode 100644
index 9811c0df2..000000000
--- a/ui/app/components/app/alerts/switch-to-connected-alert/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './switch-to-connected-alert'
diff --git a/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.js b/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.js
deleted file mode 100644
index d440c250c..000000000
--- a/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import React, { useState } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-
-import {
- ALERT_STATE,
- switchToAccount,
- dismissAlert,
- dismissAndDisableAlert,
- getAlertState,
-} from '../../../../ducks/alerts/switch-to-connected'
-import { getPermittedIdentitiesForCurrentTab } from '../../../../selectors'
-import Popover from '../../../ui/popover'
-import Button from '../../../ui/button'
-import Dropdown from '../../../ui/dropdown'
-import Checkbox from '../../../ui/check-box'
-import Tooltip from '../../../ui/tooltip-v2'
-import { useI18nContext } from '../../../../hooks/useI18nContext'
-
-const {
- ERROR,
- LOADING,
-} = ALERT_STATE
-
-const SwitchToUnconnectedAccountAlert = () => {
- const t = useI18nContext()
- const dispatch = useDispatch()
- const alertState = useSelector(getAlertState)
- const connectedAccounts = useSelector(getPermittedIdentitiesForCurrentTab)
- const [accountToSwitchTo, setAccountToSwitchTo] = useState(connectedAccounts[0].address)
- const [dontShowThisAgain, setDontShowThisAgain] = useState(false)
-
- const onClose = async () => {
- return dontShowThisAgain
- ? await dispatch(dismissAndDisableAlert())
- : dispatch(dismissAlert())
- }
-
- const options = connectedAccounts.map((account) => {
- return { name: account.name, value: account.address }
- })
-
- return (
-
- {
- alertState === ERROR
- ? (
-
- { t('failureMessage') }
-
- )
- : null
- }
-
-
-
-
- >
- )}
- footerClassName="switch-to-connected-alert__footer"
- onClose={onClose}
- subtitle={
- connectedAccounts.length > 1
- ? t('switchToConnectedAlertMultipleAccountsDescription')
- : t('switchToConnectedAlertSingleAccountDescription', [connectedAccounts[0].name])
- }
- title={t('notConnected')}
- >
- {
- connectedAccounts.length > 1
- ? (
- setAccountToSwitchTo(address)}
- options={options}
- selectedOption={accountToSwitchTo}
- />
- )
- : null
- }
-
- setDontShowThisAgain((checked) => !checked)}
- />
-
-
-
- )
-}
-
-export default SwitchToUnconnectedAccountAlert
diff --git a/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.scss b/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.scss
deleted file mode 100644
index e4e7d3f80..000000000
--- a/ui/app/components/app/alerts/switch-to-connected-alert/switch-to-connected-alert.scss
+++ /dev/null
@@ -1,66 +0,0 @@
-.switch-to-connected-alert {
- &__footer {
- flex-direction: column;
-
- :only-child {
- margin: 0;
- }
- }
-
- &__footer-buttons {
- display: flex;
- flex-direction: row;
-
- button:first-child {
- margin-right: 24px;
- }
-
- button {
- font-size: 14px;
- line-height: 20px;
- padding: 8px;
- }
- }
-
- &__error {
- margin-bottom: 16px;
- padding: 16px;
- font-size: 14px;
- border: 1px solid #D73A49;
- background: #F8EAE8;
- border-radius: 3px;
- }
-
- &__content {
- align-items: center;
- padding: 0 24px 24px 24px;
- }
-
- &__dropdown {
- background-color: white;
- width: 100%;
- margin-bottom: 24px;
- }
-
- &__checkbox-wrapper {
- display: flex;
- flex-direction: row;
- width: 100%;
- }
-
- &__checkbox {
- margin-right: 8px;
- }
-
- &__checkbox-label {
- font-size: 14px;
- margin-top: auto;
- margin-bottom: auto;
- color: $Grey-500;
- display: flex;
- }
-
- &__checkbox-label-tooltip {
- margin-left: 8px;
- }
-}
diff --git a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js
index ca5ed7db4..38a8fda6e 100644
--- a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js
+++ b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js
@@ -7,12 +7,20 @@ import {
dismissAlert,
dismissAndDisableAlert,
getAlertState,
+ switchToAccount,
} from '../../../../ducks/alerts/unconnected-account'
+import {
+ getOriginOfCurrentTab,
+ getPermittedIdentitiesForCurrentTab,
+ getSelectedAddress,
+ getSelectedIdentity,
+} from '../../../../selectors'
+import { isExtensionUrl } from '../../../../helpers/utils/util'
import Popover from '../../../ui/popover'
import Button from '../../../ui/button'
import Checkbox from '../../../ui/check-box'
import Tooltip from '../../../ui/tooltip-v2'
-import { getSelectedIdentity, getOriginOfCurrentTab } from '../../../../selectors'
+import ConnectedAccountsList from '../../connected-accounts-list'
import { useI18nContext } from '../../../../hooks/useI18nContext'
const {
@@ -20,12 +28,14 @@ const {
LOADING,
} = ALERT_STATE
-const SwitchToUnconnectedAccountAlert = () => {
+const UnconnectedAccountAlert = () => {
const t = useI18nContext()
const dispatch = useDispatch()
const alertState = useSelector(getAlertState)
+ const connectedAccounts = useSelector(getPermittedIdentitiesForCurrentTab)
const origin = useSelector(getOriginOfCurrentTab)
const selectedIdentity = useSelector(getSelectedIdentity)
+ const selectedAddress = useSelector(getSelectedAddress)
const [dontShowThisAgain, setDontShowThisAgain] = useState(false)
const onClose = async () => {
@@ -34,67 +44,70 @@ const SwitchToUnconnectedAccountAlert = () => {
: dispatch(dismissAlert())
}
- const accountName = selectedIdentity?.name || t('thisAccount')
- const siteName = origin || t('thisSite')
+ const footer = (
+ <>
+ {
+ alertState === ERROR
+ ? (
+
+ { t('failureMessage') }
+
+ )
+ : null
+ }
+
+
+ setDontShowThisAgain((checked) => !checked)}
+ />
+
+
+
+
+ >
+ )
return (
- {
- alertState === ERROR
- ? (
-
- { t('failureMessage') }
-
- )
- : null
- }
-
-
-
-
- >
- )}
+ contentClassName="unconnected-account-alert__content"
footerClassName="unconnected-account-alert__footer"
+ footer={footer}
>
- setDontShowThisAgain((checked) => !checked)}
+ dispatch(connectAccount(selectedAddress))}
+ connectedAccounts={connectedAccounts}
+ selectedAddress={selectedAddress}
+ setSelectedAddress={(address) => dispatch(switchToAccount(address))}
+ shouldRenderListOptions={false}
/>
-
)
}
-export default SwitchToUnconnectedAccountAlert
+export default UnconnectedAccountAlert
diff --git a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss
index 61ecf9a18..54f37beac 100644
--- a/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss
+++ b/ui/app/components/app/alerts/unconnected-account-alert/unconnected-account-alert.scss
@@ -1,25 +1,28 @@
.unconnected-account-alert {
+ &__content {
+ border-radius: 0;
+ }
+
&__footer {
flex-direction: column;
- :only-child {
+ > :only-child {
margin: 0;
}
}
- &__footer-buttons {
+ &__footer-row {
display: flex;
flex-direction: row;
+ }
- button:first-child {
- margin-right: 24px;
- }
-
- button {
- font-size: 14px;
- line-height: 20px;
- padding: 8px;
- }
+ &__dismiss-button {
+ background: #037DD6;
+ color: white;
+ height: 40px;
+ width: 100px;
+ border: 0;
+ border-radius: 100px;
}
&__error {
@@ -31,21 +34,24 @@
border-radius: 3px;
}
- &__content {
+ &__checkbox-wrapper {
+ width: 100%;
+ display: flex;
flex-direction: row;
- padding: 0 24px 24px 24px;
+ align-items: center;
}
&__checkbox {
margin-right: 8px;
+ padding-top: 1px; // better alignment with rest of content
}
&__checkbox-label {
- font-size: 14px;
+ display: flex;
+ font-size: 12px;
margin-top: auto;
margin-bottom: auto;
color: $Grey-500;
- display: flex;
}
&__checkbox-label-tooltip {
diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js b/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js
index 11b30660d..cfff63c1c 100644
--- a/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js
+++ b/ui/app/components/app/connected-accounts-list/connected-accounts-list-item/connected-accounts-list-item.component.js
@@ -12,13 +12,15 @@ export default class ConnectedAccountsListItem extends PureComponent {
address: PropTypes.string.isRequired,
className: PropTypes.string,
name: PropTypes.node.isRequired,
- status: PropTypes.node.isRequired,
+ status: PropTypes.string,
+ action: PropTypes.node,
options: PropTypes.node,
}
static defaultProps = {
className: null,
options: null,
+ action: null,
}
render () {
@@ -27,6 +29,7 @@ export default class ConnectedAccountsListItem extends PureComponent {
className,
name,
status,
+ action,
options,
} = this.props
@@ -39,18 +42,20 @@ export default class ConnectedAccountsListItem extends PureComponent {
diameter={32}
/>
-
- {name}
+
+ {name}
{
status
? (
+
{status}
)
: null
}
+ {action}
{options}
diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/index.js b/ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/index.js
deleted file mode 100644
index 7733018f8..000000000
--- a/ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './connected-accounts-list-permissions.component'
diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list.component.js b/ui/app/components/app/connected-accounts-list/connected-accounts-list.component.js
index 78627c160..d4e10db7f 100644
--- a/ui/app/components/app/connected-accounts-list/connected-accounts-list.component.js
+++ b/ui/app/components/app/connected-accounts-list/connected-accounts-list.component.js
@@ -1,7 +1,5 @@
-import { DateTime } from 'luxon'
import PropTypes from 'prop-types'
import React, { PureComponent } from 'react'
-import ConnectedAccountsListPermissions from './connected-accounts-list-permissions'
import ConnectedAccountsListItem from './connected-accounts-list-item'
import ConnectedAccountsListOptions from './connected-accounts-list-options'
import { MenuItem } from '../../ui/menu'
@@ -13,7 +11,6 @@ export default class ConnectedAccountsList extends PureComponent {
static defaultProps = {
accountToConnect: null,
- permissions: undefined,
}
static propTypes = {
@@ -26,31 +23,35 @@ export default class ConnectedAccountsList extends PureComponent {
name: PropTypes.string.isRequired,
lastActive: PropTypes.number,
})).isRequired,
- permissions: PropTypes.arrayOf(PropTypes.shape({
- key: PropTypes.string.isRequired,
- })),
+ connectAccount: PropTypes.func.isRequired,
selectedAddress: PropTypes.string.isRequired,
- addPermittedAccount: PropTypes.func.isRequired,
- removePermittedAccount: PropTypes.func.isRequired,
+ removePermittedAccount: PropTypes.func,
setSelectedAddress: PropTypes.func.isRequired,
+ shouldRenderListOptions: (props, propName, componentName) => {
+ if (typeof props[propName] !== 'boolean') {
+ return new Error(
+ `Warning: Failed prop type: '${propName}' of component '${componentName}' must be a boolean. Received: ${typeof props[propName]}`
+ )
+ } else if (props[propName] && !props['removePermittedAccount']) {
+ return new Error(
+ `Warning: Failed prop type: '${propName}' of component '${componentName}' requires prop 'removePermittedAccount'.`
+ )
+ }
+ },
}
state = {
accountWithOptionsShown: null,
}
- connectAccount = () => {
- this.props.addPermittedAccount(this.props.accountToConnect?.address)
- }
-
disconnectAccount = () => {
this.hideAccountOptions()
this.props.removePermittedAccount(this.state.accountWithOptionsShown)
}
- switchAccount = () => {
+ switchAccount = (address) => {
this.hideAccountOptions()
- this.props.setSelectedAddress(this.state.accountWithOptionsShown)
+ this.props.setSelectedAddress(address)
}
hideAccountOptions = () => {
@@ -62,7 +63,7 @@ export default class ConnectedAccountsList extends PureComponent {
}
renderUnconnectedAccount () {
- const { accountToConnect } = this.props
+ const { accountToConnect, connectAccount } = this.props
const { t } = this.context
if (!accountToConnect) {
@@ -75,73 +76,87 @@ export default class ConnectedAccountsList extends PureComponent {
className="connected-accounts-list__row--highlight"
address={address}
name={`${name} (…${address.substr(-4, 4)})`}
- status={(
- <>
- {t('statusNotConnected')}
- ·
-
- {t('connect')}
-
- >
+ status={t('statusNotConnected')}
+ action={(
+ connectAccount(accountToConnect.address)}
+ >
+ {t('connect')}
+
)}
/>
)
}
- render () {
- const { connectedAccounts, permissions, selectedAddress } = this.props
+ renderListItemOptions (address) {
const { accountWithOptionsShown } = this.state
const { t } = this.context
+ return (
+
+
+
+ )
+ }
+
+ renderListItemAction (address) {
+ const { t } = this.context
+
+ return (
+ this.switchAccount(address)}
+ >
+ {t('switchToThisAccount')}
+
+ )
+ }
+
+ render () {
+ const {
+ connectedAccounts,
+ selectedAddress,
+ shouldRenderListOptions,
+ } = this.props
+ const { t } = this.context
+
return (
<>
{this.renderUnconnectedAccount()}
{
- connectedAccounts.map(({ address, name, lastActive }, index) => {
- let status
- if (index === 0) {
- status = t('primary')
- } else if (lastActive) {
- status = `${t('lastActive')}: ${DateTime.fromMillis(lastActive).toISODate()}`
- }
-
+ connectedAccounts.map(({ address, name }, index) => {
return (
- {
- address === selectedAddress ? null : (
-
- )
- }
-
-
- )}
+ status={index === 0 ? t('active') : null}
+ options={
+ shouldRenderListOptions
+ ? this.renderListItemOptions(address)
+ : null
+ }
+ action={
+ address !== selectedAddress
+ ? this.renderListItemAction(address)
+ : null
+ }
/>
)
})
}
-
>
)
}
diff --git a/ui/app/components/app/connected-accounts-list/index.scss b/ui/app/components/app/connected-accounts-list/index.scss
index edb77009d..fb462775e 100644
--- a/ui/app/components/app/connected-accounts-list/index.scss
+++ b/ui/app/components/app/connected-accounts-list/index.scss
@@ -8,28 +8,34 @@
}
&__account-name {
+ display: inline;
font-weight: bold;
font-size: 14px;
line-height: 20px;
}
+ %account-status-typography {
+ font-size: 12px;
+ line-height: 17px;
+ padding-top: 4px;
+ }
+
&__account-status {
+ @extend %account-status-typography;
+ display: inline;
color: $Grey-500;
}
&__account-status-link {
+ @extend %account-status-typography;
+ display: block;
+
&, &:hover {
color: $curious-blue;
cursor: pointer;
}
}
- &__account-status {
- font-size: 12px;
- line-height: 17px;
- padding-top: 4px;
- }
-
&__row {
display: flex;
flex-direction: row;
@@ -40,10 +46,6 @@
border-top: 1px solid $geyser;
- &:last-of-type {
- border-bottom: 1px solid $geyser;
- }
-
&--highlight {
background-color: $warning-light-yellow;
border: 1px solid $warning-yellow;
@@ -70,72 +72,6 @@
}
}
-.connected-accounts-permissions {
- display: flex;
- flex-direction: column;
- padding: 24px;
-
- font-size: 12px;
- line-height: 17px;
- color: $Grey-500;
-
- strong {
- font-weight: bold;
- }
-
- p + p {
- padding-top: 8px;
- }
-
- &__header {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- align-items: center;
- cursor: pointer;
-
- font-size: 14px;
- line-height: 20px;
- color: #24292E;
-
- button {
- font-size: 16px;
- line-height: 24px;
-
- background: none;
- padding: 0;
- margin-left: 8px;
- }
- }
-
- &__list {
- padding-top: 8px;
- }
-
- &__list-item {
- display: flex;
-
- i {
- display: block;
- padding-right: 8px;
- font-size: 18px;
- color: $Grey-800;
- }
- }
-
- &__list-container {
- max-height: 0px;
- overflow: hidden;
- height: auto;
- transition: max-height 0.8s cubic-bezier(0.4, 0.0, 0.2, 1);
-
- &--expanded {
- // arbitrarily set hard coded value for effect to work
- max-height: 100px;
- }
- }
-}
-
.tippy-tooltip.none-theme {
background: none;
padding: 0;
diff --git a/ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/connected-accounts-list-permissions.component.js b/ui/app/components/app/connected-accounts-permissions/connected-accounts-permissions.component.js
similarity index 95%
rename from ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/connected-accounts-list-permissions.component.js
rename to ui/app/components/app/connected-accounts-permissions/connected-accounts-permissions.component.js
index 7ee497d53..45f886912 100644
--- a/ui/app/components/app/connected-accounts-list/connected-accounts-list-permissions/connected-accounts-list-permissions.component.js
+++ b/ui/app/components/app/connected-accounts-permissions/connected-accounts-permissions.component.js
@@ -2,7 +2,7 @@ import classnames from 'classnames'
import PropTypes from 'prop-types'
import React, { PureComponent } from 'react'
-export default class ConnectedAccountsListPermissions extends PureComponent {
+export default class ConnectedAccountsPermissions extends PureComponent {
static contextTypes = {
t: PropTypes.func.isRequired,
}
diff --git a/ui/app/components/app/connected-accounts-permissions/index.js b/ui/app/components/app/connected-accounts-permissions/index.js
new file mode 100644
index 000000000..6c6113c82
--- /dev/null
+++ b/ui/app/components/app/connected-accounts-permissions/index.js
@@ -0,0 +1 @@
+export { default } from './connected-accounts-permissions.component'
diff --git a/ui/app/components/app/connected-accounts-permissions/index.scss b/ui/app/components/app/connected-accounts-permissions/index.scss
new file mode 100644
index 000000000..838e727dc
--- /dev/null
+++ b/ui/app/components/app/connected-accounts-permissions/index.scss
@@ -0,0 +1,64 @@
+.connected-accounts-permissions {
+ display: flex;
+ flex-direction: column;
+
+ font-size: 12px;
+ line-height: 17px;
+ color: $Grey-500;
+
+ strong {
+ font-weight: bold;
+ }
+
+ p + p {
+ padding-top: 8px;
+ }
+
+ &__header {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+
+ font-size: 14px;
+ line-height: 20px;
+ color: #24292E;
+
+ button {
+ font-size: 16px;
+ line-height: 24px;
+
+ background: none;
+ padding: 0;
+ margin-left: 8px;
+ }
+ }
+
+ &__list {
+ padding-top: 8px;
+ }
+
+ &__list-item {
+ display: flex;
+
+ i {
+ display: block;
+ padding-right: 8px;
+ font-size: 18px;
+ color: $Grey-800;
+ }
+ }
+
+ &__list-container {
+ max-height: 0px;
+ overflow: hidden;
+ height: auto;
+ transition: max-height 0.8s cubic-bezier(0.4, 0.0, 0.2, 1);
+
+ &--expanded {
+ // arbitrarily set hard coded value for effect to work
+ max-height: 100px;
+ }
+ }
+}
diff --git a/ui/app/components/app/connected-sites-list/connected-sites-list.component.js b/ui/app/components/app/connected-sites-list/connected-sites-list.component.js
index 436b65338..6f6ff4f9a 100644
--- a/ui/app/components/app/connected-sites-list/connected-sites-list.component.js
+++ b/ui/app/components/app/connected-sites-list/connected-sites-list.component.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
-import IconWithFallBack from '../../ui/icon-with-fallback'
+import SiteIcon from '../../ui/site-icon'
import { stripHttpSchemes } from '../../../helpers/utils/util'
export default class ConnectedSitesList extends Component {
@@ -28,7 +28,7 @@ export default class ConnectedSitesList extends Component {
{ connectedDomains.map((domain) => (
-
+
{this.getDomainDisplayName(domain)}
diff --git a/ui/app/components/app/index.scss b/ui/app/components/app/index.scss
index 6fbe4389b..59088d232 100644
--- a/ui/app/components/app/index.scss
+++ b/ui/app/components/app/index.scss
@@ -88,10 +88,14 @@
@import 'connected-accounts-list/index';
-@import '../ui/icon-with-fallback/index';
+@import 'connected-accounts-permissions/index';
@import '../ui/icon/index';
+@import '../ui/icon-with-fallback/icon-with-fallback';
+
+@import '../ui/icon-with-label/index';
+
@import '../ui/circle-icon/index';
@import '../ui/alert-circle-icon/index';
@@ -109,3 +113,5 @@
@import 'wallet-overview/index';
@import '../ui/account-mismatch-warning/index';
+
+@import '../ui/icon-border/icon-border';
diff --git a/ui/app/components/app/menu-bar/index.scss b/ui/app/components/app/menu-bar/index.scss
index 368e5a8ec..4b9e428fa 100644
--- a/ui/app/components/app/menu-bar/index.scss
+++ b/ui/app/components/app/menu-bar/index.scss
@@ -21,7 +21,7 @@
.account-options-menu {
&__connected-sites:before {
content: "";
- background-image: url(/images/icons/connected-sites-black.svg);
+ background-image: url(/images/icons/connected-sites.svg);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
diff --git a/ui/app/components/app/permission-page-container/index.scss b/ui/app/components/app/permission-page-container/index.scss
index a996aed5b..9a17655ec 100644
--- a/ui/app/components/app/permission-page-container/index.scss
+++ b/ui/app/components/app/permission-page-container/index.scss
@@ -46,15 +46,6 @@
padding-left: 24px;
padding-right: 24px;
- &--redirect {
- margin-top: 140px;
- width: 100%;
- display: flex;
- align-items: center;
- padding-top: 8px;
- height: 144px;
- }
-
a, a:hover {
color: $dodger-blue;
}
@@ -94,10 +85,6 @@
@extend %content-text;
line-height: 20px;
color: #6A737D;
-
- &--redirect {
- text-align: center;
- }
}
&__permissions-container {
@@ -147,105 +134,3 @@
font-weight: bold;
}
}
-
-.permission-result {
- @extend %header--24;
-
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- align-items: center;
- text-align: center;
- color: $Black-100;
-
- &__icons {
- display: flex;
- }
-
- &__center-icon {
- display: flex;
- position: relative;
- justify-content: center;
- align-items: center;
- font-size: 12px;
- }
-
- h1 {
- font-size: 14px;
- line-height: 18px;
- padding: 8px 0 0;
- }
-
- h2 {
- font-size: 12px;
- line-height: 17px;
- color: #6A737D;
- padding: 0;
- }
-
- &__check {
- width: 40px;
- height: 40px;
- background: white url("/images/permissions-check.svg") no-repeat;
- position: absolute;
- }
-
- &__reject {
- position: absolute;
- background: white;
- display: flex;
- justify-content: center;
- align-items: center;
-
- i {
- color: #D73A49;
- transform: scale(3);
- }
- }
-
- &__identicon, .icon-with-fallback__identicon {
- width: 32px;
- height: 32px;
-
- &--default {
- background-color: #777A87;
- color: white;
- width: 64px;
- height: 64px;
- border-radius: 32px;
- display: flex;
- align-items: center;
- justify-content: center;
- font-weight: bold;
- }
- }
-
- &__identicon-container, .icon-with-fallback__identicon-container {
- height: auto;
- position: relative;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 64px;
- width: 64px;
- }
-
- &__identicon-border, .icon-with-fallback__identicon-border {
- height: 64px;
- width: 64px;
- border-radius: 50%;
- border: 1px solid white;
- background: #FFFFFF;
- box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25);
- }
-
- &__identicon-border {
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .icon-with-fallback__identicon-border {
- position: absolute;
- }
-}
diff --git a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js
index db7a225b3..c15e93a87 100644
--- a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js
+++ b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js
@@ -1,9 +1,7 @@
import PropTypes from 'prop-types'
import React, { PureComponent } from 'react'
-import IconWithFallBack from '../../../ui/icon-with-fallback'
import PermissionsConnectHeader from '../../permissions-connect-header'
import Tooltip from '../../../ui/tooltip-v2'
-import classnames from 'classnames'
export default class PermissionPageContainerContent extends PureComponent {
@@ -13,13 +11,9 @@ export default class PermissionPageContainerContent extends PureComponent {
onPermissionToggle: PropTypes.func.isRequired,
selectedIdentities: PropTypes.array,
allIdentitiesSelected: PropTypes.bool,
- redirect: PropTypes.bool,
- permissionRejected: PropTypes.bool,
}
static defaultProps = {
- redirect: null,
- permissionRejected: null,
selectedIdentities: [],
allIdentitiesSelected: false,
}
@@ -28,39 +22,6 @@ export default class PermissionPageContainerContent extends PureComponent {
t: PropTypes.func,
}
- renderBrokenLine () {
- return (
-
- )
- }
-
- renderRedirect () {
- const { t } = this.context
- const { permissionRejected, domainMetadata } = this.props
- return (
-
- { permissionRejected ? t('cancelling') : t('connecting') }
-
-
-
- { permissionRejected
- ?
- :
- }
- { this.renderBrokenLine() }
-
-
-
-
-
-
-
-
- )
- }
-
renderRequestedPermissions () {
const {
selectedPermissions, onPermissionToggle,
@@ -134,14 +95,10 @@ export default class PermissionPageContainerContent extends PureComponent {
}
getTitle () {
- const { domainMetadata, redirect, permissionRejected, selectedIdentities, allIdentitiesSelected } = this.props
+ const { domainMetadata, selectedIdentities, allIdentitiesSelected } = this.props
const { t } = this.context
- if (redirect && permissionRejected) {
- return t('cancelledConnectionWithMetaMask')
- } else if (redirect) {
- return t('connectingWithMetaMask')
- } else if (domainMetadata.extensionId) {
+ if (domainMetadata.extensionId) {
return t('externalExtension', [domainMetadata.extensionId])
} else if (allIdentitiesSelected) {
return t(
@@ -166,36 +123,27 @@ export default class PermissionPageContainerContent extends PureComponent {
}
render () {
- const { domainMetadata, redirect } = this.props
+ const { domainMetadata } = this.props
const { t } = this.context
const title = this.getTitle()
return (
-
- { !redirect
- ? (
-
-
-
- { this.renderRequestedPermissions() }
-
-
- )
- : this.renderRedirect()
- }
+
+
+
+
+ { this.renderRequestedPermissions() }
+
+
)
}
diff --git a/ui/app/components/app/permission-page-container/permission-page-container.component.js b/ui/app/components/app/permission-page-container/permission-page-container.component.js
index 320c28be4..3020b82b5 100644
--- a/ui/app/components/app/permission-page-container/permission-page-container.component.js
+++ b/ui/app/components/app/permission-page-container/permission-page-container.component.js
@@ -13,15 +13,11 @@ export default class PermissionPageContainer extends Component {
selectedIdentities: PropTypes.array,
allIdentitiesSelected: PropTypes.bool,
request: PropTypes.object,
- redirect: PropTypes.bool,
- permissionRejected: PropTypes.bool,
requestMetadata: PropTypes.object,
targetDomainMetadata: PropTypes.object.isRequired,
}
static defaultProps = {
- redirect: null,
- permissionRejected: null,
request: {},
requestMetadata: {},
selectedIdentities: [],
@@ -116,8 +112,6 @@ export default class PermissionPageContainer extends Component {
requestMetadata,
targetDomainMetadata,
selectedIdentities,
- redirect,
- permissionRejected,
allIdentitiesSelected,
} = this.props
@@ -129,27 +123,20 @@ export default class PermissionPageContainer extends Component {
selectedPermissions={this.state.selectedPermissions}
onPermissionToggle={this.onPermissionToggle}
selectedIdentities={selectedIdentities}
- redirect={redirect}
- permissionRejected={permissionRejected}
allIdentitiesSelected={allIdentitiesSelected}
/>
- { !redirect
- ? (
-
-
-
this.onCancel()}
- cancelText={this.context.t('cancel')}
- onSubmit={() => this.onSubmit()}
- submitText={this.context.t('connect')}
- submitButtonType="confirm"
- buttonSizeLarge={false}
- />
-
- )
- : null
- }
+
+
+
this.onCancel()}
+ cancelText={this.context.t('cancel')}
+ onSubmit={() => this.onSubmit()}
+ submitText={this.context.t('connect')}
+ submitButtonType="confirm"
+ buttonSizeLarge={false}
+ />
+
)
}
diff --git a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js
index 456295536..e32f8a0b1 100644
--- a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js
+++ b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js
@@ -1,17 +1,18 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
-import IconWithFallBack from '../../ui/icon-with-fallback'
+import SiteIcon from '../../ui/site-icon'
export default class PermissionsConnectHeader extends Component {
static propTypes = {
icon: PropTypes.string,
- iconName: PropTypes.string.isRequired,
+ iconName: PropTypes.string,
headerTitle: PropTypes.node,
headerText: PropTypes.string,
}
static defaultProps = {
icon: null,
+ iconName: '',
headerTitle: '',
headerText: '',
}
@@ -21,7 +22,7 @@ export default class PermissionsConnectHeader extends Component {
return (
)
diff --git a/ui/app/components/app/token-cell/token-cell.js b/ui/app/components/app/token-cell/token-cell.js
index 87b3210a8..cf23b51ac 100644
--- a/ui/app/components/app/token-cell/token-cell.js
+++ b/ui/app/components/app/token-cell/token-cell.js
@@ -1,47 +1,18 @@
import classnames from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
-import { conversionUtil, multiplyCurrencies } from '../../../helpers/utils/conversion-util'
import AssetListItem from '../asset-list-item'
import { useSelector } from 'react-redux'
-import { getTokenExchangeRates, getConversionRate, getCurrentCurrency, getSelectedAddress } from '../../../selectors'
+import { getSelectedAddress } from '../../../selectors'
import { useI18nContext } from '../../../hooks/useI18nContext'
-import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'
+import { useTokenFiatAmount } from '../../../hooks/useTokenFiatAmount'
+
export default function TokenCell ({ address, outdatedBalance, symbol, string, image, onClick }) {
- const contractExchangeRates = useSelector(getTokenExchangeRates)
- const conversionRate = useSelector(getConversionRate)
- const currentCurrency = useSelector(getCurrentCurrency)
const userAddress = useSelector(getSelectedAddress)
const t = useI18nContext()
- let currentTokenToFiatRate
- let currentTokenInFiat
- let formattedFiat = ''
-
-
- // if the conversionRate is 0 eg: currently unknown
- // or the contract exchange rate is currently unknown
- // the effective currentTokenToFiatRate is 0 and erroneous.
- // Skipping this entire block will result in fiat not being
- // shown to the user, instead of a fiat value of 0 for a non-zero
- // token amount.
- if (conversionRate > 0 && contractExchangeRates[address]) {
- currentTokenToFiatRate = multiplyCurrencies(
- contractExchangeRates[address],
- conversionRate
- )
- currentTokenInFiat = conversionUtil(string, {
- fromNumericBase: 'dec',
- fromCurrency: symbol,
- toCurrency: currentCurrency.toUpperCase(),
- numberOfDecimals: 2,
- conversionRate: currentTokenToFiatRate,
- })
- formattedFiat = `${formatCurrency(currentTokenInFiat, currentCurrency)} ${currentCurrency.toUpperCase()}`
- }
-
- const showFiat = Boolean(currentTokenInFiat) && currentCurrency.toUpperCase() !== symbol
+ const formattedFiat = useTokenFiatAmount(address, string, symbol)
const warning = outdatedBalance
? (
@@ -68,7 +39,7 @@ export default function TokenCell ({ address, outdatedBalance, symbol, string, i
tokenImage={image}
warning={warning}
primary={`${string || 0} ${symbol}`}
- secondary={showFiat ? formattedFiat : undefined}
+ secondary={formattedFiat}
/>
)
diff --git a/ui/app/components/app/token-cell/token-cell.test.js b/ui/app/components/app/token-cell/token-cell.test.js
index fba52b602..2b239dab1 100644
--- a/ui/app/components/app/token-cell/token-cell.test.js
+++ b/ui/app/components/app/token-cell/token-cell.test.js
@@ -20,6 +20,12 @@ describe('Token Cell', function () {
'0xAnotherToken': 0.015,
},
conversionRate: 7.00,
+ preferences: {},
+ provider: {
+ chainId: '1',
+ ticker: 'ETH',
+ type: 'mainnet',
+ },
},
appState: {
sidebar: {
diff --git a/ui/app/components/app/token-list/token-list.js b/ui/app/components/app/token-list/token-list.js
index cc0a4acaf..591dbe33a 100644
--- a/ui/app/components/app/token-list/token-list.js
+++ b/ui/app/components/app/token-list/token-list.js
@@ -1,6 +1,5 @@
import React from 'react'
import PropTypes from 'prop-types'
-import contracts from 'eth-contract-metadata'
import { isEqual } from 'lodash'
import TokenCell from '../token-cell'
@@ -10,15 +9,6 @@ import { useSelector } from 'react-redux'
import { getAssetImages } from '../../../selectors'
import { getTokens } from '../../../ducks/metamask/metamask'
-const defaultTokens = []
-for (const address in contracts) {
- const contract = contracts[address]
- if (contract.erc20) {
- contract.address = address
- defaultTokens.push(contract)
- }
-}
-
export default function TokenList ({ onTokenClick }) {
const t = useI18nContext()
const assetImages = useSelector(getAssetImages)
diff --git a/ui/app/components/app/transaction-icon/index.js b/ui/app/components/app/transaction-icon/index.js
new file mode 100644
index 000000000..d41970a54
--- /dev/null
+++ b/ui/app/components/app/transaction-icon/index.js
@@ -0,0 +1 @@
+export { default } from './transaction-icon'
diff --git a/ui/app/components/app/transaction-icon/transaction-icon.js b/ui/app/components/app/transaction-icon/transaction-icon.js
new file mode 100644
index 000000000..24f4f4715
--- /dev/null
+++ b/ui/app/components/app/transaction-icon/transaction-icon.js
@@ -0,0 +1,58 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import Approve from '../../ui/icon/approve-icon.component'
+import Interaction from '../../ui/icon/interaction-icon.component'
+import Receive from '../../ui/icon/receive-icon.component'
+import Send from '../../ui/icon/send-icon.component'
+import Sign from '../../ui/icon/sign-icon.component'
+import {
+ TRANSACTION_CATEGORY_APPROVAL,
+ TRANSACTION_CATEGORY_SIGNATURE_REQUEST,
+ TRANSACTION_CATEGORY_INTERACTION,
+ TRANSACTION_CATEGORY_SEND,
+ TRANSACTION_CATEGORY_RECEIVE,
+ UNAPPROVED_STATUS,
+ FAILED_STATUS,
+ REJECTED_STATUS,
+ CANCELLED_STATUS,
+ DROPPED_STATUS,
+ SUBMITTED_STATUS,
+ APPROVED_STATUS,
+} from '../../../helpers/constants/transactions'
+
+
+const ICON_MAP = {
+ [TRANSACTION_CATEGORY_APPROVAL]: Approve,
+ [TRANSACTION_CATEGORY_INTERACTION]: Interaction,
+ [TRANSACTION_CATEGORY_SEND]: Send,
+ [TRANSACTION_CATEGORY_SIGNATURE_REQUEST]: Sign,
+ [TRANSACTION_CATEGORY_RECEIVE]: Receive,
+}
+
+const FAIL_COLOR = '#D73A49'
+const PENDING_COLOR = '#6A737D'
+const OK_COLOR = '#2F80ED'
+
+const COLOR_MAP = {
+ [SUBMITTED_STATUS]: PENDING_COLOR,
+ [UNAPPROVED_STATUS]: PENDING_COLOR,
+ [APPROVED_STATUS]: PENDING_COLOR,
+ [FAILED_STATUS]: FAIL_COLOR,
+ [REJECTED_STATUS]: FAIL_COLOR,
+ [CANCELLED_STATUS]: FAIL_COLOR,
+ [DROPPED_STATUS]: FAIL_COLOR,
+}
+
+export default function TransactionIcon ({ status, category }) {
+
+ const color = COLOR_MAP[status] || OK_COLOR
+
+ const Icon = ICON_MAP[category]
+
+ return
+}
+
+TransactionIcon.propTypes = {
+ status: PropTypes.string.isRequired,
+ category: PropTypes.string.isRequired,
+}
diff --git a/ui/app/components/app/transaction-list-item/index.scss b/ui/app/components/app/transaction-list-item/index.scss
index 3f7af9586..71282e718 100644
--- a/ui/app/components/app/transaction-list-item/index.scss
+++ b/ui/app/components/app/transaction-list-item/index.scss
@@ -1,10 +1,4 @@
.transaction-list-item {
- cursor: pointer;
-
- &:hover {
- background-color: $Grey-000;
- }
-
&__primary-currency {
color: $Black-100;
}
@@ -15,29 +9,14 @@
color: $Grey-500;
}
- &--pending {
+ &--unconfirmed {
color: $Grey-500;
}
- &--pending &__primary-currency {
+ &--unconfirmed &__primary-currency {
color: $Grey-500;
}
- &__status {
- &--unapproved {
- color: $flamingo;
- }
- &--failed {
- color: $valencia;
- }
- &--cancelled {
- color: $valencia;
- }
- &--queued {
- color: $Grey-500;
- }
- }
-
&__pending-actions {
padding-top: 12px;
display: flex;
diff --git a/ui/app/components/app/transaction-list-item/transaction-list-item.component.js b/ui/app/components/app/transaction-list-item/transaction-list-item.component.js
index e22345916..a92880c52 100644
--- a/ui/app/components/app/transaction-list-item/transaction-list-item.component.js
+++ b/ui/app/components/app/transaction-list-item/transaction-list-item.component.js
@@ -3,11 +3,7 @@ import PropTypes from 'prop-types'
import classnames from 'classnames'
import ListItem from '../../ui/list-item'
import { useTransactionDisplayData } from '../../../hooks/useTransactionDisplayData'
-import Approve from '../../ui/icon/approve-icon.component'
-import Interaction from '../../ui/icon/interaction-icon.component'
-import Receive from '../../ui/icon/receive-icon.component'
import Preloader from '../../ui/icon/preloader'
-import Send from '../../ui/icon/send-icon.component'
import { useI18nContext } from '../../../hooks/useI18nContext'
import { useCancelTransaction } from '../../../hooks/useCancelTransaction'
import { useRetryTransaction } from '../../../hooks/useRetryTransaction'
@@ -17,17 +13,17 @@ import TransactionListItemDetails from '../transaction-list-item-details'
import { useHistory } from 'react-router-dom'
import { CONFIRM_TRANSACTION_ROUTE } from '../../../helpers/constants/routes'
import {
- TRANSACTION_CATEGORY_APPROVAL,
TRANSACTION_CATEGORY_SIGNATURE_REQUEST,
- TRANSACTION_CATEGORY_INTERACTION,
- TRANSACTION_CATEGORY_SEND,
- TRANSACTION_CATEGORY_RECEIVE,
UNAPPROVED_STATUS,
FAILED_STATUS,
- CANCELLED_STATUS,
+ DROPPED_STATUS,
+ REJECTED_STATUS,
} from '../../../helpers/constants/transactions'
import { useShouldShowSpeedUp } from '../../../hooks/useShouldShowSpeedUp'
-import Sign from '../../ui/icon/sign-icon.component'
+import TransactionStatus from '../transaction-status/transaction-status.component'
+import TransactionIcon from '../transaction-icon'
+import { useTransactionTimeRemaining } from '../../../hooks/useTransactionTimeRemaining'
+import IconWithLabel from '../../ui/icon-with-label'
export default function TransactionListItem ({ transactionGroup, isEarliestNonce = false }) {
@@ -36,8 +32,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
const { hasCancelled } = transactionGroup
const [showDetails, setShowDetails] = useState(false)
- const { initialTransaction: { id } } = transactionGroup
-
+ const { initialTransaction: { id }, primaryTransaction: { err, submittedTime, gasPrice } } = transactionGroup
const [cancelEnabled, cancelTransaction] = useCancelTransaction(transactionGroup)
const retryTransaction = useRetryTransaction(transactionGroup)
const shouldShowSpeedUp = useShouldShowSpeedUp(transactionGroup, isEarliestNonce)
@@ -55,50 +50,15 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
senderAddress,
} = useTransactionDisplayData(transactionGroup)
- const isApprove = category === TRANSACTION_CATEGORY_APPROVAL
- const isSignatureReq = category === TRANSACTION_CATEGORY_SIGNATURE_REQUEST
- const isInteraction = category === TRANSACTION_CATEGORY_INTERACTION
- const isSend = category === TRANSACTION_CATEGORY_SEND
- const isReceive = category === TRANSACTION_CATEGORY_RECEIVE
- const isUnapproved = status === UNAPPROVED_STATUS
- const isFailed = status === FAILED_STATUS
- const isCancelled = status === CANCELLED_STATUS
-
- const color = isFailed ? '#D73A49' : '#2F80ED'
+ const timeRemaining = useTransactionTimeRemaining(isPending, isEarliestNonce, submittedTime, gasPrice)
- let Icon
- if (isApprove) {
- Icon = Approve
- } else if (isSend) {
- Icon = Send
- } else if (isReceive) {
- Icon = Receive
- } else if (isInteraction) {
- Icon = Interaction
- } else if (isSignatureReq) {
- Icon = Sign
- }
- let subtitleStatus =
{date} ·
- if (isUnapproved) {
- subtitleStatus = (
-
{t('unapproved')} ·
- )
- } else if (isFailed) {
- subtitleStatus = (
-
{t('failed')} ·
- )
- } else if (isCancelled) {
- subtitleStatus = (
-
{t('cancelled')} ·
- )
- } else if (isPending && !isEarliestNonce) {
- subtitleStatus = (
-
{t('queued')} ·
- )
- }
+ const isSignatureReq = category === TRANSACTION_CATEGORY_SIGNATURE_REQUEST
+ const isUnapproved = status === UNAPPROVED_STATUS
- const className = classnames('transaction-list-item', { 'transaction-list-item--pending': isPending })
+ const className = classnames('transaction-list-item', {
+ 'transaction-list-item--unconfirmed': isPending || [FAILED_STATUS, DROPPED_STATUS, REJECTED_STATUS].includes(status),
+ })
const toggleShowDetails = useCallback(() => {
if (isUnapproved) {
@@ -106,7 +66,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
return
}
setShowDetails((prev) => !prev)
- }, [isUnapproved, id])
+ }, [isUnapproved, history, id])
const cancelButton = useMemo(() => {
const cancelButton = (
@@ -131,7 +91,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
) : cancelButton
- }, [cancelEnabled, cancelTransaction, hasCancelled])
+ }, [isPending, t, isUnapproved, cancelEnabled, cancelTransaction, hasCancelled])
const speedUpButton = useMemo(() => {
if (!shouldShowSpeedUp || !isPending || isUnapproved) {
@@ -147,7 +107,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
{ t('speedUp') }
)
- }, [shouldShowSpeedUp, isPending, retryTransaction])
+ }, [shouldShowSpeedUp, isUnapproved, t, isPending, retryTransaction])
return (
<>
@@ -156,14 +116,22 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
className={className}
title={title}
titleIcon={!isUnapproved && isPending && isEarliestNonce && (
-
}
+ label={timeRemaining}
/>
)}
- icon={
}
+ icon={
}
subtitle={subtitle}
- subtitleStatus={subtitleStatus}
+ subtitleStatus={(
+
+ )}
rightContent={!isSignatureReq && (
<>
{primaryCurrency}
@@ -184,7 +152,7 @@ export default function TransactionListItem ({ transactionGroup, isEarliestNonce
senderAddress={senderAddress}
recipientAddress={recipientAddress}
onRetry={retryTransaction}
- showRetry={isFailed}
+ showRetry={status === FAILED_STATUS}
showSpeedUp={shouldShowSpeedUp}
isEarliestNonce={isEarliestNonce}
onCancel={cancelTransaction}
diff --git a/ui/app/components/app/transaction-list/transaction-list.component.js b/ui/app/components/app/transaction-list/transaction-list.component.js
index 46b8b45de..dac902add 100644
--- a/ui/app/components/app/transaction-list/transaction-list.component.js
+++ b/ui/app/components/app/transaction-list/transaction-list.component.js
@@ -12,6 +12,7 @@ import * as actions from '../../../ducks/gas/gas.duck'
import { useI18nContext } from '../../../hooks/useI18nContext'
import TransactionListItem from '../transaction-list-item'
import Button from '../../ui/button'
+import { TOKEN_CATEGORY_HASH } from '../../../helpers/constants/transactions'
const PAGE_INCREMENT = 10
@@ -19,7 +20,23 @@ const getTransactionGroupRecipientAddressFilter = (recipientAddress) => {
return ({ initialTransaction: { txParams } }) => txParams && txParams.to === recipientAddress
}
-export default function TransactionList ({ tokenAddress }) {
+const tokenTransactionFilter = ({
+ initialTransaction: {
+ transactionCategory,
+ },
+}) => !TOKEN_CATEGORY_HASH[transactionCategory]
+
+
+const getFilteredTransactionGroups = (transactionGroups, hideTokenTransactions, tokenAddress) => {
+ if (hideTokenTransactions) {
+ return transactionGroups.filter(tokenTransactionFilter)
+ } else if (tokenAddress) {
+ return transactionGroups.filter(getTransactionGroupRecipientAddressFilter(tokenAddress))
+ }
+ return transactionGroups
+}
+
+export default function TransactionList ({ hideTokenTransactions, tokenAddress }) {
const [limit, setLimit] = useState(PAGE_INCREMENT)
const t = useI18nContext()
@@ -29,22 +46,12 @@ export default function TransactionList ({ tokenAddress }) {
const { transactionTime: transactionTimeFeatureActive } = useSelector(getFeatureFlags)
const pendingTransactions = useMemo(
- () => (
- tokenAddress && tokenAddress.startsWith('0x')
- ? unfilteredPendingTransactions
- .filter(getTransactionGroupRecipientAddressFilter(tokenAddress))
- : unfilteredPendingTransactions
- ),
- [unfilteredPendingTransactions, tokenAddress]
+ () => getFilteredTransactionGroups(unfilteredPendingTransactions, hideTokenTransactions, tokenAddress),
+ [hideTokenTransactions, tokenAddress, unfilteredPendingTransactions]
)
const completedTransactions = useMemo(
- () => (
- tokenAddress && tokenAddress.startsWith('0x')
- ? unfilteredCompletedTransactions
- .filter(getTransactionGroupRecipientAddressFilter(tokenAddress))
- : unfilteredCompletedTransactions
- ),
- [unfilteredCompletedTransactions, tokenAddress]
+ () => getFilteredTransactionGroups(unfilteredCompletedTransactions, hideTokenTransactions, tokenAddress),
+ [hideTokenTransactions, tokenAddress, unfilteredCompletedTransactions]
)
const { fetchGasEstimates, fetchBasicGasAndTimeEstimates } = useMemo(() => ({
@@ -122,9 +129,11 @@ export default function TransactionList ({ tokenAddress }) {
}
TransactionList.propTypes = {
+ hideTokenTransactions: PropTypes.bool,
tokenAddress: PropTypes.string,
}
TransactionList.defaultProps = {
+ hideTokenTransactions: false,
tokenAddress: undefined,
}
diff --git a/ui/app/components/app/transaction-status/index.scss b/ui/app/components/app/transaction-status/index.scss
index 99884d28c..13dcd6c30 100644
--- a/ui/app/components/app/transaction-status/index.scss
+++ b/ui/app/components/app/transaction-status/index.scss
@@ -1,52 +1,24 @@
.transaction-status {
- height: 26px;
- width: 84px;
- border-radius: 4px;
- background-color: #f0f0f0;
- color: #5e6064;
- font-size: .625rem;
- text-transform: uppercase;
- display: flex;
- justify-content: center;
- align-items: center;
-
- @media screen and (max-width: $break-small) {
- height: 16px;
- min-width: 72px;
- font-size: 10px;
- padding: 0 12px;
+ display: inline;
+ &--unapproved {
+ color: $Orange-500;
}
-
- &--confirmed {
- background-color: #eafad7;
- color: #609a1c;
-
- .transaction-status__transaction-count {
- border: 1px solid #609a1c;
- }
+ &--failed {
+ color: $Red-500;
}
-
- &--approved, &--submitted {
- background-color: #FFF2DB;
- color: #CA810A;
-
- .transaction-status__transaction-count {
- border: 1px solid #CA810A;
- }
+ &--cancelled {
+ color: $Red-500;
}
-
- &--failed {
- background: lighten($monzo, 56%);
- color: $monzo;
-
- .transaction-status__transaction-count {
- border: 1px solid $monzo;
- }
+ &--dropped {
+ color: $Red-500;
+ }
+ &--rejected {
+ color: $Red-500;
+ }
+ &--pending {
+ color: $Orange-500;
}
-
- &__pending-spinner {
- height: 16px;
- width: 16px;
- margin-right: 6px;
+ &--queued {
+ color: $Grey-500;
}
}
diff --git a/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js b/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js
index 510950248..939090875 100644
--- a/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js
+++ b/ui/app/components/app/transaction-status/tests/transaction-status.component.test.js
@@ -1,33 +1,80 @@
import React from 'react'
import assert from 'assert'
import { mount } from 'enzyme'
+import sinon from 'sinon'
+import * as i18nHook from '../../../../hooks/useI18nContext'
import TransactionStatus from '../transaction-status.component'
import Tooltip from '../../../ui/tooltip-v2'
describe('TransactionStatus Component', function () {
- it('should render APPROVED properly', function () {
+ before(function () {
+ sinon.stub(i18nHook, 'useI18nContext').returns((str) => str.toUpperCase())
+ })
+
+ it('should render CONFIRMED properly', function () {
const wrapper = mount(
,
- { context: { t: (str) => str.toUpperCase() } }
+ status="confirmed"
+ date="June 1"
+ />
)
assert.ok(wrapper)
- assert.equal(wrapper.text(), 'APPROVED')
+ assert.equal(wrapper.text(), 'June 1 · ')
+ })
+
+ it('should render PENDING properly when status is APPROVED', function () {
+ const wrapper = mount(
+
+ )
+
+ assert.ok(wrapper)
+ assert.equal(wrapper.text(), 'PENDING · ')
assert.equal(wrapper.find(Tooltip).props().title, 'test-title')
})
- it('should render SUBMITTED properly', function () {
+ it('should render PENDING properly', function () {
const wrapper = mount(
,
- { context: { t: (str) => str.toUpperCase() } }
+ date="June 1"
+ status="submitted"
+ isEarliestNonce
+ />
)
assert.ok(wrapper)
- assert.equal(wrapper.text(), 'PENDING')
+ assert.equal(wrapper.text(), 'PENDING · ')
+ })
+
+ it('should render QUEUED properly', function () {
+ const wrapper = mount(
+
+ )
+
+ assert.ok(wrapper)
+ assert.ok(wrapper.find('.transaction-status--queued').length, 'queued className not found')
+ assert.equal(wrapper.text(), 'QUEUED · ')
+ })
+
+ it('should render UNAPPROVED properly', function () {
+ const wrapper = mount(
+
+ )
+
+ assert.ok(wrapper)
+ assert.ok(wrapper.find('.transaction-status--unapproved').length, 'unapproved className not found')
+ assert.equal(wrapper.text(), 'UNAPPROVED · ')
+ })
+
+ after(function () {
+ sinon.restore()
})
})
diff --git a/ui/app/components/app/transaction-status/transaction-status.component.js b/ui/app/components/app/transaction-status/transaction-status.component.js
index a97b79bde..c525f7484 100644
--- a/ui/app/components/app/transaction-status/transaction-status.component.js
+++ b/ui/app/components/app/transaction-status/transaction-status.component.js
@@ -1,66 +1,78 @@
-import React, { PureComponent } from 'react'
+import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import Tooltip from '../../ui/tooltip-v2'
-import Spinner from '../../ui/spinner'
import {
UNAPPROVED_STATUS,
REJECTED_STATUS,
- APPROVED_STATUS,
- SIGNED_STATUS,
SUBMITTED_STATUS,
CONFIRMED_STATUS,
FAILED_STATUS,
DROPPED_STATUS,
CANCELLED_STATUS,
+ APPROVED_STATUS,
+ SIGNED_STATUS,
} from '../../../helpers/constants/transactions'
+import { useI18nContext } from '../../../hooks/useI18nContext'
+
+const QUEUED_PSEUDO_STATUS = 'queued'
+const PENDING_PSEUDO_STATUS = 'pending'
+
+/**
+ * A note about status logic for this component:
+ * Approved, Signed and Submitted statuses are all treated, effectively
+ * as pending. Transactions are only approved or signed for less than a
+ * second, usually, and ultimately should be rendered in the UI no
+ * differently than a pending transaction.
+ *
+ * Confirmed transactions are not especially highlighted except that their
+ * status label will be the date the transaction was finalized.
+ */
+const pendingStatusHash = {
+ [SUBMITTED_STATUS]: PENDING_PSEUDO_STATUS,
+ [APPROVED_STATUS]: PENDING_PSEUDO_STATUS,
+ [SIGNED_STATUS]: PENDING_PSEUDO_STATUS,
+}
const statusToClassNameHash = {
[UNAPPROVED_STATUS]: 'transaction-status--unapproved',
[REJECTED_STATUS]: 'transaction-status--rejected',
- [APPROVED_STATUS]: 'transaction-status--approved',
- [SIGNED_STATUS]: 'transaction-status--signed',
- [SUBMITTED_STATUS]: 'transaction-status--submitted',
- [CONFIRMED_STATUS]: 'transaction-status--confirmed',
[FAILED_STATUS]: 'transaction-status--failed',
[DROPPED_STATUS]: 'transaction-status--dropped',
- [CANCELLED_STATUS]: 'transaction-status--failed',
+ [CANCELLED_STATUS]: 'transaction-status--cancelled',
+ [QUEUED_PSEUDO_STATUS]: 'transaction-status--queued',
+ [PENDING_PSEUDO_STATUS]: 'transaction-status--pending',
}
-const statusToTextHash = {
- [SUBMITTED_STATUS]: 'pending',
-}
-
-export default class TransactionStatus extends PureComponent {
- static defaultProps = {
- title: null,
+export default function TransactionStatus ({ status, date, error, isEarliestNonce, className }) {
+ const t = useI18nContext()
+ const tooltipText = error?.rpc?.message || error?.message
+ let statusKey = status
+ if (pendingStatusHash[status]) {
+ statusKey = isEarliestNonce ? PENDING_PSEUDO_STATUS : QUEUED_PSEUDO_STATUS
}
- static contextTypes = {
- t: PropTypes.func,
- }
+ const statusText = statusKey === CONFIRMED_STATUS ? date : t(statusKey)
- static propTypes = {
- statusKey: PropTypes.string,
- className: PropTypes.string,
- title: PropTypes.string,
- }
-
- render () {
- const { className, statusKey, title } = this.props
- const statusText = this.context.t(statusToTextHash[statusKey] || statusKey)
+ return (
+
+
+ { statusText }
+
+ {' · '}
+
+ )
+}
- return (
-
- { statusToTextHash[statusKey] === 'pending' ? : null }
-
- { statusText }
-
-
- )
- }
+TransactionStatus.propTypes = {
+ status: PropTypes.string,
+ className: PropTypes.string,
+ date: PropTypes.string,
+ error: PropTypes.object,
+ isEarliestNonce: PropTypes.bool,
}
diff --git a/ui/app/components/app/transaction-time-remaining/index.js b/ui/app/components/app/transaction-time-remaining/index.js
deleted file mode 100644
index 87c6821d8..000000000
--- a/ui/app/components/app/transaction-time-remaining/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './transaction-time-remaining.container'
diff --git a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.component.js b/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.component.js
deleted file mode 100644
index c9598d69b..000000000
--- a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.component.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { PureComponent } from 'react'
-import PropTypes from 'prop-types'
-import { calcTransactionTimeRemaining } from './transaction-time-remaining.util'
-
-export default class TransactionTimeRemaining extends PureComponent {
- static propTypes = {
- className: PropTypes.string,
- initialTimeEstimate: PropTypes.number,
- submittedTime: PropTypes.number,
- }
-
- constructor (props) {
- super(props)
- const { initialTimeEstimate, submittedTime } = props
- this.state = {
- timeRemaining: calcTransactionTimeRemaining(initialTimeEstimate, submittedTime),
- }
- this.interval = setInterval(
- () => this.setState({ timeRemaining: calcTransactionTimeRemaining(initialTimeEstimate, submittedTime) }),
- 1000
- )
- }
-
- componentDidUpdate (prevProps) {
- const { initialTimeEstimate, submittedTime } = this.props
- if (initialTimeEstimate !== prevProps.initialTimeEstimate) {
- clearInterval(this.interval)
- const calcedTimeRemaining = calcTransactionTimeRemaining(initialTimeEstimate, submittedTime)
- this.setState({ timeRemaining: calcedTimeRemaining })
- this.interval = setInterval(
- () => this.setState({ timeRemaining: calcTransactionTimeRemaining(initialTimeEstimate, submittedTime) }),
- 1000
- )
- }
- }
-
- componentWillUnmount () {
- clearInterval(this.interval)
- }
-
- render () {
- const { className } = this.props
- const { timeRemaining } = this.state
-
- return (
-
- { timeRemaining }
-
-
- )
- }
-}
diff --git a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.container.js b/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.container.js
deleted file mode 100644
index 754d84991..000000000
--- a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.container.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { connect } from 'react-redux'
-import TransactionTimeRemaining from './transaction-time-remaining.component'
-import {
- getEstimatedGasPrices,
- getEstimatedGasTimes,
-} from '../../../selectors'
-import { getRawTimeEstimateData } from '../../../helpers/utils/gas-time-estimates.util'
-import { hexWEIToDecGWEI } from '../../../helpers/utils/conversions.util'
-
-const mapStateToProps = (state, ownProps) => {
- const { transaction } = ownProps
- const { gasPrice: currentGasPrice } = transaction.txParams
- const customGasPrice = calcCustomGasPrice(currentGasPrice)
- const gasPrices = getEstimatedGasPrices(state)
- const estimatedTimes = getEstimatedGasTimes(state)
-
- const {
- newTimeEstimate: initialTimeEstimate,
- } = getRawTimeEstimateData(customGasPrice, gasPrices, estimatedTimes)
-
- const submittedTime = transaction.submittedTime
-
- return {
- initialTimeEstimate,
- submittedTime,
- }
-}
-
-export default connect(mapStateToProps)(TransactionTimeRemaining)
-
-function calcCustomGasPrice (customGasPriceInHex) {
- return Number(hexWEIToDecGWEI(customGasPriceInHex))
-}
diff --git a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.util.js b/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.util.js
deleted file mode 100644
index 0ba81edfc..000000000
--- a/ui/app/components/app/transaction-time-remaining/transaction-time-remaining.util.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { formatTimeEstimate } from '../../../helpers/utils/gas-time-estimates.util'
-
-export function calcTransactionTimeRemaining (initialTimeEstimate, submittedTime) {
- const currentTime = (new Date()).getTime()
- const timeElapsedSinceSubmission = (currentTime - submittedTime) / 1000
- const timeRemainingOnEstimate = initialTimeEstimate - timeElapsedSinceSubmission
-
- const renderingTimeRemainingEstimate = timeRemainingOnEstimate < 30
- ? '< 30 s'
- : formatTimeEstimate(timeRemainingOnEstimate)
-
- return renderingTimeRemainingEstimate
-}
diff --git a/ui/app/components/app/wallet-overview/eth-overview.js b/ui/app/components/app/wallet-overview/eth-overview.js
index c9b142af2..d232b0af8 100644
--- a/ui/app/components/app/wallet-overview/eth-overview.js
+++ b/ui/app/components/app/wallet-overview/eth-overview.js
@@ -15,6 +15,7 @@ import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display
import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'
import { showModal } from '../../../store/actions'
import { isBalanceCached, getSelectedAccount, getShouldShowFiat } from '../../../selectors/selectors'
+import PaperAirplane from '../../ui/icon/paper-airplane-icon'
const EthOverview = ({ className }) => {
const dispatch = useDispatch()
@@ -78,18 +79,21 @@ const EthOverview = ({ className }) => {
buttons={(
<>
}
onClick={() => {
sendEvent()
history.push(SEND_ROUTE)
diff --git a/ui/app/components/app/wallet-overview/index.scss b/ui/app/components/app/wallet-overview/index.scss
index ac62d3f43..b461f062a 100644
--- a/ui/app/components/app/wallet-overview/index.scss
+++ b/ui/app/components/app/wallet-overview/index.scss
@@ -27,6 +27,17 @@
}
}
+%asset-buttons {
+ min-width: initial;
+ width: 100px;
+
+ &:not(:last-child) {
+ margin-right: 12px;
+ }
+ text-transform: uppercase;
+ font-weight: bold;
+}
+
.eth-overview {
&__balance {
display: flex;
@@ -73,12 +84,7 @@
}
&__button {
- min-width: initial;
- width: 100px;
-
- &:not(:last-child) {
- margin-right: 12px;
- }
+ @extend %asset-buttons;
}
}
@@ -102,12 +108,14 @@
justify-content: center;
}
- &__button {
- min-width: initial;
- width: 100px;
+ &__secondary-balance {
+ font-size: 16px;
+ line-height: 23px;
+ font-weight: 400;
+ color: $Grey-400;
+ }
- &:not(:last-child) {
- margin-right: 12px;
- }
+ &__button {
+ @extend %asset-buttons;
}
}
diff --git a/ui/app/components/app/wallet-overview/token-overview.js b/ui/app/components/app/wallet-overview/token-overview.js
index 67f5783fb..e1e0df2b6 100644
--- a/ui/app/components/app/wallet-overview/token-overview.js
+++ b/ui/app/components/app/wallet-overview/token-overview.js
@@ -5,13 +5,16 @@ import { useHistory } from 'react-router-dom'
import Button from '../../ui/button'
import Identicon from '../../ui/identicon'
-import TokenBalance from '../../ui/token-balance'
+import CurrencyDisplay from '../../ui/currency-display'
import { I18nContext } from '../../../contexts/i18n'
import WalletOverview from './wallet-overview'
import { SEND_ROUTE } from '../../../helpers/constants/routes'
import { useMetricEvent } from '../../../hooks/useMetricEvent'
+import { useTokenTracker } from '../../../hooks/useTokenTracker'
+import { useTokenFiatAmount } from '../../../hooks/useTokenFiatAmount'
import { getAssetImages } from '../../../selectors/selectors'
import { updateSendToken } from '../../../store/actions'
+import PaperAirplane from '../../ui/icon/paper-airplane-icon'
const TokenOverview = ({ className, token }) => {
const dispatch = useDispatch()
@@ -25,21 +28,38 @@ const TokenOverview = ({ className, token }) => {
})
const history = useHistory()
const assetImages = useSelector(getAssetImages)
+ const { tokensWithBalances } = useTokenTracker([token])
+ const balance = tokensWithBalances[0]?.string
+ const formattedFiatBalance = useTokenFiatAmount(token.address, balance, token.symbol)
return (
-
+ {
+ formattedFiatBalance
+ ? (
+
+ )
+ : null
+ }
)}
buttons={(
}
onClick={() => {
sendTokenEvent()
dispatch(updateSendToken(token))
diff --git a/ui/app/components/ui/button/button.component.js b/ui/app/components/ui/button/button.component.js
index cc4bb45e2..64b19cca3 100644
--- a/ui/app/components/ui/button/button.component.js
+++ b/ui/app/components/ui/button/button.component.js
@@ -25,7 +25,7 @@ const typeHash = {
'first-time': CLASSNAME_FIRST_TIME,
}
-const Button = ({ type, submit, large, children, rounded, className, ...buttonProps }) => (
+const Button = ({ type, submit, large, children, icon, rounded, className, ...buttonProps }) => (
)
@@ -48,6 +49,7 @@ Button.propTypes = {
rounded: PropTypes.bool,
className: PropTypes.string,
children: PropTypes.node,
+ icon: PropTypes.node,
}
Button.defaultProps = {
diff --git a/ui/app/components/ui/button/buttons.scss b/ui/app/components/ui/button/buttons.scss
index be2295a9f..a28dfa4d2 100644
--- a/ui/app/components/ui/button/buttons.scss
+++ b/ui/app/components/ui/button/buttons.scss
@@ -66,6 +66,12 @@ $warning-light-orange: #F8B588;
.button {
@extend %button;
+
+ &__icon {
+ display: flex;
+ align-items: center;
+ margin-right: 4px;
+ }
}
.btn-secondary {
diff --git a/ui/app/components/ui/editable-label.js b/ui/app/components/ui/editable-label.js
index 553965b1c..d1788472e 100644
--- a/ui/app/components/ui/editable-label.js
+++ b/ui/app/components/ui/editable-label.js
@@ -57,7 +57,7 @@ class EditableLabel extends Component {
{this.state.value}
), (
- this.setState({ isEditing: true })} />
+ this.setState({ isEditing: true })} />
)]
}
diff --git a/ui/app/components/ui/icon-border/icon-border.js b/ui/app/components/ui/icon-border/icon-border.js
new file mode 100644
index 000000000..5911cf918
--- /dev/null
+++ b/ui/app/components/ui/icon-border/icon-border.js
@@ -0,0 +1,16 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+export default function IconBorder ({ children, size }) {
+ const borderStyle = { height: `${size}px`, width: `${size}px` }
+ return (
+
+ { children }
+
+ )
+}
+
+IconBorder.propTypes = {
+ children: PropTypes.node.isRequired,
+ size: PropTypes.number.isRequired,
+}
diff --git a/ui/app/components/ui/icon-border/icon-border.scss b/ui/app/components/ui/icon-border/icon-border.scss
new file mode 100644
index 000000000..6a718c83a
--- /dev/null
+++ b/ui/app/components/ui/icon-border/icon-border.scss
@@ -0,0 +1,10 @@
+
+.icon-border {
+ border-radius: 50%;
+ border: 1px solid #F2F3F4;
+ background: #FFFFFF;
+
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/ui/app/components/ui/icon-border/index.js b/ui/app/components/ui/icon-border/index.js
new file mode 100644
index 000000000..dea3f116e
--- /dev/null
+++ b/ui/app/components/ui/icon-border/index.js
@@ -0,0 +1 @@
+export { default } from './icon-border'
diff --git a/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js
index 13b3e93d7..898861468 100644
--- a/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js
+++ b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.component.js
@@ -5,6 +5,7 @@ export default class IconWithFallback extends PureComponent {
static propTypes = {
icon: PropTypes.string,
name: PropTypes.string,
+ size: PropTypes.number.isRequired,
}
static defaultProps = {
@@ -17,26 +18,21 @@ export default class IconWithFallback extends PureComponent {
}
render () {
- const { icon, name } = this.props
+ const { icon, name, size } = this.props
+ const style = { height: `${size}px`, width: `${size}px` }
- return (
-
-
- { !this.state.iconError && icon
- ? (
-
this.setState({ iconError: true })}
- />
- )
- : (
-
- { name.length ? name.charAt(0).toUpperCase() : '' }
-
- )
- }
-
- )
+ return !this.state.iconError && icon
+ ? (
+
this.setState({ iconError: true })}
+ src={icon}
+ style={style}
+ />
+ )
+ : (
+
+ { name.length ? name.charAt(0).toUpperCase() : '' }
+
+ )
}
}
diff --git a/ui/app/components/ui/icon-with-fallback/icon-with-fallback.scss b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.scss
new file mode 100644
index 000000000..a0cb7cd42
--- /dev/null
+++ b/ui/app/components/ui/icon-with-fallback/icon-with-fallback.scss
@@ -0,0 +1,5 @@
+.icon-with-fallback {
+ &__fallback {
+ color: black;
+ }
+}
diff --git a/ui/app/components/ui/icon-with-fallback/index.scss b/ui/app/components/ui/icon-with-fallback/index.scss
deleted file mode 100644
index 215ea6138..000000000
--- a/ui/app/components/ui/icon-with-fallback/index.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-.icon-with-fallback {
- &__identicon-container {
- position: relative;
- display: flex;
- justify-content: center;
- align-items: center;
- height: 32px;
- width: 32px;
- }
-
- &__identicon-border {
- height: 32px;
- width: 32px;
- border-radius: 50%;
- border: 1px solid #F2F3F4;
- position: absolute;
- background: #FFFFFF;
- }
-
- &__identicon {
- position: relative;
- width: 24px;
- height: 24px;
-
- &--default {
- position: relative;
- color: black;
- }
- }
-}
diff --git a/ui/app/components/ui/icon-with-label/icon-with-label.js b/ui/app/components/ui/icon-with-label/icon-with-label.js
new file mode 100644
index 000000000..9e282611b
--- /dev/null
+++ b/ui/app/components/ui/icon-with-label/icon-with-label.js
@@ -0,0 +1,18 @@
+import React from 'react'
+import classnames from 'classnames'
+import PropTypes from 'prop-types'
+
+export default function IconWithLabel ({ icon, label, className }) {
+ return (
+
+ {icon}
+ {label && {label}}
+
+ )
+}
+
+IconWithLabel.propTypes = {
+ icon: PropTypes.node.isRequired,
+ className: PropTypes.string,
+ label: PropTypes.string,
+}
diff --git a/ui/app/components/ui/icon-with-label/index.js b/ui/app/components/ui/icon-with-label/index.js
new file mode 100644
index 000000000..10432ac8f
--- /dev/null
+++ b/ui/app/components/ui/icon-with-label/index.js
@@ -0,0 +1 @@
+export { default } from './icon-with-label'
diff --git a/ui/app/components/ui/icon-with-label/index.scss b/ui/app/components/ui/icon-with-label/index.scss
new file mode 100644
index 000000000..628a54272
--- /dev/null
+++ b/ui/app/components/ui/icon-with-label/index.scss
@@ -0,0 +1,10 @@
+.icon-with-label {
+ display: flex;
+ align-items: center;
+
+ &__label {
+ font-size: 10px;
+ margin-left: 4px;
+ color: $Grey-500;
+ }
+}
diff --git a/ui/app/components/ui/icon/icon.stories.js b/ui/app/components/ui/icon/icon.stories.js
index 73d25e6fd..ee52a2f90 100644
--- a/ui/app/components/ui/icon/icon.stories.js
+++ b/ui/app/components/ui/icon/icon.stories.js
@@ -51,3 +51,7 @@ export const preloader = () => (
size={number('size', 40)}
/>
)
+
+export const PaperAirplane = () => (
+
+)
diff --git a/ui/app/components/ui/icon/paper-airplane-icon.js b/ui/app/components/ui/icon/paper-airplane-icon.js
new file mode 100644
index 000000000..552f02d7c
--- /dev/null
+++ b/ui/app/components/ui/icon/paper-airplane-icon.js
@@ -0,0 +1,33 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+
+export default function PaperAirplane ({ size, className, color }) {
+ return (
+
+ )
+}
+
+PaperAirplane.defaultProps = {
+ color: '#FFFFFF',
+}
+
+PaperAirplane.propTypes = {
+ className: PropTypes.string,
+ size: PropTypes.number.isRequired,
+ color: PropTypes.string,
+}
+
diff --git a/ui/app/components/ui/identicon/blockieIdenticon/blockieIdenticon.component.js b/ui/app/components/ui/identicon/blockieIdenticon/blockieIdenticon.component.js
index 7ed0d00e1..ae75e5474 100644
--- a/ui/app/components/ui/identicon/blockieIdenticon/blockieIdenticon.component.js
+++ b/ui/app/components/ui/identicon/blockieIdenticon/blockieIdenticon.component.js
@@ -14,7 +14,7 @@ const BlockieIdenticon = ({ address, diameter }) => {
if (updatedDataUrl !== dataUrl) {
setDataUrl(updatedDataUrl)
}
- })
+ }, [dataUrl, address])
return (
<>
diff --git a/ui/app/components/ui/list-item/index.scss b/ui/app/components/ui/list-item/index.scss
index f424bc4c6..b6991ea22 100644
--- a/ui/app/components/ui/list-item/index.scss
+++ b/ui/app/components/ui/list-item/index.scss
@@ -15,6 +15,11 @@
'icon sub sub sub sub sub sub sub right right right right'
'. actions actions actions actions actions actions actions right right right right';
align-items: start;
+ cursor: pointer;
+
+ &:hover {
+ background-color: $Grey-000;
+ }
&__icon {
grid-area: icon;
@@ -33,12 +38,11 @@
font-size: 16px;
line-height: 160%;
position: relative;
+ display: flex;
+ align-items: center;
&-wrap {
display: inline-block;
- position: absolute;
- width: 16px;
- height: 16px;
margin-left: 8px;
}
}
diff --git a/ui/app/components/ui/list-item/list-item.component.js b/ui/app/components/ui/list-item/list-item.component.js
index 6f04c5590..60d395ab3 100644
--- a/ui/app/components/ui/list-item/list-item.component.js
+++ b/ui/app/components/ui/list-item/list-item.component.js
@@ -26,9 +26,9 @@ export default function ListItem ({
)}
{ title } {titleIcon && (
-
+
{titleIcon}
-
+
)}
diff --git a/ui/app/components/ui/menu/menu.scss b/ui/app/components/ui/menu/menu.scss
index 5674aee69..76102c49b 100644
--- a/ui/app/components/ui/menu/menu.scss
+++ b/ui/app/components/ui/menu/menu.scss
@@ -44,6 +44,7 @@
&__icon {
margin-right: 8px;
grid-row: 1 / span 2;
+ color: $Grey-500;
}
.disconnect-icon {
diff --git a/ui/app/components/ui/menu/menu.stories.js b/ui/app/components/ui/menu/menu.stories.js
index ec8822d62..c3071c798 100644
--- a/ui/app/components/ui/menu/menu.stories.js
+++ b/ui/app/components/ui/menu/menu.stories.js
@@ -6,7 +6,7 @@ export default {
title: 'Menu',
}
-export const basic = () => {
+export const Basic = () => {
return (