diff options
59 files changed, 3417 insertions, 429 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 75ba7670f..fa4493278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,26 @@ ## Current Master -- MetaMask will no longer allow nonces to be specified by the dapp -- Add ability for internationalization. +## 4.4.0 Mon Mar 26 2018 + +- Internationalization: Taiwanese, Thai, Slovenian +- Fixes bug where MetaMask would not open once its storage grew too large. +- Updates design of new-ui Add Token screen +- New-ui can send to ens addresses +- Update new-ui button styles +- Signed-type-data notification handles long messages +- Popup extension in new-ui uses new on-boarding designs +- Buy ether step of new-ui on-boarding uses new buy ether modal designs + +## 4.3.0 Wed Mar 21 2018 + +- (beta) Add internationalization support! Includes translations for 13 (!!) new languages: French, Spanish, Italian, German, Dutch, Portuguese, Japanese, Korean, Vietnamese, Mandarin, Hindi, Tagalog, and Russian! Select "Try Beta" in the menu to take them for a spin. Read more about the community effort [here](https://medium.com/gitcoin/metamask-internationalizes-via-gitcoin-bf1390c0301c) +- No longer uses nonces specified by the dapp - Will now throw an error if the `to` field in txParams is not valid. - Will strip null values from the `to` field. -- Fix flashing to Log in screen after logging in or restoring from seed phrase. +- (beta) No longer shows token confirmation screen when performing a non-send +- (beta) Fixes bug where tx data was nullified when repricing a tx +- Fix flashing Login screen after logging in or restoring from seed phrase. - Increase tap areas for menu buttons on mobile - Change all fonts in new-ui onboarding to Roboto, size 400 - Add a welcome screen to new-ui onboarding flow @@ -1,5 +1,5 @@ # MetaMask Browser Extension -[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](http://waffle.io/MetaMask/metamask-extension) +[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](https://waffle.io/MetaMask/metamask-extension) ## Support diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index c64b7248b..0bfa992b4 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -171,6 +171,9 @@ "customGas": { "message": "Customize Gas" }, + "customToken": { + "message": "Custom Token" + }, "customize": { "message": "Customize" }, @@ -415,6 +418,9 @@ "message": "JSON File", "description": "format for importing an account" }, + "keepTrackTokens": { + "message": "Keep track of the tokens you’ve bought with your MetaMask account." + }, "kovan": { "message": "Kovan Test Network" }, @@ -424,6 +430,9 @@ "max": { "message": "Max" }, + "learnMore": { + "message": "Learn more." + }, "lessThanMax": { "message": "must be less than or equal to $1.", "description": "helper for inputting hex as decimal input" @@ -564,6 +573,9 @@ "pleaseReviewTransaction": { "message": "Please review your transaction." }, + "popularTokens": { + "message": "Popular Tokens" + }, "privacyMsg": { "message": "Privacy Policy" }, @@ -702,6 +714,9 @@ "onlySendToEtherAddress": { "message": "Only send ETH to an Ethereum address." }, + "searchTokens": { + "message": "Search Tokens" + }, "sendTokensAnywhere": { "message": "Send Tokens to anyone with an Ethereum account" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index aa2701c2c..fa28b09da 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -75,7 +75,7 @@ "message": "Pedir prestado con Dharma (Beta)" }, "builtInCalifornia": { - "message": "Metamask fue diseñado y construido en California " + "message": "Metamask fue diseñado y construido en California" }, "buy": { "message": "Comprar" @@ -84,13 +84,13 @@ "message": "Comprar en Coinbase" }, "buyCoinbaseExplainer": { - "message": "Coinbase es la forma global más popular para comprar y vender bitcoin, ethereum y litecoin" + "message": "Coinbase es la plataforma global más popular para comprar y vender Bitcoin, Ethereum y Litecoin" }, "cancel": { "message": "Cancelar" }, "classicInterface": { - "message": "Usar interfaz clásica " + "message": "Usar interfaz clásica" }, "clickCopy": { "message": "Click para copiar" @@ -144,7 +144,7 @@ "message": "Copiado al portapapeles" }, "copiedExclamation": { - "message": "Copiado!" + "message": "¡Copiado!" }, "copiedSafe": { "message": "Ya lo guardé en un lugar seguro" @@ -156,7 +156,7 @@ "message": " Copiar " }, "copyPrivateKey": { - "message": "Esta es tu llave privada (Click para copiar)" + "message": "Ésta es tu llave privada (haz click para copiar)" }, "copyToClipboard": { "message": "Copiar al portapapeles" @@ -165,17 +165,17 @@ "message": "Crear" }, "createAccount": { - "message": "Crear Cuenta" + "message": "Crear cuenta" }, "createDen": { "message": "Crear" }, "crypto": { "message": "Crypto", - "description": "Tipo de Cambio (criptomonedas)" + "description": "Tipo de cambio (criptomonedas)" }, "currentConversion": { - "message": "Conversión Actual" + "message": "Conversión actual" }, "currentNetwork": { "message": "Red actual" @@ -184,10 +184,10 @@ "message": "RPC actual" }, "customGas": { - "message": "Personalizar Gas" + "message": "Personalizar gas" }, "customRPC": { - "message": "RPC Personalizado" + "message": "RPC personalizado" }, "customize": { "message": "Personalizar" @@ -202,7 +202,7 @@ "message": "La red por defecto para las transacciones de Ether es MainNet (red principal)" }, "denExplainer": { - "message": "Tu DEN es tu contraseña encriptada guardada dentro de MetaMask" + "message": "El DEN es tu contraseña encriptada almacenada dentro de MetaMask" }, "deposit": { "message": "Depositar" @@ -221,7 +221,7 @@ "message": "Depositar Ether" }, "depositFiat": { - "message": "Depositar con Fiat (divisa nacional)" + "message": "Depositar con fiat (divisa nacional)" }, "depositFromAccount": { "message": "Depositar con otra cuenta" @@ -230,7 +230,7 @@ "message": "Depositar con ShapeShift" }, "depositShapeShiftExplainer": { - "message": "Si tu tienes otras criptomonedas, puedes intercambiar y depositar Ether directamente en tu billetera de MetaMask. No necesitas tener una cuenta" + "message": "Si posees otras criptomonedas, puedes intercambiar y depositar Ether directamente en tu billetera de MetaMask. No necesitas tener una cuenta." }, "details": { "message": "Detalles" @@ -242,7 +242,7 @@ "message": "Depositar Ether directamente" }, "directDepositEtherExplainer": { - "message": "Si tu tienes algo de Ether, la forma rápida para tener Ether en tu nueva billetera es depositando directamente" + "message": "Si posees Ether, la forma más rápida de transferirlo a tu nueva billetera es depositándolo directamente" }, "done": { "message": "Completo" @@ -260,7 +260,7 @@ "message": "Editar el nombre de la cuenta" }, "emailUs": { - "message": "Envíanos un correo!" + "message": "¡Envíanos un correo!" }, "encryptNewDen": { "message": "Encriptar tu nuevo DEN" @@ -291,7 +291,7 @@ "description": "Tipo de cambio" }, "fileImportFail": { - "message": "No funciona importar el archivo? Haz Click Aquí!", + "message": "¿La importación no funcionó? ¡Haz click aquí!", "description": "Ayuda al usuario a importar su cuenta desde un archivo JSON" }, "followTwitter": { @@ -320,7 +320,7 @@ "message": "Calculamos el límite de gas sugerido en función de las tasas de éxito de la red" }, "gasLimitRequired": { - "message": "Límite de Gas requerido" + "message": "Límite de gas requerido" }, "gasLimitTooLow": { "message": "El límite de gas debe ser de al menos 21000" @@ -353,22 +353,22 @@ "description": "como en -haz click aquí- para más información" }, "hereList": { - "message": "Aquí está una lista!!!" + "message": "¡¡¡Aquí está una lista!!!" }, "hide": { "message": "Ocultar" }, "hideToken": { - "message": "Ocultar Token" + "message": "Ocultar token" }, "hideTokenPrompt": { - "message": "Ocultar Token?" + "message": "¿Ocultar token?" }, "holdEther": { "message": "Te permite mantener tus ether y tokens, así como puente para aplicaciones descentralizadas" }, "howToDeposit": { - "message": "Cómo te gustaria depositar Ether?" + "message": "¿Cómo te gustaria depositar Ether?" }, "import": { "message": "Importar", @@ -388,13 +388,13 @@ "description": "Estado que muestra que una cuenta ha sido completamente cargada en el llavero" }, "importAccountMsg": { - "message": "Cuentas importadas no serán asociadas con tu cuenta original creada con tu MetaMask. Aprende más acerca de importar cuentas." + "message": "Las cuentas importadas no serán asociadas con tu cuenta original creada con tu MetaMask. Aprende más acerca de importar cuentas." }, "info": { "message": "Información" }, "infoHelp": { - "message": "Informacion y Ayuda" + "message": "Informacion y ayuda" }, "insufficientFunds": { "message": "Fondos insuficientes" @@ -421,7 +421,7 @@ "message": "Petición inválida" }, "jsonFail": { - "message": "Algo malo pasó. Asegurate que tu JSON tiene el formato correcto" + "message": "Algo falló. Asegúrate que tu JSON tiene el formato correcto" }, "jsonFile": { "message": "Archivo JSON", @@ -477,7 +477,7 @@ "message": "Mensaje" }, "metamaskDescription": { - "message": "Metamask es una identidad segura en Ethereum" + "message": "MetaMask es una identidad segura en Ethereum" }, "min": { "message": "Mínimo" @@ -489,7 +489,7 @@ "message": "Mis cuentas" }, "needEtherInWallet": { - "message": "Para interactuar con una aplicación descentralizada usando MetaMask, vas a necesitar tener Ether en tu billetera" + "message": "Para interactuar con una aplicación descentralizada usando MetaMask, necesitas tener Ether en tu billetera" }, "needImportFile": { "message": "Debes seleccionar un archivo para importar", @@ -565,17 +565,17 @@ "message": "Asegurate que tu contraseña es correcta" }, "passwordMismatch": { - "message": "Contraseña no coincide", + "message": "La contraseña no coincide", "description": "En el proceso de creación de contraseña, los dos campos de contraseña no coincidieron" }, "passwordNotLongEnough": { "message": "La contraseña no es lo suficientemente larga" }, "passwordsDontMatch": { - "message": "Contraseñas no coinciden" + "message": "Las contraseñas no coinciden" }, "passwordShort": { - "message": "Contraseña no es lo suficientemente larga", + "message": "La contraseña no es lo suficientemente larga", "description": "En el proceso de creación de contraseña, esta no es lo suficientemente larga para ser segura" }, "pastePrivateKey": { @@ -583,13 +583,13 @@ "description": "Para importar una cuenta desde una llave privada" }, "pasteSeed": { - "message": "Pega tu frase semilla aquí!" + "message": "¡Pega tu frase semilla aquí!" }, "personalAddressDetected": { "message": "Dirección personal detectada. Ingresa la dirección del contrato del token" }, "pleaseReviewTransaction": { - "message": "Por favor revisa tu transaccion" + "message": "Por favor, revisa tu transaccion" }, "privacyMsg": { "message": "Política de privacidad" @@ -602,7 +602,7 @@ "message": "Advertencia: NUNCA reveles esta clave. Cualquier persona con tus claves privadas puede robar los activos retenidos en tu cuenta" }, "privateNetwork": { - "message": "Red Privada" + "message": "Red privada" }, "qrCode": { "message": "Mostrar codigo QR" @@ -614,7 +614,7 @@ "message": "Leer más" }, "readdToken": { - "message": "Puede volver a agregar este token en el futuro yendo a 'Agregar token' en el menú de opciones de tu cuenta" + "message": "Puedes volver a agregar este token en el futuro pinchando sobre 'Agregar token' en el menú de opciones de tu cuenta" }, "receive": { "message": "Recibir" @@ -641,13 +641,13 @@ "message": "Restaurar Bóveda" }, "retryWithMoreGas": { - "message": "Vuelva a intentar con un precio de Gas más alto aquí" + "message": "Vuelva a intentar con un precio de gas más alto aquí" }, "revealSeedWords": { "message": "Revelar palabras de semilla" }, "revealSeedWordsWarning": { - "message": "No recuperes tu semilla en un lugar publico! Esas palabras pueden ser usadas para robarte todas tus cuentas" + "message": "¡No recuperes tu semilla en un lugar pública! Esas palabras pueden ser usadas para robarte todas tus cuentas" }, "revert": { "message": "Revertir" @@ -659,7 +659,7 @@ "message": "Red privada Ropsten" }, "sampleAccountName": { - "message": "Ej. Mi nueva cuenta", + "message": "P.ej. Mi nueva cuenta", "description": "Ayuda al usuario a entender el concepto de agregar un nombre, leíble por humanos, a su cuenta" }, "save": { @@ -700,10 +700,10 @@ "message": "Enviar Ether" }, "sendTokens": { - "message": "Enviar Tokens" + "message": "Enviar tokens" }, "sendTokensAnywhere": { - "message": "Enviar Tokens a cualquiera con una cuenta de Ethereum" + "message": "Enviar tokens a cualquiera con una cuenta de Ethereum" }, "settings": { "message": "Configuración" @@ -730,10 +730,10 @@ "message": "Firmado" }, "signMessage": { - "message": "Firmar Mensaje" + "message": "Firmar mensaje" }, "signNotice": { - "message": "Firmar este mensaje puede tener\n efectos secundarios peligrosos. Firma sólo\nmensajes desde sitios a los cuales tú estés dispuesto a confiar completamente tu cuenta.\nEste método peligroso va a ser \nremovido en una version futura." + "message": "Firmar este mensaje puede tener\n efectos secundarios peligrosos. Firma sólo\nmensajes desde sitios a los que estés plenamente dispuesto a confiar tu cuenta.\nEste método peligroso va a ser \neliminado en una version futura." }, "spaceBetween": { "message": "Sólo puede haber un espacio entre las palabras" @@ -742,7 +742,7 @@ "message": "Logs de estado" }, "stateLogsDescription": { - "message": "Los Logs de estado contienen tus direcciones de cuentas públicas y transacciones envíadas" + "message": "Los logs de estado contienen tus direcciones de cuentas públicas y transacciones envíadas" }, "stateLogError": { "message": "Error en la recogida de logs de estado" @@ -763,10 +763,10 @@ "message": "Símbolo debe ser entre 0 y 10 caracteres" }, "takesTooLong": { - "message": "¿Está tomando demasiado?" + "message": "¿Está tardando demasiado?" }, "terms": { - "message": "Terminos de Uso" + "message": "Términos de uso" }, "testFaucet": { "message": "Probar Faucet" @@ -782,7 +782,7 @@ "message": "Dirección del token" }, "tokenAlreadyAdded": { - "message": "El token esta actualmente agregado" + "message": "El token está actualmente agregado" }, "tokenBalance": { "message": "Tu balance de tokens es:" @@ -794,13 +794,13 @@ "message": "Símbolo del token" }, "tokenWarning1": { - "message": "Manten un registro de los tokens que has comprado con tu cuenta de MetaMask. Si compraste tokens usando una cuenta diferente, esos tokens no aparecerán aquí." + "message": "Mantén un registro de los tokens que has comprado con tu cuenta de MetaMask. Si compraste tokens usando una cuenta diferente, esos tokens no aparecerán aquí." }, "total": { "message": "Total" }, "transactionMemo": { - "message": "Memo de transaccion (opcional)" + "message": "Memo de transacción (opcional)" }, "transactionNumber": { "message": "Número de transacción" @@ -816,7 +816,7 @@ "description": "Seguidos por un enlace (aquí) para ver los saldos de token" }, "twelveWords": { - "message": "Estas 12 palabras son la única forma de restablecer tus cuentas de MetaMask. \nGuardalas en un lugar seguro y secreto." + "message": "Estas 12 palabras son la única forma de restablecer tus cuentas de MetaMask. \nGuárdalas en un lugar seguro y secreto." }, "typePassword": { "message": "Escribe tu contraseña" @@ -825,13 +825,13 @@ "message": "Bienvenido a la nueva UI (Beta)" }, "uiWelcomeMessage": { - "message": "Estás usando la nueva UI de MetaMask. Echa un vistazo alrededor, prueba las nuevas características, tales como mandar tokens, y déjanos saber si tienes algún problema" + "message": "Estás usando la nueva UI de MetaMask. Echa un vistazo alrededor, prueba las nuevas características, tales como mandar tokens, y háznos saber si tienes algún problema" }, "unavailable": { "message": "No disponible" }, "unapproved": { - "message": "No Aprobado" + "message": "No aprobado" }, "unknown": { "message": "Desconocido (a)" @@ -840,14 +840,14 @@ "message": "Red privada desconocida" }, "unknownNetworkId": { - "message": "ID (identidad) de Red desconocida" + "message": "ID (identidad) de red desconocida" }, "uriErrorMsg": { - "message": "URI necesita el prefijo HTTP/HTTPS apropiado" + "message": "URI necesita el prefijo HTTP/HTTPS apropiado" }, "usaOnly": { "message": "Sólo USA (Estados Unidos)", - "description": "El uso de este exchange (casa de cambio) está limitado a las personas dentro de los Estados Unidos de America" + "description": "El uso de este exchange (casa de cambio) está limitado a las personas dentro de los Estados Unidos de América" }, "useOldUI": { "message": "Usar UI antigua" @@ -877,7 +877,7 @@ "message": "Bienvenido a Metamask Beta" }, "whatsThis": { - "message": "Qué es esto?" + "message": "¿Qué es esto?" }, "youSign": { "message": "Usted está firmando" diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index bab8d3b95..d9762a3e9 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -14,6 +14,9 @@ "address": { "message": "アドレス" }, + "addCustomToken": { + "message": "カスタムトークンを追加" + }, "addToken": { "message": "トークンを追加" }, @@ -63,11 +66,14 @@ "message": "Coinbaseで購入" }, "buyCoinbaseExplainer": { - "message": "Coinbaseは、世界で最もポピュラーなBitcoin、Ethereum、そしてLitecoinの取引所です。" + "message": "Coinbaseは、世界的なBitcoin、Ethereum、そしてLitecoinの取引所です。" }, "cancel": { "message": "キャンセル" }, + "classicInterface": { + "message": "旧インタフェイスを使用" + }, "clickCopy": { "message": "クリックしてコピー" }, @@ -126,6 +132,9 @@ "message": "暗号通貨", "description": "Exchange type (cryptocurrencies)" }, + "currentConversion": { + "message": "基軸通貨" + }, "customGas": { "message": "ガスのカスタマイズ" }, @@ -135,14 +144,17 @@ "customRPC": { "message": "カスタムRPC" }, + "decimal": { + "message": "小数点桁数" + }, "defaultNetwork": { - "message": "Etherトランザクションのデフォルトのネットワークはメインネットです。" + "message": "デフォルトのEther送受信ネットワークはメインネットです。" }, "denExplainer": { "message": "DENとは、あなたのパスワードが暗号化されたMetaMask内のストレージです。" }, "deposit": { - "message": "デポジット" + "message": "受取り" }, "depositBTC": { "message": "あなたのBTCを次のアドレスへデポジット:" @@ -161,13 +173,13 @@ "message": "法定通貨でデポジット" }, "depositFromAccount": { - "message": "別のアカウントからデポジット" + "message": "別のアカウントから入金" }, "depositShapeShift": { - "message": "ShapeShiftでデポジット" + "message": "ShapeShiftで入金" }, "depositShapeShiftExplainer": { - "message": "あなたが他の暗号通貨を持っているなら、Etherにトレードしてダイレクトにメタマスクウォレットへのデポジットが可能です。アカウント作成は不要。" + "message": "他の暗号通貨をEtherと交換してMetaMaskのウォレットへ入金できます。アカウント作成は不要です。" }, "details": { "message": "詳細" @@ -176,10 +188,10 @@ "message": "ダイレクトデポジット" }, "directDepositEther": { - "message": "Etherをダイレクトデポジット" + "message": "Etherを直接受け取り" }, "directDepositEtherExplainer": { - "message": "あなたがEtherをすでにお持ちなら、ダイレクトデポジットは新しいウォレットにEtherを入手する最も迅速な方法です。" + "message": "Etherをすでにお持ちなら、MetaMaskの新しいウォレットにEtherを送信することができます。" }, "done": { "message": "完了" @@ -197,7 +209,7 @@ "message": "パスワードを入力" }, "etherscanView": { - "message": "Etherscanでアカウントを見る" + "message": "Etherscanでアカウントを参照" }, "exchangeRate": { "message": "交換レート" @@ -257,7 +269,7 @@ "message": "Etherをゲット" }, "getEtherFromFaucet": { - "message": "フォーセットで $1のEtherをゲット", + "message": "フォーセットで $1のEtherを得ることができます。", "description": "Displays network name for Ether faucet" }, "greaterThanMin": { @@ -281,12 +293,15 @@ "message": "どのようにEtherをデポジットしますか?" }, "import": { - "message": "インポート", + "message": "追加", "description": "Button to import an account from a selected file" }, "importAccount": { "message": "アカウントのインポート" }, + "importAccountMsg": { + "message":"追加したアカウントはMetaMaskのアカウントシードフレーズとは関連付けられません。インポートしたアカウントについての詳細は" + }, "importAnAccount": { "message": "アカウントをインポート" }, @@ -298,7 +313,10 @@ "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { - "message": "インフォメーションとヘルプ" + "message": "情報とヘルプ" + }, + "insufficientFunds": { + "message": "残高不足" }, "invalidAddress": { "message": "アドレスが無効です。" @@ -354,7 +372,7 @@ "message": "マイアカウント" }, "needEtherInWallet": { - "message": "MetaMaskを使って分散型アプリケーションと対話するためには、あなたのウォレットにEtherが必要になります。" + "message": "MetaMaskを使って分散型アプリケーションを使用するためには、このウォレットにEtherが必要です。" }, "needImportFile": { "message": "インポートするファイルを選択してください。", @@ -383,6 +401,9 @@ "newRecipient": { "message": "新規受取人" }, + "newRPC": { + "message": "新しいRPCのURLを追加" + }, "next": { "message": "次へ" }, @@ -460,12 +481,21 @@ "rejected": { "message": "拒否されました" }, + "resetAccount": { + "message": "アカウントをリセット" + }, + "restoreFromSeed": { + "message": "パスフレーズから復元する" + }, "required": { "message": "必要です。" }, "retryWithMoreGas": { "message": "より高いガスプライスで再度試して下さい。" }, + "revealSeedWords": { + "message": "パスフレーズを表示" + }, "revert": { "message": "元に戻す" }, @@ -495,8 +525,11 @@ "sendTokens": { "message": "トークンを送る" }, + "onlySendToEtherAddress": { + "message": "ETHはイーサリウムアカウントのみに送信できます。" + }, "sendTokensAnywhere": { - "message": "イーサリアムのアカウントを持っている人にトークンを送る" + "message": "イーサリアムアカウントを持っている人にトークンを送る" }, "settings": { "message": "設定" @@ -544,9 +577,21 @@ "message": "ShapeShiftで $1をETHにする", "description": "system will fill in deposit type in start of message" }, + "tokenAddress": { + "message": "トークンアドレス" + }, "tokenBalance": { "message": "あなたのトークン残高:" }, + "tokenSelection": { + "message": "トークンを検索、またはリストから選択してください。" + }, + "tokenSymbol": { + "message": "トークンシンボル" + }, + "tokenWarning1": { + "message": "MetaMaskのアカウントで取得したアカウントのみ追加できます。他のアカウントを使用して取得したトークンは、カスタムトークンを使用してください。" + }, "total": { "message": "合計" }, @@ -591,6 +636,9 @@ "usedByClients": { "message": "様々なクライアントによって使用されています。" }, + "useOldUI": { + "message": "旧UIに切り替え" + }, "viewAccount": { "message": "アカウントを見る" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json new file mode 100644 index 000000000..0532f11b2 --- /dev/null +++ b/app/_locales/sl/messages.json @@ -0,0 +1,819 @@ +{ + "accept": { + "message": "Sprejmi" + }, + "account": { + "message": "Račun" + }, + "accountDetails": { + "message": "Podrobnosti računa" + }, + "accountName": { + "message": "Ime računa" + }, + "address": { + "message": "Naslov" + }, + "addCustomToken": { + "message": "Dodaj žeton po meri" + }, + "addToken": { + "message": "Dodaj žeton" + }, + "addTokens": { + "message": "Dodaj žetone" + }, + "amount": { + "message": "Znesek" + }, + "amountPlusGas": { + "message": "Znesek + Gas" + }, + "appDescription": { + "message": "Denarnica za Ethereum v brskalniku", + "description": "The description of the application" + }, + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "attemptingConnect": { + "message": "Povezovanje z verigo blokov ..." + }, + "attributions": { + "message": "Dodelitve" + }, + "available": { + "message": "Na voljo" + }, + "back": { + "message": "Nazaj" + }, + "balance": { + "message": "Znesek:" + }, + "balances": { + "message": "Vaš znesek" + }, + "balanceIsInsufficientGas": { + "message": "Napačen znesek za skupno gas vrednost" + }, + "beta": { + "message": "BETA" + }, + "betweenMinAndMax": { + "message": "mora biti večji ali enak $1 in manjši ali enak $1.", + "description": "helper for inputting hex as decimal input" + }, + "blockiesIdenticon": { + "message": "Uporabite Blockies Identicon" + }, + "borrowDharma": { + "message": "Izposoja z Dharma (Beta)" + }, + "builtInCalifornia": { + "message": "MetaMask je ustvarjen v Kaliforniji." + }, + "buy": { + "message": "Kupi" + }, + "buyCoinbase": { + "message": "Kupi na Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase je najpopularnejši načun za kupovanje in prodajo bitcoinov, ethereuma, in litecoina." + }, + "cancel": { + "message": "Prekliči" + }, + "classicInterface": { + "message": "Uporabi navaden način" + }, + "clickCopy": { + "message": "Kliknite za kopiranje" + }, + "confirm": { + "message": "Potrdi" + }, + "confirmContract": { + "message": "Potrdi pogodbo" + }, + "confirmPassword": { + "message": "Potrdi geslo" + }, + "confirmTransaction": { + "message": "Potrdi transakcijo" + }, + "continue": { + "message": "Nadaljuj" + }, + "continueToCoinbase": { + "message": "Nadaljuj na Coinbase" + }, + "contractDeployment": { + "message": "Ustvarjanje pogodbe" + }, + "conversionProgress": { + "message": "Poteka pretvorba" + }, + "copiedButton": { + "message": "Kopirano" + }, + "copiedClipboard": { + "message": "Kopirano v odložišče" + }, + "copiedExclamation": { + "message": "Kopirano!" + }, + "copiedSafe": { + "message": "Prilepil sem ga na varno!" + }, + "copy": { + "message": "Kopiraj" + }, + "copyToClipboard": { + "message": "Kopiraj v odložišče" + }, + "copyButton": { + "message": " Kopiraj " + }, + "copyPrivateKey": { + "message": "To je vaš zesebni ključ (kliknite za kopiranje)" + }, + "create": { + "message": "Ustvari" + }, + "createAccount": { + "message": "Ustvari račun" + }, + "createDen": { + "message": "Ustvari" + }, + "crypto": { + "message": "Kripto", + "description": "Exchange type (cryptocurrencies)" + }, + "currentConversion": { + "message": "Trenutna cena" + }, + "currentNetwork": { + "message": "Trenutno omrežje" + }, + "customGas": { + "message": "Prilagodi gas" + }, + "customize": { + "message": "Prilagodi" + }, + "customRPC": { + "message": "Poljuben RPC" + }, + "decimalsMustZerotoTen": { + "message": "Decimalk mora biti vsaj 0, in ne več kot 36." + }, + "decimal": { + "message": "Decimalke natančnosti" + }, + "defaultNetwork": { + "message": "Privzeto omrežje za transakcije je Main Net." + }, + "denExplainer": { + "message": "DEN je vaša šifrirana shramba v MetaMasku." + }, + "deposit": { + "message": "Vplačilo" + }, + "depositBTC": { + "message": "Vplačajte vaš BTC na spodnji naslov:" + }, + "depositCoin": { + "message": "Vplačajte $1 na spodnji naslov", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "Vplačilo ETH" + }, + "depositEther": { + "message": "Vplačilo ethera" + }, + "depositFiat": { + "message": "Vplačilo s klasičnimi valutami" + }, + "depositFromAccount": { + "message": "Vplačilo iz drugega računa" + }, + "depositShapeShift": { + "message": "Vplačilo z ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "Če imate druge kriptovalute, lahko vpačate ether neposredno v MetaMask. Brez računov." + }, + "details": { + "message": "Podrobnosti" + }, + "directDeposit": { + "message": "Direktno vplačilo" + }, + "directDepositEther": { + "message": "Direktno vplačilo ehera" + }, + "directDepositEtherExplainer": { + "message": "Če že imate ether, ga lahko najhitreje dobite v MetaMask z direktnim vplačilom." + }, + "done": { + "message": "Končano" + }, + "downloadStatelogs": { + "message": "Prenesi state dnevnike" + }, + "edit": { + "message": "Uredi" + }, + "editAccountName": { + "message": "Uredi ime računa" + }, + "emailUs": { + "message": "Pišite nam!" + }, + "encryptNewDen": { + "message": "Šifrirajte DEN" + }, + "enterPassword": { + "message": "Vpišite geslo" + }, + "enterPasswordConfirm": { + "message": "Potrdite geslo" + }, + "etherscanView": { + "message": "Poglejte račun na Etherscan" + }, + "exchangeRate": { + "message": "Menjalni tečaj" + }, + "exportPrivateKey": { + "message": "Izvozi zasebni ključ" + }, + "exportPrivateKeyWarning": { + "message": "Izvažanje zasebnih ključev je na lastno odgovornost." + }, + "failed": { + "message": "Ni uspelo" + }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "Uvoz z datoteko ni uspel? Kliknite tukaj!", + "description": "Helps user import their account from a JSON file" + }, + "followTwitter": { + "message": "Sledite nam na Twitterju" + }, + "from": { + "message": "Od" + }, + "fromToSame": { + "message": "From and To address cannot be the same" + }, + "fromShapeShift": { + "message": "Od ShapeShift" + }, + "gas": { + "message": "Gas", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "Gas fee" + }, + "gasLimit": { + "message": "Gas limit" + }, + "gasLimitCalculation": { + "message": "Priporočen gas limit je izračunan glede na omrežje." + }, + "gasLimitRequired": { + "message": "Gas limit je zahtevan" + }, + "gasLimitTooLow": { + "message": "Gas limit mora biti najmanj 21000" + }, + "generatingSeed": { + "message": "Ustvarjenje seed ..." + }, + "gasPrice": { + "message": "Gas price (GWEI)" + }, + "gasPriceCalculation": { + "message": "Priporočen gas price je izračunan glede na omrežje" + }, + "gasPriceRequired": { + "message": "Gas price je zahtevan" + }, + "getEther": { + "message": "Pridobite ether" + }, + "getEtherFromFaucet": { + "message": "Pridobite ether iz fauceta za $1", + "description": "Displays network name for Ether faucet" + }, + "greaterThanMin": { + "message": "mora biti višji ali enak $1.", + "description": "helper for inputting hex as decimal input" + }, + "here": { + "message": "tukaj", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hereList": { + "message": "Tukaj je seznam!!!" + }, + "hide": { + "message": "Skrij" + }, + "hideToken": { + "message": "Skrij žeton" + }, + "hideTokenPrompt": { + "message": "Skrijem žeton?" + }, + "howToDeposit": { + "message": "Kako želite vplačati ether?" + }, + "holdEther": { + "message": "Omogoča vam, da imate eter in žetone in služi kot most za decentralizirane aplikacije." + }, + "import": { + "message": "Uvozi", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "Uvozi račun" + }, + "importAccountMsg": { + "message":" Uvoženi računi ne bodo povezani s prvotnim seedphaseom. Preberite več o uvoženih računih " + }, + "importAnAccount": { + "message": "Uvozi račun" + }, + "importDen": { + "message": "Uvozi DEN" + }, + "imported": { + "message": "Uvoženo", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "infoHelp": { + "message": "Info & Pomoč" + }, + "insufficientFunds": { + "message": "Nezadostna sredstva." + }, + "insufficientTokens": { + "message": "Nezadostni žetoni." + }, + "invalidAddress": { + "message": "Nepravilen naslov" + }, + "invalidAddressRecipient": { + "message": "Prejemnikov naslov je neveljaven" + }, + "invalidGasParams": { + "message": "Nepravilno nastavljen gas" + }, + "invalidInput": { + "message": "Napačen vnos." + }, + "invalidRequest": { + "message": "Napačna zahteva" + }, + "invalidRPC": { + "message": "Napačen RPC URI" + }, + "jsonFail": { + "message": "Nekaj je bilo narobe. Prepričajte se, da je JSON datoteka pravilno oblikovana." + }, + "jsonFile": { + "message": "JSON datoteka", + "description": "format for importing an account" + }, + "kovan": { + "message": "Testno omrežje Kovan" + }, + "knowledgeDataBase": { + "message": "Obiščite našo pomoč" + }, + "lessThanMax": { + "message": "mora biti večji ali enak $1.", + "description": "helper for inputting hex as decimal input" + }, + "likeToAddTokens": { + "message": "Želite dodati te žetone?" + }, + "limit": { + "message": "Omejitev" + }, + "loading": { + "message": "Nalaganje ..." + }, + "loadingTokens": { + "message": "Nalaganje žetonov ..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "login": { + "message": "Prijava" + }, + "logout": { + "message": "Odjava" + }, + "loose": { + "message": "Loose" + }, + "loweCaseWords": { + "message": "seed words imajo lahko le male črke" + }, + "mainnet": { + "message": "Glavno omrežje" + }, + "message": { + "message": "Sporočilo" + }, + "metamaskDescription": { + "message": "MetaMask je varen identitetni sklad za Ethereum." + }, + "min": { + "message": "Najmanj" + }, + "myAccounts": { + "message": "Moji računi" + }, + "mustSelectOne": { + "message": "Izbran mora biti vsaj 1 žeton." + }, + "needEtherInWallet": { + "message": "Za interakcijo z decentraliziranimi aplikacijami, ki uporabljajo MetaMask, boste v svoji denarnici potrebovali eter." + }, + "needImportFile": { + "message": "Za uvoz morate izbrati datoteko.", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "Za izbrano datoteko morate vnesti geslo.", + "description": "Password and file needed to import an account" + }, + "negativeETH": { + "message": "Ni mogoče poslati negativne vsote ETH." + }, + "networks": { + "message": "Omrežja" + }, + "newAccount": { + "message": "Nov račun" + }, + "newAccountNumberName": { + "message": "Račun $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "Nova pogodba" + }, + "newPassword": { + "message": "Novo geslo (min. 8. črk)" + }, + "newRecipient": { + "message": "Nov prejemnik" + }, + "newRPC": { + "message": "Nov RPC URL" + }, + "next": { + "message": "Naprej" + }, + "noAddressForName": { + "message": "Za to ime ni bil nastavljen noben naslov." + }, + "noDeposits": { + "message": "Ni prejetih vplačil" + }, + "noTransactionHistory": { + "message": "Ni zgodovine transakcij." + }, + "noTransactions": { + "message": "Ni transakcij" + }, + "notStarted": { + "message": "Ni se začelo" + }, + "oldUI": { + "message": "Starejši uporabniški vmesnik" + }, + "oldUIMessage": { + "message": "Vrnili ste se v starejši uporabniški vmesnik. V novega se lahko vrnete z možnostjo v spustnem meniju v zgornjem desnem kotu." + }, + "or": { + "message": "ali", + "description": "choice between creating or importing a new account" + }, + "passwordCorrect": { + "message": "Prepričajte se, da je geslo pravilno." + }, + "passwordMismatch": { + "message": "gesli se ne ujemata", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordShort": { + "message": "geslo ni dovolj dolgo", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "Tukaj prilepite zasebni ključ:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "Tukaj prilepite seed phrase!" + }, + "personalAddressDetected": { + "message": "Osebni naslov je zaznan. Vnesite naslov žetona." + }, + "pleaseReviewTransaction": { + "message": "Preglejte transakcijo." + }, + "privacyMsg": { + "message": "Politika zasebnosti" + }, + "privateKey": { + "message": "Zasebni ključ", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "Opozorilo: Nikoli ne razkrijte tega ključa. Vsakdo s svojimi zasebnimi ključi lahko ukrade vse premoženje v računu." + }, + "privateNetwork": { + "message": "Zasebno omrežje" + }, + "qrCode": { + "message": "Prikaži QR kodo" + }, + "readdToken": { + "message": "Ta žeton lahko dodate tudi v prihodnosti, tako da odprete možnost »Dodaj žeton« v meniju z računi." + }, + "readMore": { + "message": "Preberite več." + }, + "readMore2": { + "message": "Preberite več." + }, + "receive": { + "message": "Prejmite" + }, + "recipientAddress": { + "message": "Prejemnikov naslov" + }, + "refundAddress": { + "message": "Vaš naslov za vračilo" + }, + "rejected": { + "message": "Zavrnjeno" + }, + "resetAccount": { + "message": "Ponastavi račun" + }, + "restoreFromSeed": { + "message": "Obnovi iz seed phrase" + }, + "required": { + "message": "Zahtevano" + }, + "retryWithMoreGas": { + "message": "Poskusi z višjim gas price" + }, + "revealSeedWords": { + "message": "Prikaži seed words" + }, + "revealSeedWordsWarning": { + "message": "Ne obnovite seed words na javnem mestu! Te besede se lahko uporabijo za krajo vseh vaših računov." + }, + "revert": { + "message": "Povrni" + }, + "rinkeby": { + "message": "Testno omrežje Rinkeby" + }, + "ropsten": { + "message": "Testno omrežje Ropsten" + }, + "sampleAccountName": { + "message": "npr. Moj nov račun", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "Shrani" + }, + "saveAsFile": { + "message": "Shrani kot datoteko", + "description": "Account export process" + }, + "saveSeedAsFile": { + "message": "Shrani seed words kot datoteko" + }, + "search": { + "message": "Iskanje" + }, + "secretPhrase": { + "message": "Tukaj vnesite svoje seed words, da obnovite svoje račune." + }, + "seedPhraseReq": { + "message": "seed phrases so dolgi 12 besed" + }, + "select": { + "message": "Izberi" + }, + "selectCurrency": { + "message": "Izberi valuto" + }, + "selectService": { + "message": "Izberi storitev" + }, + "selectType": { + "message": "Izberi vrsto" + }, + "send": { + "message": "Pošlji" + }, + "sendETH": { + "message": "Pošlji ETH" + }, + "sendTokens": { + "message": "Pošlji žetone" + }, + "sendTokensAnywhere": { + "message": "Pošljite žetone vsem, ki imajo Ethereum račun" + }, + "settings": { + "message": "Nastavitve" + }, + "shapeshiftBuy": { + "message": "Kupite z Shapeshift" + }, + "showPrivateKeys": { + "message": "Prikaži zasebne ključe" + }, + "showQRCode": { + "message": "Prikaži QR kodo" + }, + "sign": { + "message": "Podpiši" + }, + "signMessage": { + "message": "Podpiši sporočilo" + }, + "signNotice": { + "message": "To podpisovanje lahko povzroči \nnevarne stranske učinke. Podpisujte samo sporočila \nstrani, ki jim zaupate s svojim celotnim računom.\n Ta nevarna funkcija bo odstranjena v prihodnji različici. " + }, + "sigRequest": { + "message": "Zahteva za podpis" + }, + "sigRequested": { + "message": "Podpis je zahtevan" + }, + "spaceBetween": { + "message": "med besedami je lahko samo presledek" + }, + "status": { + "message": "Status" + }, + "stateLogs": { + "message": "State dnevniki" + }, + "stateLogsDescription": { + "message": "State dnevniki vsebujejo naslove vašega računa in poslane transakcije.." + }, + "submit": { + "message": "Potrdi" + }, + "supportCenter": { + "message": "Obiščite našo podporo" + }, + "symbolBetweenZeroTen": { + "message": "Simbol mora biti dolg od 0 do 10 znakov." + }, + "takesTooLong": { + "message": "Traja predolgo?" + }, + "terms": { + "message": "Pogoji uporabe" + }, + "testFaucet": { + "message": "Testni faucet" + }, + "to": { + "message": "Za" + }, + "toETHviaShapeShift": { + "message": "$1 v ETH prek ShapeShift", + "description": "system will fill in deposit type in start of message" + }, + "tokenAddress": { + "message": "Naslov žetona" + }, + "tokenAlreadyAdded": { + "message": "Žeton je že bil dodan." + }, + "tokenBalance": { + "message": "Vaš znesek žetona:" + }, + "tokenSelection": { + "message": "Poiščite žetone ali jih izberite z našega seznama priljubljenih žetonov." + }, + "tokenSymbol": { + "message": "Simbol žetona" + }, + "tokenWarning1": { + "message": "Spremljajte žetone, ki ste jih kupili s svojim MetaMask računom. Če ste kupili žetone z drugačnim računom, ti žetoni ne bodo prikazani tukaj." + }, + "total": { + "message": "Skupno" + }, + "transactions": { + "message": "transakcije" + }, + "transactionMemo": { + "message": "Opis transakcije (ni zahtevano)" + }, + "transactionNumber": { + "message": "Številka transakcije" + }, + "transfers": { + "message": "Prenosi" + }, + "troubleTokenBalances": { + "message": "Imeli smo težave pri nalaganju vaših žetonov. Ogledate si jih lahko ", + "description": "Followed by a link (here) to view token balances" + }, + "twelveWords": { + "message": "Edini način za obnovitev MetaMask računa, je teh 12 besed.\nShranite jih na varno in skrivno mesto." + }, + "typePassword": { + "message": "Vpišite vaše geslo" + }, + "uiWelcome": { + "message": "Dobrodošli v novem uporabniškem vmesniku (Beta)" + }, + "uiWelcomeMessage": { + "message": "Zdaj uporabljate novi MetaMask uporabniški vmesnik. Razglejte se, preizkusite nove funkcije, kot so pošiljanje žetonov, in nas obvestite, če imate kakšne težave." + }, + "unavailable": { + "message": "Ni na voljo" + }, + "unknown": { + "message": "Neznano" + }, + "unknownNetwork": { + "message": "Neznano zasebno omrežje" + }, + "unknownNetworkId": { + "message": "Neznan ID omrežja" + }, + "uriErrorMsg": { + "message": "URI-ji zahtevajo ustrezno HTTP/HTTPS predpono." + }, + "usaOnly": { + "message": "Samo za ZDA", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "Uporablja jih več različnih odjemalcev" + }, + "useOldUI": { + "message": "Uporabi star uporabniški vmesnik" + }, + "validFileImport": { + "message": "Za uvoz morate izbrati pravilno datoteko." + }, + "vaultCreated": { + "message": "Račun je ustvarjen" + }, + "viewAccount": { + "message": "Poglej račun" + }, + "visitWebSite": { + "message": "Obiščite našo spletno stran" + }, + "warning": { + "message": "Opozorilo" + }, + "welcomeBeta": { + "message": "Dobrodošli v MetaMask Beta" + }, + "whatsThis": { + "message": "Kaj je to?" + }, + "yourSigRequested": { + "message": "Vaš podpis je bil zahtevan" + }, + "youSign": { + "message": "Podpisani ste" + } +} diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json new file mode 100644 index 000000000..887714f3f --- /dev/null +++ b/app/_locales/th/messages.json @@ -0,0 +1,819 @@ +{ + "accept": { + "message": "ยอมรับ" + }, + "account": { + "message": "บัญชี" + }, + "accountDetails": { + "message": "รายละเอียดบัญชี" + }, + "accountName": { + "message": "ชื่อบัญชี" + }, + "address": { + "message": "แอดเดรส" + }, + "addCustomToken": { + "message": "เพิ่มโทเค็นด้วยตัวเอง" + }, + "addToken": { + "message": "เพิ่มโทเค็น" + }, + "addTokens": { + "message": "เพิ่มหลายโทเค็น" + }, + "amount": { + "message": "จำนวน" + }, + "amountPlusGas": { + "message": "จำนวน + แก๊ส" + }, + "appDescription": { + "message": "ส่วนขยายเบราว์เซอร์สำหรับอีเธอเรียม", + "description": "The description of the application" + }, + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "attemptingConnect": { + "message": "กำลังเชื่อมต่อกับบล็อกเชน" + }, + "attributions": { + "message": "อ้างถึง" + }, + "available": { + "message": "ว่าง" + }, + "back": { + "message": "กลับ" + }, + "balance": { + "message": "ยอดคงเหลือ:" + }, + "balances": { + "message": "ยอดคงเหลือของคุณ" + }, + "balanceIsInsufficientGas": { + "message": "ยอดคงเหลือไม่พอสำหรับจ่ายค่าแก๊สทั้งหมด" + }, + "beta": { + "message": "เบต้า" + }, + "betweenMinAndMax": { + "message": "ต้องมากกว่าหรือเท่ากับ $1 และน้อยกว่าหรือเท่ากับ $2", + "description": "helper for inputting hex as decimal input" + }, + "blockiesIdenticon": { + "message": "ใช้งาน Blockies Identicon" + }, + "borrowDharma": { + "message": "ยืมด้วย Dharma (เบต้า)" + }, + "builtInCalifornia": { + "message": "MetaMask ออกแบบและพัฒนาที่แคลิฟอร์เนีย" + }, + "buy": { + "message": "ซื้อ" + }, + "buyCoinbase": { + "message": "ซื้อด้วย Coinbase" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase เป็นแหล่งซื้อขายบิตคอยน์ไลท์คอยน์และอีเธอเรียมที่ได้รับความนิยมสูงสุดในโลก" + }, + "cancel": { + "message": "ยกเลิก" + }, + "classicInterface": { + "message": "ใช้หน้าตาแบบเก่า" + }, + "clickCopy": { + "message": "กดเพื่อคัดลอก" + }, + "confirm": { + "message": "ยืนยัน" + }, + "confirmContract": { + "message": "ยืนยันสัญญา" + }, + "confirmPassword": { + "message": "ยืนยันรหัสผ่าน" + }, + "confirmTransaction": { + "message": "ยืนยันการทำรายการธุรกรรม" + }, + "continue": { + "message": "ทำต่อไป" + }, + "continueToCoinbase": { + "message": "ไปที่ Coinbase" + }, + "contractDeployment": { + "message": "การติดตั้งสัญญา" + }, + "conversionProgress": { + "message": "กำลังดำเนินการแปลงหน่วย" + }, + "copiedButton": { + "message": "คัดลอกแล้ว" + }, + "copiedClipboard": { + "message": "คัดลอกไปที่คลิบบอร์ดแล้ว" + }, + "copiedExclamation": { + "message": "คัดลอกแล้ว!" + }, + "copiedSafe": { + "message": "ฉันได้คัดลอกเก็บไว้ในที่ปลอดภัยเรียบร้อยแล้ว" + }, + "copy": { + "message": "คัดลอก" + }, + "copyToClipboard": { + "message": "คัดลอกไปคลิปบอร์ด" + }, + "copyButton": { + "message": " คัดลอก " + }, + "copyPrivateKey": { + "message": "นี่คือคีย์ส่วนตัวของคุณ(กดเพื่อคัดลอก)" + }, + "create": { + "message": "สร้าง" + }, + "createAccount": { + "message": "สร้างบัญชี" + }, + "createDen": { + "message": "สร้าง" + }, + "crypto": { + "message": "คริปโต", + "description": "Exchange type (cryptocurrencies)" + }, + "currentConversion": { + "message": "อัตราแลกเปลี่ยนปัจจุบัน" + }, + "currentNetwork": { + "message": "เครือข่ายปัจจุบัน" + }, + "customGas": { + "message": "กำหนดค่าแก็สเอง" + }, + "customize": { + "message": "กำหนดค่าเอง" + }, + "customRPC": { + "message": "กำหนดค่า RPC เอง" + }, + "decimalsMustZerotoTen": { + "message": "จำนวนต้องมากกว่า 0 และไม่เกิน 36" + }, + "decimal": { + "message": "ตำแหน่งของทศนิยม" + }, + "defaultNetwork": { + "message": "ค่าเริ่มต้นของเครือข่ายสำหรับทำรายการธุรกรรมอีเธอร์คือ Main Net" + }, + "denExplainer": { + "message": "DEN ของคุณคือตัวเก็บข้อมูลที่เข้ารหัสไว้ด้วยรหัสผ่านของคุณภายใน MetaMask " + }, + "deposit": { + "message": "ฝาก" + }, + "depositBTC": { + "message": "ฝากบิตคอยน์ของคุณไปที่แอดเดรสด้านล่างนี้:" + }, + "depositCoin": { + "message": "ฝาก $1 ของคุณไปที่แอดเดรสด้านล่างนี้:", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "การฝากอีเธอร์" + }, + "depositEther": { + "message": "การฝากอีเธอร์" + }, + "depositFiat": { + "message": "ฝากด้วยเงินตรา" + }, + "depositFromAccount": { + "message": "ฝากจากบัญชีอื่น" + }, + "depositShapeShift": { + "message": "ฝากด้วย ShapeShift" + }, + "depositShapeShiftExplainer": { + "message": "ถ้ามีเงินสกุลอื่นอยู่ก็สามารถแลกเงินและฝากเป็นอีเธอร์ได้โดยตรงเข้ากระเป๋า MetaMask ได้เลยไม่ต้องสมัครบัญชี" + }, + "details": { + "message": "รายละเอียด" + }, + "directDeposit": { + "message": "ฝากตรง" + }, + "directDepositEther": { + "message": "ฝากอีเธอร์โดยตรง" + }, + "directDepositEtherExplainer": { + "message": "ถ้าคุณมีอีเธอร์อยู่แล้ววิธีการที่เร็วที่สุดในการเอาเงินเข้ากระเป๋าใหม่ก็คือการโอนตรงๆ" + }, + "done": { + "message": "เสร็จสิ้น" + }, + "downloadStatelogs": { + "message": "ดาวน์โหลดล็อกสถานะ" + }, + "edit": { + "message": "แก้ไข" + }, + "editAccountName": { + "message": "แก้ไขชื่อบัญชี" + }, + "emailUs": { + "message": "อีเมลหาเรา!" + }, + "encryptNewDen": { + "message": "เข้ารหัส DEN ของคุณ" + }, + "enterPassword": { + "message": "ใส่รหัสผ่าน" + }, + "enterPasswordConfirm": { + "message": "ใส่รหัสผ่านอีกครั้งเพื่อยืนยัน" + }, + "etherscanView": { + "message": "ดูบัญชีบน Etherscan" + }, + "exchangeRate": { + "message": "อัตราแลกเปลี่ยน" + }, + "exportPrivateKey": { + "message": "ส่งออกคีย์ส่วนตัว" + }, + "exportPrivateKeyWarning": { + "message": "ส่งออกคีย์ส่วนตัวโดยคุณรับความเสี่ยงเอง" + }, + "failed": { + "message": "ล้มเหลว" + }, + "fiat": { + "message": "เงินตรา", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "นำเข้าไฟล์ไม่สำเหร็จ กดที่นี่!", + "description": "Helps user import their account from a JSON file" + }, + "followTwitter": { + "message": "ติดตามเราบนทวิตเตอร์" + }, + "from": { + "message": "จาก" + }, + "fromToSame": { + "message": "แอดเดรสที่ส่งกับที่รับจะต้องไม่ไช่อันเดียวกัน" + }, + "fromShapeShift": { + "message": "จาก ShapeShift" + }, + "gas": { + "message": "แก็ส", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "ค่าแก๊ส" + }, + "gasLimit": { + "message": "วงเงินแก็ส" + }, + "gasLimitCalculation": { + "message": "เราแนะนำวงเงินแก็สตามความสำเร็จบนเครือข่าย" + }, + "gasLimitRequired": { + "message": "ต้องกำหนดวงเงินแก็ส" + }, + "gasLimitTooLow": { + "message": "วงเงินแก็สต้องอย่างน้อย 21000" + }, + "generatingSeed": { + "message": "กำลังสร้างชีด..." + }, + "gasPrice": { + "message": "ราคาแก๊ส (GWEI)" + }, + "gasPriceCalculation": { + "message": "เราแนะนำราคาแก็สตามความสำเร็จบนเครือข่าย" + }, + "gasPriceRequired": { + "message": "ต้องมีราคาแก๊ส" + }, + "getEther": { + "message": "รับอีเธอร์" + }, + "getEtherFromFaucet": { + "message": "รับอีเธอร์ที่ปล่อยจาก $1", + "description": "Displays network name for Ether faucet" + }, + "greaterThanMin": { + "message": "ต้องมากกว่าหรือเท่ากับ $1.", + "description": "helper for inputting hex as decimal input" + }, + "here": { + "message": "ที่นี่", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hereList": { + "message": "รายการอยู่ที่นี่!!!!" + }, + "hide": { + "message": "ซ่อน" + }, + "hideToken": { + "message": "ซ่อนโทเค็น" + }, + "hideTokenPrompt": { + "message": "ซ่อนโทเค็นหรือไม่?" + }, + "howToDeposit": { + "message": "คุณต้องการฝากอีเธอร์อย่างไร?" + }, + "holdEther": { + "message": "ช่วยคุณถืออีเทอร์และโทเค็นและทำหน้าที่เป็นสะพานเชื่อมต่อกับแอพพลิเคชันแบบกระจาย" + }, + "import": { + "message": "นำเข้า", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "นำเข้าบัญชี" + }, + "importAccountMsg": { + "message":"บัญชีที่นำเข้าจะไม่ถูกรวมกับบัญชีที่สร้างด้วยคำเเริ่มต้นบนเมต้ามาร์สในตอนแรก เรียนรู้เพิ่มเติมเกี่ยวกับบัญชีที่นำเข้า" + }, + "importAnAccount": { + "message": "นำเข้าบัญชี" + }, + "importDen": { + "message": "นำเข้า DEN ที่มีอยู่แล้ว" + }, + "imported": { + "message": "นำเข้าเรียบร้อย", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "infoHelp": { + "message": "ข้อมูลและความช่วยเหลือ" + }, + "insufficientFunds": { + "message": "เงินทุนไม่เพียงพอ" + }, + "insufficientTokens": { + "message": "โทเค็นไม่เพียงพอ" + }, + "invalidAddress": { + "message": "แอดแดรสไม่ถูกต้อง" + }, + "invalidAddressRecipient": { + "message": "แอดแดรสผู้รับไม่ถูกต้อง" + }, + "invalidGasParams": { + "message": "ตั้งค่าแก๊สไม่ถูกต้อง" + }, + "invalidInput": { + "message": "อินพุทไม่ถูกต้อง" + }, + "invalidRequest": { + "message": "คำร้องขอไม่ถูกต้อง" + }, + "invalidRPC": { + "message": "RPC URI ไม่ถูกต้อง" + }, + "jsonFail": { + "message": "เกิดบางอย่างผิดพลาด โปรดตรวจสอบว่าไฟล์ JSON ของคุณมีรูปแบบที่ถูกต้อง." + }, + "jsonFile": { + "message": "ไฟล์ JSON", + "description": "format for importing an account" + }, + "kovan": { + "message": "เครือข่ายทดสอบ Kovan" + }, + "knowledgeDataBase": { + "message": "ไปที่คลังความรู้ของเรา" + }, + "lessThanMax": { + "message": "ต้องน้อยกว่าหรือเท่ากับ $1.", + "description": "helper for inputting hex as decimal input" + }, + "likeToAddTokens": { + "message": "คุณต้องการเพิ่มโทเค็นเหล่านี้หรือไม่?" + }, + "limit": { + "message": "ข้อจำกัด" + }, + "loading": { + "message": "กำลังโหลด..." + }, + "loadingTokens": { + "message": "กำลังโหลดโทเค็น..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "login": { + "message": "เข้าสู่ระบบ" + }, + "logout": { + "message": "ออกจากระบบ" + }, + "loose": { + "message": "อิสระ" + }, + "loweCaseWords": { + "message": "กลุ่มคำชีดมีเพียงตัวพิมพ์เล็กเท่านั้น" + }, + "mainnet": { + "message": "เครือข่าย Main Net" + }, + "message": { + "message": "ข้อความ" + }, + "metamaskDescription": { + "message": "MetaMask คือที่เก็บตัวตนนิรภัยสำหรับอีเธอเรียม" + }, + "min": { + "message": "ขั้นต่ำ" + }, + "myAccounts": { + "message": "บัญชีของฉัน" + }, + "mustSelectOne": { + "message": "ต้องเลือกอย่างน้อย 1 โทเค็น" + }, + "needEtherInWallet": { + "message": "คุณจะต้องมีอีเธอร์ในกระเป๋าเงินของคุณในการใช้งานกับแอพพลิเคชันแบบกระจายด้วย MetaMask" + }, + "needImportFile": { + "message": "คุณต้องเลือกไฟล์ที่จะนำเข้า", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "คุณต้องป้อนรหัสผ่านสำหรับไฟล์ที่เลือก", + "description": "Password and file needed to import an account" + }, + "negativeETH": { + "message": "ไม่สามารถส่งอีเธอร์เป็นจำนวนติดลบได้" + }, + "networks": { + "message": "เครือข่าย" + }, + "newAccount": { + "message": "บัญชีใหม่" + }, + "newAccountNumberName": { + "message": "บัญชี $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "สร้างสัญญาใหม่" + }, + "newPassword": { + "message": "รหัสผ่านใหม่(ขั้นต่ำ 8 ตัวอักษร)" + }, + "newRecipient": { + "message": "ผู้รับใหม่" + }, + "newRPC": { + "message": "RPC URL ใหม่" + }, + "next": { + "message": "ถัดไป" + }, + "noAddressForName": { + "message": "ยังไม่มีแอดแดรสไหนตั้งในชื่อนี้" + }, + "noDeposits": { + "message": "ไม่มีเงินฝากเข้ามา" + }, + "noTransactionHistory": { + "message": "ไม่มีรายการธุรกรรมในอดีต" + }, + "noTransactions": { + "message": "ยังไม่มีรายการธุรกรรม" + }, + "notStarted": { + "message": "ยังไม่เริ่ม" + }, + "oldUI": { + "message": "หน้าตาแบบเก่า" + }, + "oldUIMessage": { + "message": "คุณได้เปลี่ยนเป็นหน้าตาแบบเก่าแล้ว คุณสามารถเปลี่ยนเป็นหน้าตาแบบใหม่ได้โดยไปที่ตัวเลือกตรงเมนูมุมขวาบน" + }, + "or": { + "message": "หรือ", + "description": "choice between creating or importing a new account" + }, + "passwordCorrect": { + "message": "โปรดตรวจสอบว่ารหัสผ่านของคุณถูกต้อง" + }, + "passwordMismatch": { + "message": "รหัสผ่านไม่ตรงกัน", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordShort": { + "message": "รหัสผ่านไม่ยาวพอ", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "วางคีย์ส่วนตัวของคุณที่นี่:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "วางคำชีดของคุณที่นี่!" + }, + "personalAddressDetected": { + "message": "ตรวจพบแอดแดรสส่วนตัวแล้ว ใส่แอดแดรสสัญญาโทเค็น" + }, + "pleaseReviewTransaction": { + "message": "โปรดตรวจสอบธุรกรรมของคุณ" + }, + "privacyMsg": { + "message": "นโยบายสความเป็นส่วนตัว" + }, + "privateKey": { + "message": "คีย์ส่วนตัว", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "คำเตือน: ห้ามเปิดเผยคีย์นี้ ทุกคนที่มีคีย์ส่วนตัวสามารถขโมยข้อมูลใด ๆ ที่เก็บไว้ในบัญชีของคุณได้" + }, + "privateNetwork": { + "message": "เครือข่ายส่วนตัว" + }, + "qrCode": { + "message": "แสดง QR Code" + }, + "readdToken": { + "message": "คุณสามารถเพิ่มโทเค็นนี้ในอนาคตได้โดยไปที่ “เพิ่มโทเค็น” ในเมนูตัวเลือกบัญชีของคุณ" + }, + "readMore": { + "message": "อ่านเพิ่มเติมที่นี่" + }, + "readMore2": { + "message": "อ่านเพิ่มเติม" + }, + "receive": { + "message": "รับ" + }, + "recipientAddress": { + "message": "แอดแดรสผู้รับ" + }, + "refundAddress": { + "message": "แอดแดรสสำหรับการคืนเงินของคุณ" + }, + "rejected": { + "message": "ถูกปฏิเสธ" + }, + "resetAccount": { + "message": "รีเซ็ตบัญชี" + }, + "restoreFromSeed": { + "message": "กู้คืนจากกลุ่มคำชีด" + }, + "required": { + "message": "จำเป็น" + }, + "retryWithMoreGas": { + "message": "ลองใหม่ด้วยราคาแก๊สที่สูงกว่านี้ที่นี่" + }, + "revealSeedWords": { + "message": "เปิดเผยกลุ่มคำชีด" + }, + "revealSeedWordsWarning": { + "message": "อย่าเปิดเผยคำกลุ่มคำชีดของคุณในที่สาธารณะ! คำเหล่านี้สามารถใช้เพื่อขโมยบัญชีทั้งหมดของคุณ" + }, + "revert": { + "message": "ย้อนกลับ" + }, + "rinkeby": { + "message": "เครือข่ายทดสอบ Rinkeby" + }, + "ropsten": { + "message": "เครือข่ายทดสอบ Ropsten" + }, + "sampleAccountName": { + "message": "เช่น บัญชีเฮงเฮงของฉัน", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "บันทึก" + }, + "saveAsFile": { + "message": "บันทึกเป็นไฟล์", + "description": "Account export process" + }, + "saveSeedAsFile": { + "message": "บันทึกกลุ่มคำชีดเป็นไฟล์" + }, + "search": { + "message": "ค้นหา" + }, + "secretPhrase": { + "message": "ป้อนกลุ่มคำสิบสองคำเพื่อกู้คืนตู้เซฟของคุณ" + }, + "seedPhraseReq": { + "message": "กลุ่มคำชีดมีความยาว 12 คำ" + }, + "select": { + "message": "เลือก" + }, + "selectCurrency": { + "message": "เลือกสกุลเงิน" + }, + "selectService": { + "message": "เลือกบริการ" + }, + "selectType": { + "message": "เลือกประเภท" + }, + "send": { + "message": "ส่ง" + }, + "sendETH": { + "message": "ส่งอีเธอร์" + }, + "sendTokens": { + "message": "ส่งโทเค็น" + }, + "sendTokensAnywhere": { + "message": "ส่งโทเค็นไปให้ทุกคนที่มีบัญชีอีเธอเรียม" + }, + "settings": { + "message": "การตั้งค่า" + }, + "shapeshiftBuy": { + "message": "ซื้อด้วย Shapeshift" + }, + "showPrivateKeys": { + "message": "แสดงคีย์ส่วนตัว" + }, + "showQRCode": { + "message": "แสดง QR Code" + }, + "sign": { + "message": "เซ็นชื่อ" + }, + "signMessage": { + "message": "เซ็นชื่อในข้อความ" + }, + "signNotice": { + "message": "การเซ็นชื่อในข้อความนี้อาจจะเป็นอันตรายได้ \nเซ็นชื่อเฉพาะข้อความจากแหล่งที่คุณไว้วางใจได้จริง ๆ เท่านั้น \nวิธีที่อันตรายนี้จะถูกลบออกในอนาคต" + }, + "sigRequest": { + "message": "ขอลายเซ็น" + }, + "sigRequested": { + "message": "ขอลายเซ็นแล้ว" + }, + "spaceBetween": { + "message": "มีช่องว่างได้เพียงตัวเดียวระหว่างคำเท่านั้น" + }, + "status": { + "message": "สถานะ" + }, + "stateLogs": { + "message": "บันทึกของสถานะ" + }, + "stateLogsDescription": { + "message": "บันทึกของสถานะประกอบด้วยแอดแดรสสาธารณะและธุรกรรมที่ส่ง" + }, + "submit": { + "message": "ตกลง" + }, + "supportCenter": { + "message": "ไปที่ศูนย์สนับสนุนของเรา" + }, + "symbolBetweenZeroTen": { + "message": "สัญลักษณ์ต้องมีความยาวตั้งแต่ 0 ถึง 10 อักขระ" + }, + "takesTooLong": { + "message": "ใช้เวลานานเกินไปใช่หรือไม่?" + }, + "terms": { + "message": "ข้อตกลงในการใช้งาน" + }, + "testFaucet": { + "message": "ตัวแจกจ่ายเพื่อการทดสอบ" + }, + "to": { + "message": "ถึง" + }, + "toETHviaShapeShift": { + "message": "$1 เป็นอีเธอร์โดย ShapeShift", + "description": "system will fill in deposit type in start of message" + }, + "tokenAddress": { + "message": "แอดแดรสโทเค็น" + }, + "tokenAlreadyAdded": { + "message": "โทเคนได้ถูกเพิ่มไปแล้ว" + }, + "tokenBalance": { + "message": "ยอดโทเค็นคงเหลือของคุณคือ:" + }, + "tokenSelection": { + "message": "ค้นหาโทเค็นหรือเลือกจากรายการโทเค็นยอดนิยมของเรา" + }, + "tokenSymbol": { + "message": "สัญลักษณ์ประจำตัว" + }, + "tokenWarning1": { + "message": "ติดตามโทเค็นที่คุณซื้อด้วยบัญชี MetaMask ของคุณ หากคุณซื้อโทเค็นโดยใช้บัญชีอื่นโทเค็นเหล่านั้นจะไม่ปรากฏที่นี่" + }, + "total": { + "message": "รวม" + }, + "transactions": { + "message": "ธุรกรรม" + }, + "transactionMemo": { + "message": "บันทึกช่วยจำของการทำธุรกรรม (ไม่บังคับ)" + }, + "transactionNumber": { + "message": "หมายเลขธุรกรรม" + }, + "transfers": { + "message": "โอน" + }, + "troubleTokenBalances": { + "message": "เรามีปัญหาในการโหลดยอดโทเค็นคงเหลือของคุณ คุณสามารถดูได้ที่นี่", + "description": "Followed by a link (here) to view token balances" + }, + "twelveWords": { + "message": "กลุ่มคำ 12 คำเหล่านี้เป็นวิธีเดียวที่จะกู้คืนบัญชี MetaMask ของคุณ \n กรุณาเก็บไว้ในที่ปลอดภัยและเก็บเป็นความลับ" + }, + "typePassword": { + "message": "พิมพ์รหัสผ่านของคุณ" + }, + "uiWelcome": { + "message": "ยินดีต้อนรับสู่หน้าตาใหม่ (เบต้า)" + }, + "uiWelcomeMessage": { + "message": "ขณะนี้คุณใช้งาน Metamask หน้าตาใหม่แล้ว ลองใช้ความสามรถใหม่ ๆ เช่นการส่งโทเค็นและหากพบปัญหากรุณาแจ้งให้เราทราบ" + }, + "unavailable": { + "message": "ใช้งานไม่ได้" + }, + "unknown": { + "message": "ไม่รู้จัก" + }, + "unknownNetwork": { + "message": "ไม่รู้จักเครือข่ายส่วนตัว" + }, + "unknownNetworkId": { + "message": "ไม่รู้จักหมายเลขเครือข่าย" + }, + "uriErrorMsg": { + "message": "URI ต้องมีคำนำหน้าเป็น HTTP หรือ HTTPS" + }, + "usaOnly": { + "message": "ในสหรัฐอเมริกาเท่านั้น", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "ถูกใช้งานโดยหลายไคลเอนท์" + }, + "useOldUI": { + "message": "ใช้หน้าตาเก่า" + }, + "validFileImport": { + "message": "คุณต้องเลือกไฟล์ที่ถูกต้องเพื่อนำเข้า" + }, + "vaultCreated": { + "message": "สร้างตู้เซฟแล้ว" + }, + "viewAccount": { + "message": "ดูบัญชี" + }, + "visitWebSite": { + "message": "เยี่ยมชมเว็บไซต์ของเรา" + }, + "warning": { + "message": "คำเตือน" + }, + "welcomeBeta": { + "message": "ยินดีต้อนรับสู่ MetaMask เบต้า" + }, + "whatsThis": { + "message": "นี่คืออะไร?" + }, + "yourSigRequested": { + "message": "ลายเซ็นของคุณกำลังได้รับการร้องขอ" + }, + "youSign": { + "message": "คุณกำลังเซ็นชื่อ" + } +} diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json new file mode 100644 index 000000000..e39793430 --- /dev/null +++ b/app/_locales/zh_TW/messages.json @@ -0,0 +1,903 @@ +{ + "accept": { + "message": "接受" + }, + "account": { + "message": "帳戶" + }, + "accountDetails": { + "message": "帳戶詳情" + }, + "accountName": { + "message": "帳戶名稱" + }, + "address": { + "message": "帳戶地址" + }, + "addCustomToken": { + "message": "加入自訂代幣" + }, + "addToken": { + "message": "加入代幣" + }, + "addTokens": { + "message": "加入多筆代幣" + }, + "amount": { + "message": "數額" + }, + "amountPlusGas": { + "message": "數額 + Gas" + }, + "appDescription": { + "message": "乙太坊瀏覽器擴充插件", + "description": "The description of the application" + }, + "appName": { + "message": "MetaMask", + "description": "The name of the application" + }, + "approved": { + "message": "已同意" + }, + "attemptingConnect": { + "message": "正在嘗試連接區塊鏈。" + }, + "attributions": { + "message": "來源" + }, + "available": { + "message": "可使用" + }, + "back": { + "message": "上一頁" + }, + "balance": { + "message": "餘額:" + }, + "balances": { + "message": "你的餘額:" + }, + "balanceIsInsufficientGas": { + "message": "當前餘額不足以支付 Gas" + }, + "beta": { + "message": "BETA" + }, + "betweenMinAndMax": { + "message": "必須大於等於 $1 並且小於等於 $2 。", + "description": "helper for inputting hex as decimal input" + }, + "blockiesIdenticon": { + "message": "使用 Blockies Identicon" + }, + "borrowDharma": { + "message": "透過 Dharma (Beta) 借用" + }, + "builtInCalifornia": { + "message": "MetaMask 是在加州設計製造." + }, + "buy": { + "message": "購買" + }, + "buyCoinbase": { + "message": "在 Coinbase 上購買" + }, + "buyCoinbaseExplainer": { + "message": "Coinbase 是世界上最流行的買賣比特幣,以太幣和萊特幣的交易所。" + }, + "ok": { + "message": "Ok" + }, + "cancel": { + "message": "取消" + }, + "classicInterface": { + "message": "使用舊版界面" + }, + "clickCopy": { + "message": "點擊複製" + }, + "confirm": { + "message": "確認" + }, + "confirmed": { + "message": "已確認" + }, + "confirmContract": { + "message": "確認合約" + }, + "confirmPassword": { + "message": "確認密碼" + }, + "confirmTransaction": { + "message": "確認交易" + }, + "continue": { + "message": "繼續" + }, + "continueToCoinbase": { + "message": "繼續前往 Coinbase" + }, + "contractDeployment": { + "message": "合約部署" + }, + "conversionProgress": { + "message": "正在取得匯率" + }, + "copiedButton": { + "message": "已複製" + }, + "copiedClipboard": { + "message": "已複製到剪貼簿" + }, + "copiedExclamation": { + "message": "已複製!" + }, + "copiedSafe": { + "message": "我已經複製到某個安全的地方了" + }, + "copy": { + "message": "複製" + }, + "copyToClipboard": { + "message": "複製到剪貼簿" + }, + "copyButton": { + "message": " 複製 " + }, + "copyPrivateKey": { + "message": "這是你的私鑰(點擊複製)" + }, + "create": { + "message": "建立" + }, + "createAccount": { + "message": "建立帳戶" + }, + "createDen": { + "message": "建立" + }, + "crypto": { + "message": "加密", + "description": "Exchange type (cryptocurrencies)" + }, + "currentConversion": { + "message": "當前匯率" + }, + "currentNetwork": { + "message": "當前網路" + }, + "customGas": { + "message": "自訂 Gas" + }, + "customToken": { + "message": "自訂代幣" + }, + "customize": { + "message": "自訂" + }, + "customRPC": { + "message": "自訂 RPC" + }, + "decimalsMustZerotoTen": { + "message": "小數點後位數至少為0, 最多為36." + }, + "decimal": { + "message": "小數點精度" + }, + "defaultNetwork": { + "message": "預設 Ether 交易網路為主網路(Main Net)。" + }, + "denExplainer": { + "message": "你的 DEN 是在你的 MetaMask 中的加密密碼儲存庫。" + }, + "deposit": { + "message": "存入" + }, + "depositBTC": { + "message": "將你的 BTC 存入到下面的地址:" + }, + "depositCoin": { + "message": "將你的 $1 存入到下面的地址", + "description": "Tells the user what coin they have selected to deposit with shapeshift" + }, + "depositEth": { + "message": "存入 Eth" + }, + "depositEther": { + "message": "存入 Ether" + }, + "depositFiat": { + "message": "從法定貨幣存入" + }, + "depositFromAccount": { + "message": "從其他帳戶存入" + }, + "depositShapeShift": { + "message": "從 ShapeShift 存入" + }, + "depositShapeShiftExplainer": { + "message": "如果你擁有其他加密貨幣,你可以直接交易並存入 Ether 到你的 MetaMask 錢包。不需要開帳戶。" + }, + "details": { + "message": "詳情" + }, + "directDeposit": { + "message": "直接存入" + }, + "directDepositEther": { + "message": "直接存入 Ether" + }, + "directDepositEtherExplainer": { + "message": "如果你已經擁有了一些 Ether,使用直接存入功能是讓你的新錢包最快取得 Ether 的方式。" + }, + "done": { + "message": "完成" + }, + "downloadStatelogs": { + "message": "下載狀態紀錄" + }, + "dropped": { + "message": "丟棄" + }, + "edit": { + "message": "編輯" + }, + "editAccountName": { + "message": "編輯帳戶名稱" + }, + "emailUs": { + "message": "寄 Email 給我們!" + }, + "encryptNewDen": { + "message": "加密你的新 DEN" + }, + "enterPassword": { + "message": "請輸入密碼" + }, + "enterPasswordConfirm": { + "message": "請再次輸入密碼確認" + }, + "passwordNotLongEnough": { + "message": "您所輸入的密碼長度不足" + }, + "passwordsDontMatch": { + "message": "您所輸入的密碼不一致" + }, + "etherscanView": { + "message": "在 Etherscan 上查看帳戶" + }, + "exchangeRate": { + "message": "匯率" + }, + "exportPrivateKey": { + "message": "導出私鑰" + }, + "exportPrivateKeyWarning": { + "message": "您需要自行負擔導出私鑰產生的風險" + }, + "failed": { + "message": "失败" + }, + "fiat": { + "message": "FIAT", + "description": "Exchange type" + }, + "fileImportFail": { + "message": "檔案導入失敗?點擊這裡!", + "description": "Helps user import their account from a JSON file" + }, + "followTwitter": { + "message": "追蹤 Twitter" + }, + "from": { + "message": "來源地址" + }, + "fromToSame": { + "message": "來源和目的地址不能一樣" + }, + "fromShapeShift": { + "message": "來自 ShapeShift" + }, + "gas": { + "message": "Gas", + "description": "Short indication of gas cost" + }, + "gasFee": { + "message": "Gas 費用" + }, + "gasLimit": { + "message": "Gas 上限" + }, + "gasLimitCalculation": { + "message": "我們根據網路成功率算出建議的 Gas 上限。" + }, + "gasLimitRequired": { + "message": "必需填寫 Gas 上限" + }, + "gasLimitTooLow": { + "message": "Gas 上限至少為 21000" + }, + "generatingSeed": { + "message": "產生助憶詞中..." + }, + "gasPrice": { + "message": "Gas 價格 (GWEI)" + }, + "gasPriceCalculation": { + "message": "我們根據網路成功率算出建議的 Gas 價格" + }, + "gasPriceRequired": { + "message": "必需填寫 Gas 價格" + }, + "getEther": { + "message": "取得 Ether" + }, + "getEtherFromFaucet": { + "message": "從水管取得$1 Ether", + "description": "Displays network name for Ether faucet" + }, + "greaterThanMin": { + "message": "必須要大於等於 $1。", + "description": "helper for inputting hex as decimal input" + }, + "here": { + "message": "這裡", + "description": "as in -click here- for more information (goes with troubleTokenBalances)" + }, + "hereList": { + "message": "Here's a list!!!!" + }, + "hide": { + "message": "隱藏" + }, + "hideToken": { + "message": "隱藏代幣" + }, + "hideTokenPrompt": { + "message": "隱藏代幣?" + }, + "howToDeposit": { + "message": "你想怎麼存入 Ether?" + }, + "holdEther": { + "message": "Metamask 讓您能保存 ether 和代幣, 並成為您接觸分散式應用程式的途徑." + }, + "import": { + "message": "導入", + "description": "Button to import an account from a selected file" + }, + "importAccount": { + "message": "導入帳戶" + }, + "importAccountMsg": { + "message":" 匯入的帳戶與您原有 MetaMask 帳戶的助憶詞並無關聯. 請查看與導入帳戶相關的資料 " + }, + "importAnAccount": { + "message": "導入一個帳戶" + }, + "importDen": { + "message": "導入現成的 DEN" + }, + "imported": { + "message": "已導入私鑰", + "description": "status showing that an account has been fully loaded into the keyring" + }, + "infoHelp": { + "message": "說明 & 資訊" + }, + "insufficientFunds": { + "message": "資金不足." + }, + "insufficientTokens": { + "message": "代幣不足." + }, + "invalidAddress": { + "message": "錯誤的地址" + }, + "invalidAddressRecipient": { + "message": "接收地址錯誤" + }, + "invalidGasParams": { + "message": "Gas 參數錯誤" + }, + "invalidInput": { + "message": "輸入錯誤。" + }, + "invalidRequest": { + "message": "無效的請求" + }, + "invalidRPC": { + "message": "無效的 RPC URI" + }, + "jsonFail": { + "message": "有東西出錯了. 請確認你的 JSON 檔案格式正確。" + }, + "jsonFile": { + "message": "JSON 檔案", + "description": "format for importing an account" + }, + "keepTrackTokens": { + "message": "持續追蹤您 MetaMask 帳戶中的代幣。" + }, + "kovan": { + "message": "Kovan 測試網路" + }, + "knowledgeDataBase": { + "message": "查看我們的知識庫" + }, + "max": { + "message": "最大值" + }, + "learnMore": { + "message": "了解更多。" + }, + "lessThanMax": { + "message": "必須小於等於 $1.", + "description": "helper for inputting hex as decimal input" + }, + "likeToAddTokens": { + "message": "您確定要加入這些代幣嗎?" + }, + "links": { + "message": "連結" + }, + "limit": { + "message": "上限" + }, + "loading": { + "message": "載入..." + }, + "loadingTokens": { + "message": "載入代幣..." + }, + "localhost": { + "message": "Localhost 8545" + }, + "login": { + "message": "登入" + }, + "logout": { + "message": "登出" + }, + "loose": { + "message": "非 MetaMask 帳號" + }, + "loweCaseWords": { + "message": "助憶詞僅包含小寫字元" + }, + "mainnet": { + "message": "乙太坊 主網路" + }, + "message": { + "message": "訊息" + }, + "metamaskDescription": { + "message": "MetaMask 是Ethereum的安全身份識別金庫." + }, + "min": { + "message": "最小" + }, + "myAccounts": { + "message": "我的帳戶" + }, + "mustSelectOne": { + "message": "必須選擇至少 1 代幣." + }, + "needEtherInWallet": { + "message": "要使用 MetaMask 存取 DAPP 時,您的錢包中需要有 Ether。" + }, + "needImportFile": { + "message": "您必須選擇一個檔案來導入。", + "description": "User is important an account and needs to add a file to continue" + }, + "needImportPassword": { + "message": "您必須為選擇好的檔案輸入密碼。", + "description": "Password and file needed to import an account" + }, + "negativeETH": { + "message": "不能送出負值的 ETH。" + }, + "networks": { + "message": "網路" + }, + "newAccount": { + "message": "新帳戶" + }, + "newAccountNumberName": { + "message": "帳戶 $1", + "description": "Default name of next account to be created on create account screen" + }, + "newContract": { + "message": "新合約" + }, + "newPassword": { + "message": "新密碼(至少8個字)" + }, + "newRecipient": { + "message": "新收款人" + }, + "newRPC": { + "message": "New RPC URL" + }, + "next": { + "message": "下一頁" + }, + "noAddressForName": { + "message": "此 ENS 尚未指定地址。" + }, + "noDeposits": { + "message": "尚未有存款" + }, + "noTransactionHistory": { + "message": "尚未有交易紀錄。" + }, + "noTransactions": { + "message": "尚未有交易" + }, + "notStarted": { + "message": "尚未開始" + }, + "oldUI": { + "message": "舊版界面" + }, + "oldUIMessage": { + "message": "你已經切換到舊版界面。可以通過右上方下拉選單中的選項切換回新的使用者界面。" + }, + "or": { + "message": "或", + "description": "choice between creating or importing a new account" + }, + "passwordCorrect": { + "message": "請確認您的密碼是正確的。" + }, + "passwordMismatch": { + "message": "密碼不一致", + "description": "in password creation process, the two new password fields did not match" + }, + "passwordShort": { + "message": "密碼不夠長", + "description": "in password creation process, the password is not long enough to be secure" + }, + "pastePrivateKey": { + "message": "請貼上你的私鑰串:", + "description": "For importing an account from a private key" + }, + "pasteSeed": { + "message": "請貼上你的助憶詞!" + }, + "personalAddressDetected": { + "message": "已偵測到個人地址. 請輸入代幣合約地址." + }, + "pleaseReviewTransaction": { + "message": "請檢查你的交易。" + }, + "popularTokens": { + "message": "常見的代幣" + }, + "privacyMsg": { + "message": "隱私政策" + }, + "privateKey": { + "message": "私鑰", + "description": "select this type of file to use to import an account" + }, + "privateKeyWarning": { + "message": "注意:永遠不要公開這個私鑰。任何取得這把私鑰的人都可以竊取這個帳號中的任何資產。" + }, + "privateNetwork": { + "message": "私有網路" + }, + "qrCode": { + "message": "顯示 QR Code" + }, + "readdToken": { + "message": "之後還可以透過帳戶選單中的“加入代幣”來加入此代幣。" + }, + "readMore": { + "message": "了解更多。" + }, + "readMore2": { + "message": "了解更多。" + }, + "receive": { + "message": "接收" + }, + "recipientAddress": { + "message": "接收地址" + }, + "refundAddress": { + "message": "你的退款地址" + }, + "rejected": { + "message": "拒絕" + }, + "resetAccount": { + "message": "重置帳戶" + }, + "restoreFromSeed": { + "message": "透過助憶詞重置" + }, + "restoreVault": { + "message": "重置金庫" + }, + "required": { + "message": "必填" + }, + "retryWithMoreGas": { + "message": "改用更高的 Gas 價格重試" + }, + "walletSeed": { + "message": "錢包助憶詞" + }, + "revealSeedWords": { + "message": "顯示助憶詞" + }, + "revealSeedWordsWarning": { + "message": "別在公共場合回復你的助憶詞!這些詞可被用來竊取你的帳戶." + }, + "revert": { + "message": "還原" + }, + "rinkeby": { + "message": "Rinkeby 測試網路" + }, + "ropsten": { + "message": "Ropsten 測試網路" + }, + "currentRpc": { + "message": "當前的 RPC" + }, + "connectingToMainnet": { + "message": "連線到主 Ethereum 網路" + }, + "connectingToRopsten": { + "message": "連線到 Ropsten 測試網路" + }, + "connectingToKovan": { + "message": "連線到 Kovan 測試網路" + }, + "connectingToRinkeby": { + "message": "連線到 Rinkeby 測試網路" + }, + "connectingToUnknown": { + "message": "連線到未知網路" + }, + "sampleAccountName": { + "message": "例如:我的新帳戶", + "description": "Help user understand concept of adding a human-readable name to their account" + }, + "save": { + "message": "儲存" + }, + "saveAsFile": { + "message": "儲存檔案", + "description": "Account export process" + }, + "saveSeedAsFile": { + "message": "將助憶詞儲存成檔案" + }, + "search": { + "message": "搜尋" + }, + "secretPhrase": { + "message": "在此輸入你的12個祕密助憶詞以回復金庫." + }, + "newPassword8Chars": { + "message": "新密碼 (至少 8 個字元)" + }, + "seedPhraseReq": { + "message": "助憶詞為 12 個詞語" + }, + "select": { + "message": "選擇" + }, + "selectCurrency": { + "message": "選擇幣別" + }, + "selectService": { + "message": "選擇服務" + }, + "selectType": { + "message": "選擇類型" + }, + "send": { + "message": "發送" + }, + "sendETH": { + "message": "發送 ETH" + }, + "sendTokens": { + "message": "發送代幣" + }, + "onlySendToEtherAddress": { + "message": "只發送 ETH 到乙太坊地址." + }, + "searchTokens": { + "message": "搜尋代幣" + }, + "sendTokensAnywhere": { + "message": "發送代幣給擁有乙太坊帳戶的任何人" + }, + "settings": { + "message": "設定" + }, + "info": { + "message": "資訊" + }, + "shapeshiftBuy": { + "message": "從 Shapeshift 購買" + }, + "showPrivateKeys": { + "message": "顯示私鑰" + }, + "showQRCode": { + "message": "顯示 QR Code" + }, + "sign": { + "message": "簽署" + }, + "signed": { + "message": "已簽署" + }, + "signMessage": { + "message": "簽署訊息" + }, + "signNotice": { + "message": "簽署此訊息可能會產生危險地副作用。 \n只從你完全信任的網站上簽署。這種危險的方法;將在未來的版本中被移除。" + }, + "sigRequest": { + "message": "請求簽署" + }, + "sigRequested": { + "message": "已請求簽署" + }, + "spaceBetween": { + "message": "there can only be a space between words" + }, + "status": { + "message": "狀態" + }, + "stateLogs": { + "message": "狀態紀錄" + }, + "stateLogsDescription": { + "message": "狀態紀錄包含你的公開帳戶地址和已傳送的交易資訊." + }, + "stateLogError": { + "message": "在取得狀態紀錄時發生錯誤." + }, + "submit": { + "message": "送出" + }, + "submitted": { + "message": "已送出" + }, + "supportCenter": { + "message": "造訪我們的協助中心" + }, + "symbolBetweenZeroTen": { + "message": "代號必須介於 0 到 10 字元間." + }, + "takesTooLong": { + "message": "花費太長時間?" + }, + "terms": { + "message": "使用條款" + }, + "testFaucet": { + "message": "測試水管" + }, + "to": { + "message": "目的帳號" + }, + "toETHviaShapeShift": { + "message": "$1 ETH 透過 ShapeShift", + "description": "system will fill in deposit type in start of message" + }, + "tokenAddress": { + "message": "代幣地址" + }, + "tokenAlreadyAdded": { + "message": "已加入過此代幣。" + }, + "tokenBalance": { + "message": "代幣餘額:" + }, + "tokenSelection": { + "message": "搜尋代幣或是從常見代幣列表中選擇。" + }, + "tokenSymbol": { + "message": "代幣代號" + }, + "tokenWarning1": { + "message": "使用 MetaMask 帳戶追蹤你已購得的代幣。如果你使用不同的帳戶保存購得的代幣,那些代幣就不會出現在這裡。" + }, + "total": { + "message": "總量" + }, + "transactions": { + "message": "交易紀錄" + }, + "transactionMemo": { + "message": "交易備註(選填)" + }, + "transactionNumber": { + "message": "交易號碼" + }, + "transfers": { + "message": "交易" + }, + "troubleTokenBalances": { + "message": "無法取得代幣餘額。您k可以到這裡查看 ", + "description": "Followed by a link (here) to view token balances" + }, + "twelveWords": { + "message": "這 12 個單詞是唯一回復你的 MetaMask 帳號的方法。\n將它們儲存到那些安全且隱密的地方吧。" + }, + "typePassword": { + "message": "請輸入密碼" + }, + "uiWelcome": { + "message": "歡迎使用新版界面 (Beta)" + }, + "uiWelcomeMessage": { + "message": "你現在正在使用新版 MetaMask 界面。試試諸如發送代幣等新功能吧,有任何問題請告知我們。" + }, + "unapproved": { + "message": "未同意" + }, + "unavailable": { + "message": "不可用" + }, + "unknown": { + "message": "未知" + }, + "unknownNetwork": { + "message": "未知私有網路" + }, + "unknownNetworkId": { + "message": "未知網路 ID" + }, + "uriErrorMsg": { + "message": "URIs 需要加入適當的 HTTP/HTTPS 前綴." + }, + "usaOnly": { + "message": "僅限美國", + "description": "Using this exchange is limited to people inside the USA" + }, + "usedByClients": { + "message": "可用於各種不同的客戶端" + }, + "useOldUI": { + "message": "使用舊版界面" + }, + "validFileImport": { + "message": "您必須選擇一個合法的檔案來導入." + }, + "vaultCreated": { + "message": "已建立金庫" + }, + "viewAccount": { + "message": "查看帳戶" + }, + "visitWebSite": { + "message": "造訪我們的網站" + }, + "warning": { + "message": "警告" + }, + "welcomeBeta": { + "message": "歡迎到 MetaMask Beta" + }, + "whatsThis": { + "message": "這是什麼?" + }, + "yourSigRequested": { + "message": "正在請求你的簽署" + }, + "youSign": { + "message": "正在簽署" + } +} diff --git a/app/manifest.json b/app/manifest.json index 6fcf6cd7c..a20f9b976 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.2.0", + "version": "4.4.0", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", diff --git a/app/scripts/background.js b/app/scripts/background.js index ef5513ec7..7bbaa89d6 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -42,6 +42,7 @@ const isIE = !!document.documentMode const isEdge = !isIE && !!window.StyleMedia let popupIsOpen = false +let notificationIsOpen = false let openMetamaskTabsIDs = {} // state persistence @@ -83,7 +84,6 @@ async function loadStateFromPersistence () { // write to disk if (localStore.isSupported) localStore.set(versionedData) - diskStore.putState(versionedData) // return just the data return versionedData.data @@ -120,7 +120,6 @@ function setupController (initState) { debounce(1000), storeTransform(versionifyData), storeTransform(syncDataWithExtension), - asStream(diskStore), (error) => { log.error('pump hit error', error) } @@ -165,6 +164,11 @@ function setupController (initState) { } }) } + if (remotePort.name === 'notification') { + endOfStream(portStream, () => { + notificationIsOpen = false + }) + } } else { // communication with page const originDomain = urlUtil.parse(remotePort.sender.url).hostname @@ -207,7 +211,8 @@ function setupController (initState) { function triggerUi () { extension.tabs.query({ active: true }, (tabs) => { const currentlyActiveMetamaskTab = tabs.find(tab => openMetamaskTabsIDs[tab.id]) - if (!popupIsOpen && !currentlyActiveMetamaskTab) notificationManager.showPopup() + if (!popupIsOpen && !currentlyActiveMetamaskTab && !notificationIsOpen) notificationManager.showPopup() + notificationIsOpen = true }) } diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js index adaf60c65..1fcb7cf69 100644 --- a/app/scripts/lib/notification-manager.js +++ b/app/scripts/lib/notification-manager.js @@ -13,11 +13,12 @@ class NotificationManager { this._getPopup((err, popup) => { if (err) throw err + // Bring focus to chrome popup if (popup) { - // bring focus to existing popup + // bring focus to existing chrome popup extension.windows.update(popup.id, { focused: true }) } else { - // create new popup + // create new notification popup extension.windows.create({ url: 'notification.html', type: 'popup', @@ -29,6 +30,7 @@ class NotificationManager { } closePopup () { + // closes notification popup this._getPopup((err, popup) => { if (err) throw err if (!popup) return @@ -60,9 +62,8 @@ class NotificationManager { _getPopupIn (windows) { return windows ? windows.find((win) => { - return (win && win.type === 'popup' && - win.height === height && - win.width === width) + // Returns notification popup + return (win && win.type === 'popup') }) : null } diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index 42e48cb90..02c01b755 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -1,4 +1,4 @@ -const Raven = require('../vendor/raven.min.js') +const Raven = require('raven-js') const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' @@ -18,9 +18,35 @@ function setupRaven(opts) { ravenTarget = PROD } - Raven.config(ravenTarget, { + const client = Raven.config(ravenTarget, { release, - }).install() + transport: function(opts) { + // modify report urls + const report = opts.data + rewriteReportUrls(report) + // make request normally + client._makeRequest(opts) + }, + }) + client.install() return Raven } + +function rewriteReportUrls(report) { + // update request url + report.request.url = toMetamaskUrl(report.request.url) + // update exception stack trace + report.exception.values.forEach(item => { + item.stacktrace.frames.forEach(frame => { + frame.filename = toMetamaskUrl(frame.filename) + }) + }) +} + +function toMetamaskUrl(origUrl) { + const filePath = origUrl.split(location.origin)[1] + if (!filePath) return origUrl + const metamaskUrl = `metamask${filePath}` + return metamaskUrl +} diff --git a/app/scripts/migrations/022.js b/app/scripts/migrations/022.js new file mode 100644 index 000000000..c3c0d53ef --- /dev/null +++ b/app/scripts/migrations/022.js @@ -0,0 +1,39 @@ + +const version = 22 + +/* + +This migration adds submittedTime to the txMeta if it is not their + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + try { + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + } catch (err) { + console.warn(`MetaMask Migration #${version}` + err.stack) + } + return Promise.resolve(versionedData) + }, +} + +function transformState (state) { + const newState = state + const transactions = newState.TransactionController.transactions + + newState.TransactionController.transactions = transactions.map((txMeta) => { + if (txMeta.status !== 'submitted' || txMeta.submittedTime) return txMeta + txMeta.submittedTime = (new Date()).getTime() + return txMeta + }) + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index a0cf5f4d4..b49a40c65 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -32,4 +32,5 @@ module.exports = [ require('./019'), require('./020'), require('./021'), + require('./022'), ] diff --git a/app/scripts/popup.js b/app/scripts/popup.js index 11d50ee87..e78981f06 100644 --- a/app/scripts/popup.js +++ b/app/scripts/popup.js @@ -65,6 +65,7 @@ startPopup({ container, connectionStream }, (err, store) => { function closePopupIfOpen (windowType) { if (windowType !== 'notification') { + // should close only chrome popup notificationManager.closePopup() } } diff --git a/app/scripts/vendor/raven.min.js b/app/scripts/vendor/raven.min.js deleted file mode 100644 index b439aeae6..000000000 --- a/app/scripts/vendor/raven.min.js +++ /dev/null @@ -1,3 +0,0 @@ -/*! Raven.js 3.22.1 (7584197) | github.com/getsentry/raven-js */ -!function(a){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=a();else if("function"==typeof define&&define.amd)define([],a);else{var b;b="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,b.Raven=a()}}(function(){return function a(b,c,d){function e(g,h){if(!c[g]){if(!b[g]){var i="function"==typeof require&&require;if(!h&&i)return i(g,!0);if(f)return f(g,!0);var j=new Error("Cannot find module '"+g+"'");throw j.code="MODULE_NOT_FOUND",j}var k=c[g]={exports:{}};b[g][0].call(k.exports,function(a){var c=b[g][1][a];return e(c?c:a)},k,k.exports,a,b,c,d)}return c[g].exports}for(var f="function"==typeof require&&require,g=0;g<d.length;g++)e(d[g]);return e}({1:[function(a,b,c){function d(a){this.name="RavenConfigError",this.message=a}d.prototype=new Error,d.prototype.constructor=d,b.exports=d},{}],2:[function(a,b,c){var d=function(a,b,c){var d=a[b],e=a;if(b in a){var f="warn"===b?"warning":b;a[b]=function(){var a=[].slice.call(arguments),g=""+a.join(" "),h={level:f,logger:"console",extra:{arguments:a}};"assert"===b?a[0]===!1&&(g="Assertion failed: "+(a.slice(1).join(" ")||"console.assert"),h.extra.arguments=a.slice(1),c&&c(g,h)):c&&c(g,h),d&&Function.prototype.apply.call(d,e,a)}}};b.exports={wrapMethod:d}},{}],3:[function(a,b,c){(function(c){function d(){return+new Date}function e(a,b){return o(b)?function(c){return b(c,a)}:b}function f(){this.a=!("object"!=typeof JSON||!JSON.stringify),this.b=!n(K),this.c=!n(L),this.d=null,this.e=null,this.f=null,this.g=null,this.h=null,this.i=null,this.j={},this.k={release:J.SENTRY_RELEASE&&J.SENTRY_RELEASE.id,logger:"javascript",ignoreErrors:[],ignoreUrls:[],whitelistUrls:[],includePaths:[],headers:null,collectWindowErrors:!0,maxMessageLength:0,maxUrlLength:250,stackTraceLimit:50,autoBreadcrumbs:!0,instrument:!0,sampleRate:1},this.l={method:"POST",keepalive:!0,referrerPolicy:"origin"},this.m=0,this.n=!1,this.o=Error.stackTraceLimit,this.p=J.console||{},this.q={},this.r=[],this.s=d(),this.t=[],this.u=[],this.v=null,this.w=J.location,this.x=this.w&&this.w.href,this.y();for(var a in this.p)this.q[a]=this.p[a]}var g=a(6),h=a(7),i=a(1),j=a(5),k=j.isError,l=j.isObject,m=j.isErrorEvent,n=j.isUndefined,o=j.isFunction,p=j.isString,q=j.isArray,r=j.isEmptyObject,s=j.each,t=j.objectMerge,u=j.truncate,v=j.objectFrozen,w=j.hasKey,x=j.joinRegExp,y=j.urlencode,z=j.uuid4,A=j.htmlTreeAsString,B=j.isSameException,C=j.isSameStacktrace,D=j.parseUrl,E=j.fill,F=j.supportsFetch,G=a(2).wrapMethod,H="source protocol user pass host port path".split(" "),I=/^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/,J="undefined"!=typeof window?window:"undefined"!=typeof c?c:"undefined"!=typeof self?self:{},K=J.document,L=J.navigator;f.prototype={VERSION:"3.22.1",debug:!1,TraceKit:g,config:function(a,b){var c=this;if(c.g)return this.z("error","Error: Raven has already been configured"),c;if(!a)return c;var d=c.k;b&&s(b,function(a,b){"tags"===a||"extra"===a||"user"===a?c.j[a]=b:d[a]=b}),c.setDSN(a),d.ignoreErrors.push(/^Script error\.?$/),d.ignoreErrors.push(/^Javascript error: Script error\.? on line 0$/),d.ignoreErrors=x(d.ignoreErrors),d.ignoreUrls=!!d.ignoreUrls.length&&x(d.ignoreUrls),d.whitelistUrls=!!d.whitelistUrls.length&&x(d.whitelistUrls),d.includePaths=x(d.includePaths),d.maxBreadcrumbs=Math.max(0,Math.min(d.maxBreadcrumbs||100,100));var e={xhr:!0,console:!0,dom:!0,location:!0,sentry:!0},f=d.autoBreadcrumbs;"[object Object]"==={}.toString.call(f)?f=t(e,f):f!==!1&&(f=e),d.autoBreadcrumbs=f;var h={tryCatch:!0},i=d.instrument;return"[object Object]"==={}.toString.call(i)?i=t(h,i):i!==!1&&(i=h),d.instrument=i,g.collectWindowErrors=!!d.collectWindowErrors,c},install:function(){var a=this;return a.isSetup()&&!a.n&&(g.report.subscribe(function(){a.A.apply(a,arguments)}),a.B(),a.k.instrument&&a.k.instrument.tryCatch&&a.C(),a.k.autoBreadcrumbs&&a.D(),a.E(),a.n=!0),Error.stackTraceLimit=a.k.stackTraceLimit,this},setDSN:function(a){var b=this,c=b.F(a),d=c.path.lastIndexOf("/"),e=c.path.substr(1,d);b.G=a,b.h=c.user,b.H=c.pass&&c.pass.substr(1),b.i=c.path.substr(d+1),b.g=b.I(c),b.J=b.g+"/"+e+"api/"+b.i+"/store/",this.y()},context:function(a,b,c){return o(a)&&(c=b||[],b=a,a=void 0),this.wrap(a,b).apply(this,c)},wrap:function(a,b,c){function d(){var d=[],f=arguments.length,g=!a||a&&a.deep!==!1;for(c&&o(c)&&c.apply(this,arguments);f--;)d[f]=g?e.wrap(a,arguments[f]):arguments[f];try{return b.apply(this,d)}catch(h){throw e.K(),e.captureException(h,a),h}}var e=this;if(n(b)&&!o(a))return a;if(o(a)&&(b=a,a=void 0),!o(b))return b;try{if(b.L)return b;if(b.M)return b.M}catch(f){return b}for(var g in b)w(b,g)&&(d[g]=b[g]);return d.prototype=b.prototype,b.M=d,d.L=!0,d.N=b,d},uninstall:function(){return g.report.uninstall(),this.O(),this.P(),Error.stackTraceLimit=this.o,this.n=!1,this},captureException:function(a,b){var c=!k(a),d=!m(a),e=m(a)&&!a.error;if(c&&d||e)return this.captureMessage(a,t({trimHeadFrames:1,stacktrace:!0},b));m(a)&&(a=a.error),this.d=a;try{var f=g.computeStackTrace(a);this.Q(f,b)}catch(h){if(a!==h)throw h}return this},captureMessage:function(a,b){if(!this.k.ignoreErrors.test||!this.k.ignoreErrors.test(a)){b=b||{};var c,d=t({message:a+""},b);try{throw new Error(a)}catch(e){c=e}c.name=null;var f=g.computeStackTrace(c),h=q(f.stack)&&f.stack[1],i=h&&h.url||"";if((!this.k.ignoreUrls.test||!this.k.ignoreUrls.test(i))&&(!this.k.whitelistUrls.test||this.k.whitelistUrls.test(i))){if(this.k.stacktrace||b&&b.stacktrace){b=t({fingerprint:a,trimHeadFrames:(b.trimHeadFrames||0)+1},b);var j=this.R(f,b);d.stacktrace={frames:j.reverse()}}return this.S(d),this}}},captureBreadcrumb:function(a){var b=t({timestamp:d()/1e3},a);if(o(this.k.breadcrumbCallback)){var c=this.k.breadcrumbCallback(b);if(l(c)&&!r(c))b=c;else if(c===!1)return this}return this.u.push(b),this.u.length>this.k.maxBreadcrumbs&&this.u.shift(),this},addPlugin:function(a){var b=[].slice.call(arguments,1);return this.r.push([a,b]),this.n&&this.E(),this},setUserContext:function(a){return this.j.user=a,this},setExtraContext:function(a){return this.T("extra",a),this},setTagsContext:function(a){return this.T("tags",a),this},clearContext:function(){return this.j={},this},getContext:function(){return JSON.parse(h(this.j))},setEnvironment:function(a){return this.k.environment=a,this},setRelease:function(a){return this.k.release=a,this},setDataCallback:function(a){var b=this.k.dataCallback;return this.k.dataCallback=e(b,a),this},setBreadcrumbCallback:function(a){var b=this.k.breadcrumbCallback;return this.k.breadcrumbCallback=e(b,a),this},setShouldSendCallback:function(a){var b=this.k.shouldSendCallback;return this.k.shouldSendCallback=e(b,a),this},setTransport:function(a){return this.k.transport=a,this},lastException:function(){return this.d},lastEventId:function(){return this.f},isSetup:function(){return!!this.a&&(!!this.g||(this.ravenNotConfiguredError||(this.ravenNotConfiguredError=!0,this.z("error","Error: Raven has not been configured.")),!1))},afterLoad:function(){var a=J.RavenConfig;a&&this.config(a.dsn,a.config).install()},showReportDialog:function(a){if(K){a=a||{};var b=a.eventId||this.lastEventId();if(!b)throw new i("Missing eventId");var c=a.dsn||this.G;if(!c)throw new i("Missing DSN");var d=encodeURIComponent,e="";e+="?eventId="+d(b),e+="&dsn="+d(c);var f=a.user||this.j.user;f&&(f.name&&(e+="&name="+d(f.name)),f.email&&(e+="&email="+d(f.email)));var g=this.I(this.F(c)),h=K.createElement("script");h.async=!0,h.src=g+"/api/embed/error-page/"+e,(K.head||K.body).appendChild(h)}},K:function(){var a=this;this.m+=1,setTimeout(function(){a.m-=1})},U:function(a,b){var c,d;if(this.b){b=b||{},a="raven"+a.substr(0,1).toUpperCase()+a.substr(1),K.createEvent?(c=K.createEvent("HTMLEvents"),c.initEvent(a,!0,!0)):(c=K.createEventObject(),c.eventType=a);for(d in b)w(b,d)&&(c[d]=b[d]);if(K.createEvent)K.dispatchEvent(c);else try{K.fireEvent("on"+c.eventType.toLowerCase(),c)}catch(e){}}},V:function(a){var b=this;return function(c){if(b.W=null,b.v!==c){b.v=c;var d;try{d=A(c.target)}catch(e){d="<unknown>"}b.captureBreadcrumb({category:"ui."+a,message:d})}}},X:function(){var a=this,b=1e3;return function(c){var d;try{d=c.target}catch(e){return}var f=d&&d.tagName;if(f&&("INPUT"===f||"TEXTAREA"===f||d.isContentEditable)){var g=a.W;g||a.V("input")(c),clearTimeout(g),a.W=setTimeout(function(){a.W=null},b)}}},Y:function(a,b){var c=D(this.w.href),d=D(b),e=D(a);this.x=b,c.protocol===d.protocol&&c.host===d.host&&(b=d.relative),c.protocol===e.protocol&&c.host===e.host&&(a=e.relative),this.captureBreadcrumb({category:"navigation",data:{to:b,from:a}})},B:function(){var a=this;a.Z=Function.prototype.toString,Function.prototype.toString=function(){return"function"==typeof this&&this.L?a.Z.apply(this.N,arguments):a.Z.apply(this,arguments)}},O:function(){this.Z&&(Function.prototype.toString=this.Z)},C:function(){function a(a){return function(b,d){for(var e=new Array(arguments.length),f=0;f<e.length;++f)e[f]=arguments[f];var g=e[0];return o(g)&&(e[0]=c.wrap(g)),a.apply?a.apply(this,e):a(e[0],e[1])}}function b(a){var b=J[a]&&J[a].prototype;b&&b.hasOwnProperty&&b.hasOwnProperty("addEventListener")&&(E(b,"addEventListener",function(b){return function(d,f,g,h){try{f&&f.handleEvent&&(f.handleEvent=c.wrap(f.handleEvent))}catch(i){}var j,k,l;return e&&e.dom&&("EventTarget"===a||"Node"===a)&&(k=c.V("click"),l=c.X(),j=function(a){if(a){var b;try{b=a.type}catch(c){return}return"click"===b?k(a):"keypress"===b?l(a):void 0}}),b.call(this,d,c.wrap(f,void 0,j),g,h)}},d),E(b,"removeEventListener",function(a){return function(b,c,d,e){try{c=c&&(c.M?c.M:c)}catch(f){}return a.call(this,b,c,d,e)}},d))}var c=this,d=c.t,e=this.k.autoBreadcrumbs;E(J,"setTimeout",a,d),E(J,"setInterval",a,d),J.requestAnimationFrame&&E(J,"requestAnimationFrame",function(a){return function(b){return a(c.wrap(b))}},d);for(var f=["EventTarget","Window","Node","ApplicationCache","AudioTrackList","ChannelMergerNode","CryptoOperation","EventSource","FileReader","HTMLUnknownElement","IDBDatabase","IDBRequest","IDBTransaction","KeyOperation","MediaController","MessagePort","ModalWindow","Notification","SVGElementInstance","Screen","TextTrack","TextTrackCue","TextTrackList","WebSocket","WebSocketWorker","Worker","XMLHttpRequest","XMLHttpRequestEventTarget","XMLHttpRequestUpload"],g=0;g<f.length;g++)b(f[g])},D:function(){function a(a,c){a in c&&o(c[a])&&E(c,a,function(a){return b.wrap(a)})}var b=this,c=this.k.autoBreadcrumbs,d=b.t;if(c.xhr&&"XMLHttpRequest"in J){var e=XMLHttpRequest.prototype;E(e,"open",function(a){return function(c,d){return p(d)&&d.indexOf(b.h)===-1&&(this.$={method:c,url:d,status_code:null}),a.apply(this,arguments)}},d),E(e,"send",function(c){return function(){function d(){if(e.$&&4===e.readyState){try{e.$.status_code=e.status}catch(a){}b.captureBreadcrumb({type:"http",category:"xhr",data:e.$})}}for(var e=this,f=["onload","onerror","onprogress"],g=0;g<f.length;g++)a(f[g],e);return"onreadystatechange"in e&&o(e.onreadystatechange)?E(e,"onreadystatechange",function(a){return b.wrap(a,void 0,d)}):e.onreadystatechange=d,c.apply(this,arguments)}},d)}c.xhr&&F()&&E(J,"fetch",function(a){return function(){for(var c=new Array(arguments.length),d=0;d<c.length;++d)c[d]=arguments[d];var e,f=c[0],g="GET";if("string"==typeof f?e=f:"Request"in J&&f instanceof J.Request?(e=f.url,f.method&&(g=f.method)):e=""+f,e.indexOf(b.h)!==-1)return a.apply(this,c);c[1]&&c[1].method&&(g=c[1].method);var h={method:g,url:e,status_code:null};return a.apply(this,c).then(function(a){return h.status_code=a.status,b.captureBreadcrumb({type:"http",category:"fetch",data:h}),a})}},d),c.dom&&this.b&&(K.addEventListener?(K.addEventListener("click",b.V("click"),!1),K.addEventListener("keypress",b.X(),!1)):(K.attachEvent("onclick",b.V("click")),K.attachEvent("onkeypress",b.X())));var f=J.chrome,g=f&&f.app&&f.app.runtime,h=!g&&J.history&&history.pushState&&history.replaceState;if(c.location&&h){var i=J.onpopstate;J.onpopstate=function(){var a=b.w.href;if(b.Y(b.x,a),i)return i.apply(this,arguments)};var j=function(a){return function(){var c=arguments.length>2?arguments[2]:void 0;return c&&b.Y(b.x,c+""),a.apply(this,arguments)}};E(history,"pushState",j,d),E(history,"replaceState",j,d)}if(c.console&&"console"in J&&console.log){var k=function(a,c){b.captureBreadcrumb({message:a,level:c.level,category:"console"})};s(["debug","info","warn","error","log"],function(a,b){G(console,b,k)})}},P:function(){for(var a;this.t.length;){a=this.t.shift();var b=a[0],c=a[1],d=a[2];b[c]=d}},E:function(){var a=this;s(this.r,function(b,c){var d=c[0],e=c[1];d.apply(a,[a].concat(e))})},F:function(a){var b=I.exec(a),c={},d=7;try{for(;d--;)c[H[d]]=b[d]||""}catch(e){throw new i("Invalid DSN: "+a)}if(c.pass&&!this.k.allowSecretKey)throw new i("Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key");return c},I:function(a){var b="//"+a.host+(a.port?":"+a.port:"");return a.protocol&&(b=a.protocol+":"+b),b},A:function(){this.m||this.Q.apply(this,arguments)},Q:function(a,b){var c=this.R(a,b);this.U("handle",{stackInfo:a,options:b}),this._(a.name,a.message,a.url,a.lineno,c,b)},R:function(a,b){var c=this,d=[];if(a.stack&&a.stack.length&&(s(a.stack,function(b,e){var f=c.aa(e,a.url);f&&d.push(f)}),b&&b.trimHeadFrames))for(var e=0;e<b.trimHeadFrames&&e<d.length;e++)d[e].in_app=!1;return d=d.slice(0,this.k.stackTraceLimit)},aa:function(a,b){var c={filename:a.url,lineno:a.line,colno:a.column,"function":a.func||"?"};return a.url||(c.filename=b),c.in_app=!(this.k.includePaths.test&&!this.k.includePaths.test(c.filename)||/(Raven|TraceKit)\./.test(c["function"])||/raven\.(min\.)?js$/.test(c.filename)),c},_:function(a,b,c,d,e,f){var g=(a?a+": ":"")+(b||"");if(!this.k.ignoreErrors.test||!this.k.ignoreErrors.test(b)&&!this.k.ignoreErrors.test(g)){var h;if(e&&e.length?(c=e[0].filename||c,e.reverse(),h={frames:e}):c&&(h={frames:[{filename:c,lineno:d,in_app:!0}]}),(!this.k.ignoreUrls.test||!this.k.ignoreUrls.test(c))&&(!this.k.whitelistUrls.test||this.k.whitelistUrls.test(c))){var i=t({exception:{values:[{type:a,value:b,stacktrace:h}]},culprit:c},f);this.S(i)}}},ba:function(a){var b=this.k.maxMessageLength;if(a.message&&(a.message=u(a.message,b)),a.exception){var c=a.exception.values[0];c.value=u(c.value,b)}var d=a.request;return d&&(d.url&&(d.url=u(d.url,this.k.maxUrlLength)),d.Referer&&(d.Referer=u(d.Referer,this.k.maxUrlLength))),a.breadcrumbs&&a.breadcrumbs.values&&this.ca(a.breadcrumbs),a},ca:function(a){for(var b,c,d,e=["to","from","url"],f=0;f<a.values.length;++f)if(c=a.values[f],c.hasOwnProperty("data")&&l(c.data)&&!v(c.data)){d=t({},c.data);for(var g=0;g<e.length;++g)b=e[g],d.hasOwnProperty(b)&&d[b]&&(d[b]=u(d[b],this.k.maxUrlLength));a.values[f].data=d}},da:function(){if(this.c||this.b){var a={};return this.c&&L.userAgent&&(a.headers={"User-Agent":navigator.userAgent}),J.location&&J.location.href&&(a.url=J.location.href),this.b&&K.referrer&&(a.headers||(a.headers={}),a.headers.Referer=K.referrer),a}},y:function(){this.ea=0,this.fa=null},ga:function(){return this.ea&&d()-this.fa<this.ea},ha:function(a){var b=this.e;return!(!b||a.message!==b.message||a.culprit!==b.culprit)&&(a.stacktrace||b.stacktrace?C(a.stacktrace,b.stacktrace):!a.exception&&!b.exception||B(a.exception,b.exception))},ia:function(a){if(!this.ga()){var b=a.status;if(400===b||401===b||429===b){var c;try{c=F()?a.headers.get("Retry-After"):a.getResponseHeader("Retry-After"),c=1e3*parseInt(c,10)}catch(e){}this.ea=c?c:2*this.ea||1e3,this.fa=d()}}},S:function(a){var b=this.k,c={project:this.i,logger:b.logger,platform:"javascript"},e=this.da();if(e&&(c.request=e),a.trimHeadFrames&&delete a.trimHeadFrames,a=t(c,a),a.tags=t(t({},this.j.tags),a.tags),a.extra=t(t({},this.j.extra),a.extra),a.extra["session:duration"]=d()-this.s,this.u&&this.u.length>0&&(a.breadcrumbs={values:[].slice.call(this.u,0)}),this.j.user&&(a.user=this.j.user),b.environment&&(a.environment=b.environment),b.release&&(a.release=b.release),b.serverName&&(a.server_name=b.serverName),Object.keys(a).forEach(function(b){(null==a[b]||""===a[b]||r(a[b]))&&delete a[b]}),o(b.dataCallback)&&(a=b.dataCallback(a)||a),a&&!r(a)&&(!o(b.shouldSendCallback)||b.shouldSendCallback(a)))return this.ga()?void this.z("warn","Raven dropped error due to backoff: ",a):void("number"==typeof b.sampleRate?Math.random()<b.sampleRate&&this.ja(a):this.ja(a))},ka:function(){return z()},ja:function(a,b){var c=this,d=this.k;if(this.isSetup()){if(a=this.ba(a),!this.k.allowDuplicates&&this.ha(a))return void this.z("warn","Raven dropped repeat event: ",a);this.f=a.event_id||(a.event_id=this.ka()),this.e=a,this.z("debug","Raven about to send:",a);var e={sentry_version:"7",sentry_client:"raven-js/"+this.VERSION,sentry_key:this.h};this.H&&(e.sentry_secret=this.H);var f=a.exception&&a.exception.values[0];this.k.autoBreadcrumbs&&this.k.autoBreadcrumbs.sentry&&this.captureBreadcrumb({category:"sentry",message:f?(f.type?f.type+": ":"")+f.value:a.message,event_id:a.event_id,level:a.level||"error"});var g=this.J;(d.transport||this.la).call(this,{url:g,auth:e,data:a,options:d,onSuccess:function(){c.y(),c.U("success",{data:a,src:g}),b&&b()},onError:function(d){c.z("error","Raven transport failed to send: ",d),d.request&&c.ia(d.request),c.U("failure",{data:a,src:g}),d=d||new Error("Raven send failed (no additional details provided)"),b&&b(d)}})}},la:function(a){var b=a.url+"?"+y(a.auth),c=null,d={};if(a.options.headers&&(c=this.ma(a.options.headers)),a.options.fetchParameters&&(d=this.ma(a.options.fetchParameters)),F()){d.body=h(a.data);var e=t({},this.l),f=t(e,d);return c&&(f.headers=c),J.fetch(b,f).then(function(b){if(b.ok)a.onSuccess&&a.onSuccess();else{var c=new Error("Sentry error code: "+b.status);c.request=b,a.onError&&a.onError(c)}})["catch"](function(){a.onError&&a.onError(new Error("Sentry error code: network unavailable"))})}var g=J.XMLHttpRequest&&new J.XMLHttpRequest;if(g){var i="withCredentials"in g||"undefined"!=typeof XDomainRequest;i&&("withCredentials"in g?g.onreadystatechange=function(){if(4===g.readyState)if(200===g.status)a.onSuccess&&a.onSuccess();else if(a.onError){var b=new Error("Sentry error code: "+g.status);b.request=g,a.onError(b)}}:(g=new XDomainRequest,b=b.replace(/^https?:/,""),a.onSuccess&&(g.onload=a.onSuccess),a.onError&&(g.onerror=function(){var b=new Error("Sentry error code: XDomainRequest");b.request=g,a.onError(b)})),g.open("POST",b),c&&s(c,function(a,b){g.setRequestHeader(a,b)}),g.send(h(a.data)))}},ma:function(a){var b={};for(var c in a)if(a.hasOwnProperty(c)){var d=a[c];b[c]="function"==typeof d?d():d}return b},z:function(a){this.q[a]&&this.debug&&Function.prototype.apply.call(this.q[a],this.p,[].slice.call(arguments,1))},T:function(a,b){n(b)?delete this.j[a]:this.j[a]=t(this.j[a]||{},b)}},f.prototype.setUser=f.prototype.setUserContext,f.prototype.setReleaseContext=f.prototype.setRelease,b.exports=f}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{1:1,2:2,5:5,6:6,7:7}],4:[function(a,b,c){(function(c){var d=a(3),e="undefined"!=typeof window?window:"undefined"!=typeof c?c:"undefined"!=typeof self?self:{},f=e.Raven,g=new d;g.noConflict=function(){return e.Raven=f,g},g.afterLoad(),b.exports=g}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{3:3}],5:[function(a,b,c){(function(a){function c(a){return"object"==typeof a&&null!==a}function d(a){switch({}.toString.call(a)){case"[object Error]":return!0;case"[object Exception]":return!0;case"[object DOMException]":return!0;default:return a instanceof Error}}function e(a){return l()&&"[object ErrorEvent]"==={}.toString.call(a)}function f(a){return void 0===a}function g(a){return"function"==typeof a}function h(a){return"[object Object]"===Object.prototype.toString.call(a)}function i(a){return"[object String]"===Object.prototype.toString.call(a)}function j(a){return"[object Array]"===Object.prototype.toString.call(a)}function k(a){if(!h(a))return!1;for(var b in a)if(a.hasOwnProperty(b))return!1;return!0}function l(){try{return new ErrorEvent(""),!0}catch(a){return!1}}function m(){if(!("fetch"in E))return!1;try{return new Headers,new Request(""),new Response,!0}catch(a){return!1}}function n(a){function b(b,c){var d=a(b)||b;return c?c(d)||d:d}return b}function o(a,b){var c,d;if(f(a.length))for(c in a)s(a,c)&&b.call(null,c,a[c]);else if(d=a.length)for(c=0;c<d;c++)b.call(null,c,a[c])}function p(a,b){return b?(o(b,function(b,c){a[b]=c}),a):a}function q(a){return!!Object.isFrozen&&Object.isFrozen(a)}function r(a,b){return!b||a.length<=b?a:a.substr(0,b)+"…"}function s(a,b){return Object.prototype.hasOwnProperty.call(a,b)}function t(a){for(var b,c=[],d=0,e=a.length;d<e;d++)b=a[d],i(b)?c.push(b.replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1")):b&&b.source&&c.push(b.source);return new RegExp(c.join("|"),"i")}function u(a){var b=[];return o(a,function(a,c){b.push(encodeURIComponent(a)+"="+encodeURIComponent(c))}),b.join("&")}function v(a){if("string"!=typeof a)return{};var b=a.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/),c=b[6]||"",d=b[8]||"";return{protocol:b[2],host:b[4],path:b[5],relative:b[5]+c+d}}function w(){var a=E.crypto||E.msCrypto;if(!f(a)&&a.getRandomValues){var b=new Uint16Array(8);a.getRandomValues(b),b[3]=4095&b[3]|16384,b[4]=16383&b[4]|32768;var c=function(a){for(var b=a.toString(16);b.length<4;)b="0"+b;return b};return c(b[0])+c(b[1])+c(b[2])+c(b[3])+c(b[4])+c(b[5])+c(b[6])+c(b[7])}return"xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g,function(a){var b=16*Math.random()|0,c="x"===a?b:3&b|8;return c.toString(16)})}function x(a){for(var b,c=5,d=80,e=[],f=0,g=0,h=" > ",i=h.length;a&&f++<c&&(b=y(a),!("html"===b||f>1&&g+e.length*i+b.length>=d));)e.push(b),g+=b.length,a=a.parentNode;return e.reverse().join(h)}function y(a){var b,c,d,e,f,g=[];if(!a||!a.tagName)return"";if(g.push(a.tagName.toLowerCase()),a.id&&g.push("#"+a.id),b=a.className,b&&i(b))for(c=b.split(/\s+/),f=0;f<c.length;f++)g.push("."+c[f]);var h=["type","name","title","alt"];for(f=0;f<h.length;f++)d=h[f],e=a.getAttribute(d),e&&g.push("["+d+'="'+e+'"]');return g.join("")}function z(a,b){return!!(!!a^!!b)}function A(a,b){return f(a)&&f(b)}function B(a,b){return!z(a,b)&&(a=a.values[0],b=b.values[0],a.type===b.type&&a.value===b.value&&(!A(a.stacktrace,b.stacktrace)&&C(a.stacktrace,b.stacktrace)))}function C(a,b){if(z(a,b))return!1;var c=a.frames,d=b.frames;if(c.length!==d.length)return!1;for(var e,f,g=0;g<c.length;g++)if(e=c[g],f=d[g],e.filename!==f.filename||e.lineno!==f.lineno||e.colno!==f.colno||e["function"]!==f["function"])return!1;return!0}function D(a,b,c,d){var e=a[b];a[b]=c(e),a[b].L=!0,a[b].N=e,d&&d.push([a,b,e])}var E="undefined"!=typeof window?window:"undefined"!=typeof a?a:"undefined"!=typeof self?self:{};b.exports={isObject:c,isError:d,isErrorEvent:e,isUndefined:f,isFunction:g,isPlainObject:h,isString:i,isArray:j,isEmptyObject:k,supportsErrorEvent:l,supportsFetch:m,wrappedCallback:n,each:o,objectMerge:p,truncate:r,objectFrozen:q,hasKey:s,joinRegExp:t,urlencode:u,uuid4:w,htmlTreeAsString:x,htmlElementAsString:y,isSameException:B,isSameStacktrace:C,parseUrl:v,fill:D}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],6:[function(a,b,c){(function(c){function d(){return"undefined"==typeof document||null==document.location?"":document.location.href}var e=a(5),f={collectWindowErrors:!0,debug:!1},g="undefined"!=typeof window?window:"undefined"!=typeof c?c:"undefined"!=typeof self?self:{},h=[].slice,i="?",j=/^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/;f.report=function(){function a(a){m(),s.push(a)}function b(a){for(var b=s.length-1;b>=0;--b)s[b]===a&&s.splice(b,1)}function c(){n(),s=[]}function k(a,b){var c=null;if(!b||f.collectWindowErrors){for(var d in s)if(s.hasOwnProperty(d))try{s[d].apply(null,[a].concat(h.call(arguments,2)))}catch(e){c=e}if(c)throw c}}function l(a,b,c,g,h){var l=null,m=e.isErrorEvent(h)?h.error:h,n=e.isErrorEvent(a)?a.message:a;if(v)f.computeStackTrace.augmentStackTraceWithInitialElement(v,b,c,n),o();else if(m&&e.isError(m))l=f.computeStackTrace(m),k(l,!0);else{var p,r={url:b,line:c,column:g},s=void 0;if("[object String]"==={}.toString.call(n)){var p=n.match(j);p&&(s=p[1],n=p[2])}r.func=i,l={name:s,message:n,url:d(),stack:[r]},k(l,!0)}return!!q&&q.apply(this,arguments)}function m(){r||(q=g.onerror,g.onerror=l,r=!0)}function n(){r&&(g.onerror=q,r=!1,q=void 0)}function o(){var a=v,b=t;t=null,v=null,u=null,k.apply(null,[a,!1].concat(b))}function p(a,b){var c=h.call(arguments,1);if(v){if(u===a)return;o()}var d=f.computeStackTrace(a);if(v=d,u=a,t=c,setTimeout(function(){u===a&&o()},d.incomplete?2e3:0),b!==!1)throw a}var q,r,s=[],t=null,u=null,v=null;return p.subscribe=a,p.unsubscribe=b,p.uninstall=c,p}(),f.computeStackTrace=function(){function a(a){if("undefined"!=typeof a.stack&&a.stack){for(var b,c,e,f=/^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,g=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,h=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx(?:-web)|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,j=/(\S+) line (\d+)(?: > eval line \d+)* > eval/i,k=/\((\S*)(?::(\d+))(?::(\d+))\)/,l=a.stack.split("\n"),m=[],n=(/^(.*) is undefined$/.exec(a.message),0),o=l.length;n<o;++n){if(c=f.exec(l[n])){var p=c[2]&&0===c[2].indexOf("native"),q=c[2]&&0===c[2].indexOf("eval");q&&(b=k.exec(c[2]))&&(c[2]=b[1],c[3]=b[2],c[4]=b[3]),e={url:p?null:c[2],func:c[1]||i,args:p?[c[2]]:[],line:c[3]?+c[3]:null,column:c[4]?+c[4]:null}}else if(c=h.exec(l[n]))e={url:c[2],func:c[1]||i,args:[],line:+c[3],column:c[4]?+c[4]:null};else{if(!(c=g.exec(l[n])))continue;var q=c[3]&&c[3].indexOf(" > eval")>-1;q&&(b=j.exec(c[3]))?(c[3]=b[1],c[4]=b[2],c[5]=null):0!==n||c[5]||"undefined"==typeof a.columnNumber||(m[0].column=a.columnNumber+1),e={url:c[3],func:c[1]||i,args:c[2]?c[2].split(","):[],line:c[4]?+c[4]:null,column:c[5]?+c[5]:null}}!e.func&&e.line&&(e.func=i),m.push(e)}return m.length?{name:a.name,message:a.message,url:d(),stack:m}:null}}function b(a,b,c,d){var e={url:b,line:c};if(e.url&&e.line){if(a.incomplete=!1,e.func||(e.func=i),a.stack.length>0&&a.stack[0].url===e.url){if(a.stack[0].line===e.line)return!1;if(!a.stack[0].line&&a.stack[0].func===e.func)return a.stack[0].line=e.line,!1}return a.stack.unshift(e),a.partial=!0,!0}return a.incomplete=!0,!1}function c(a,g){for(var h,j,k=/function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,l=[],m={},n=!1,o=c.caller;o&&!n;o=o.caller)if(o!==e&&o!==f.report){if(j={url:null,func:i,line:null,column:null},o.name?j.func=o.name:(h=k.exec(o.toString()))&&(j.func=h[1]),"undefined"==typeof j.func)try{j.func=h.input.substring(0,h.input.indexOf("{"))}catch(p){}m[""+o]?n=!0:m[""+o]=!0,l.push(j)}g&&l.splice(0,g);var q={name:a.name,message:a.message,url:d(),stack:l};return b(q,a.sourceURL||a.fileName,a.line||a.lineNumber,a.message||a.description),q}function e(b,e){var g=null;e=null==e?0:+e;try{if(g=a(b))return g}catch(h){if(f.debug)throw h}try{if(g=c(b,e+1))return g}catch(h){if(f.debug)throw h}return{name:b.name,message:b.message,url:d()}}return e.augmentStackTraceWithInitialElement=b,e.computeStackTraceFromStackProp=a,e}(),b.exports=f}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{5:5}],7:[function(a,b,c){function d(a,b){for(var c=0;c<a.length;++c)if(a[c]===b)return c;return-1}function e(a,b,c,d){return JSON.stringify(a,g(b,d),c)}function f(a){var b={stack:a.stack,message:a.message,name:a.name};for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&(b[c]=a[c]);return b}function g(a,b){var c=[],e=[];return null==b&&(b=function(a,b){return c[0]===b?"[Circular ~]":"[Circular ~."+e.slice(0,d(c,b)).join(".")+"]"}),function(g,h){if(c.length>0){var i=d(c,this);~i?c.splice(i+1):c.push(this),~i?e.splice(i,1/0,g):e.push(g),~d(c,h)&&(h=b.call(this,g,h))}else c.push(h);return null==a?h instanceof Error?f(h):h:a.call(this,g,h)}}c=b.exports=e,c.getSerialize=g},{}]},{},[4])(4)}); -//# sourceMappingURL=raven.min.js.map
\ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index adfb148a9..f57ea6206 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -339,7 +339,7 @@ function generateBundler(opts, performBundle) { const browserifyOpts = assign({}, watchify.args, { entries: ['./app/scripts/'+opts.filename], plugin: 'browserify-derequire', - debug: debug, + debug: true, fullPaths: debug, }) @@ -405,13 +405,13 @@ function bundleTask(opts) { .pipe(buffer()) // sourcemaps // loads map from browserify file - .pipe(gulpif(debug, sourcemaps.init({ loadMaps: true }))) + .pipe(sourcemaps.init({ loadMaps: true })) // Minification .pipe(gulpif(opts.isBuild, uglify({ mangle: { reserved: [ 'MetamaskInpageProvider' ] }, }))) // writes .map file - .pipe(gulpif(debug, sourcemaps.write('./'))) + .pipe(sourcemaps.write(debug ? './' : '../../sourcemaps')) // write completed bundles .pipe(gulp.dest('./dist/firefox/scripts')) .pipe(gulp.dest('./dist/chrome/scripts')) diff --git a/mascara/src/app/first-time/index.css b/mascara/src/app/first-time/index.css index d7b146e51..5f8bbd4be 100644 --- a/mascara/src/app/first-time/index.css +++ b/mascara/src/app/first-time/index.css @@ -122,6 +122,10 @@ width: calc(100vw - 80px); } + .unique-image { + width: auto; + } + .create-password__title, .unique-image__title, .tou__title, @@ -221,10 +225,6 @@ max-width: 46rem; } -.backup-phrase { - width: 100%; -} - .create-password__title, .unique-image__title, .tou__title, @@ -674,7 +674,6 @@ button.backup-phrase__confirm-seed-option:hover { } .buy-ether__action-content-wrapper { - width: 360px; display: flex; flex-flow: column nowrap; } diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index da2f6bab9..c0bba53d6 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -10,6 +10,7 @@ import ImportSeedPhraseScreen from './import-seed-phrase-screen' import { onboardingBuyEthView, unMarkPasswordForgotten, + showModal, } from '../../../../ui/app/actions' class FirstTimeFlow extends Component { @@ -80,7 +81,7 @@ class FirstTimeFlow extends Component { renderScreen () { const {SCREEN_TYPE} = FirstTimeFlow const { - goToBuyEtherView, + openBuyEtherModal, address, restoreCreatePasswordScreen, forgottenPassword, @@ -131,7 +132,7 @@ class FirstTimeFlow extends Component { case SCREEN_TYPE.BACK_UP_PHRASE: return ( <BackupPhraseScreen - next={() => goToBuyEtherView(address)} + next={() => openBuyEtherModal()} /> ) default: @@ -167,7 +168,7 @@ export default connect( }), dispatch => ({ leaveImportSeedScreenState: () => dispatch(unMarkPasswordForgotten()), - goToBuyEtherView: address => dispatch(onboardingBuyEthView(address)), + openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})), }) )(FirstTimeFlow) diff --git a/package-lock.json b/package-lock.json index c7fd5e8ba..56f6c4305 100644 --- a/package-lock.json +++ b/package-lock.json @@ -182,6 +182,48 @@ "through2": "2.0.3" } }, + "@sentry/cli": { + "version": "1.30.3", + "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.30.3.tgz", + "integrity": "sha1-AtD3eBwe5eG+WkMSoyX76LGzcjE=", + "dev": true, + "requires": { + "https-proxy-agent": "2.2.0", + "node-fetch": "1.7.3", + "progress": "2.0.0", + "proxy-from-env": "1.0.0" + }, + "dependencies": { + "agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "dev": true, + "requires": { + "es6-promisify": "5.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "https-proxy-agent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz", + "integrity": "sha512-uUWcfXHvy/dwfM9bqa6AozvAjS32dZSTUYd/4SEpYKRg6LEcPLshksnQYRudM9AyNvUARMfAg5TLjUDyX/K4vA==", + "dev": true, + "requires": { + "agent-base": "4.2.0", + "debug": "3.1.0" + } + } + } + }, "@types/node": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.5.tgz", @@ -4946,11 +4988,20 @@ } }, "es6-promise": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", - "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", "dev": true }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "4.2.4" + } + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -17041,6 +17092,12 @@ } } }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -17364,6 +17421,11 @@ "eve-raphael": "0.5.0" } }, + "raven-js": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/raven-js/-/raven-js-3.24.0.tgz", + "integrity": "sha512-+/ygcWib8PXAE7Xq53j1tYxCgkzFyp9z05LYAKp2PA9KwO4Ek74q1tkGwZyPWI/FoXOgas6jNtQ7O3tdPif6uA==" + }, "raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", diff --git a/package.json b/package.json index 9573d39ba..09e90ec59 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "mascara": "gulp build && cross-env METAMASK_DEBUG=true node ./mascara/example/server", "dist": "npm run dist:clear && npm install && gulp dist", "dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect", - "test": "npm run lint && npm run test:coverage && npm run test:integration", + "test": "npm run test:unit && npm run test:integration && npm run lint", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", @@ -30,6 +30,13 @@ "test:mascara:build:ui": "browserify mascara/test/test-ui.js -o dist/mascara/ui.js", "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js", + "sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", + "sentry:release": "npm run sentry:release:new && npm run sentry:release:clean", + "sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE", + "sentry:release:clean": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE delete --all", + "sentry:upload": "npm run sentry:upload:source && npm run sentry:upload:maps", + "sentry:upload:source": "for FILEPATH in ./dist/chrome/scripts/*.js; do [ -e $FILEPATH ] || continue; export FILE=`basename $FILEPATH` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload $FILEPATH metamask/scripts/$FILE; done;", + "sentry:upload:maps": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps' --rewrite", "lint": "gulp lint", "lint:fix": "gulp lint:fix", "disc": "gulp disc --debug", @@ -145,6 +152,7 @@ "pumpify": "^1.3.4", "qrcode-npm": "0.0.3", "ramda": "^0.24.1", + "raven-js": "^3.24.0", "react": "^15.6.2", "react-addons-css-transition-group": "^15.6.0", "react-dom": "^15.6.2", @@ -180,6 +188,7 @@ "xtend": "^4.0.1" }, "devDependencies": { + "@sentry/cli": "^1.30.3", "babel-core": "^6.24.1", "babel-eslint": "^8.0.0", "babel-plugin-transform-async-to-generator": "^6.24.1", diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js index 42ed28dca..cc04beb21 100644 --- a/test/integration/lib/add-token.js +++ b/test/integration/lib/add-token.js @@ -26,7 +26,7 @@ async function runAddTokenFlowTest (assert, done) { assert.ok($('.token-list-item').length === 0, 'no tokens added') // Go to Add Token screen - let addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button') + let addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button') assert.ok(addTokenButton[0], 'add token button present') addTokenButton[0].click() @@ -34,26 +34,26 @@ async function runAddTokenFlowTest (assert, done) { let addTokenWrapper = await queryAsync($, '.add-token__wrapper') assert.ok(addTokenWrapper[0], 'add token wrapper renders') - let addTokenTitle = await queryAsync($, '.add-token__title') - assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct') + let addTokenTitle = await queryAsync($, '.add-token__header__title') + assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct') // Cancel Add Token - const cancelAddTokenButton = await queryAsync($, 'button.btn-cancel.add-token__button') + const cancelAddTokenButton = await queryAsync($, 'button.btn-secondary--lg.add-token__cancel-button') assert.ok(cancelAddTokenButton[0], 'cancel add token button present') cancelAddTokenButton.click() assert.ok($('.wallet-view')[0], 'cancelled and returned to account detail wallet view') // Return to Add Token Screen - addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button') + addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button') assert.ok(addTokenButton[0], 'add token button present') addTokenButton[0].click() // Verify Add Token Screen addTokenWrapper = await queryAsync($, '.add-token__wrapper') - addTokenTitle = await queryAsync($, '.add-token__title') + addTokenTitle = await queryAsync($, '.add-token__header__title') assert.ok(addTokenWrapper[0], 'add token wrapper renders') - assert.equal(addTokenTitle[0].textContent, 'Add Token', 'add token title is correct') + assert.equal(addTokenTitle[0].textContent, 'Add Tokens', 'add token title is correct') // Search for token const searchInput = await queryAsync($, 'input.add-token__input') @@ -68,7 +68,7 @@ async function runAddTokenFlowTest (assert, done) { tokenWrapper[0].click() // Click Next button - let nextButton = await queryAsync($, 'button.btn-clear.add-token__button') + let nextButton = await queryAsync($, 'button.btn-primary--lg') assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') nextButton[0].click() @@ -78,8 +78,8 @@ async function runAddTokenFlowTest (assert, done) { 'Would you like to add these tokens?', 'confirm add token rendered' ) - assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found') - $('button.btn-clear.add-token__button')[0].click() + assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') + $('button.btn-primary--lg')[0].click() // Verify added token image let heroBalance = await queryAsync($, '.hero-balance') @@ -87,13 +87,15 @@ async function runAddTokenFlowTest (assert, done) { assert.ok(tokenImageUrl.indexOf(heroBalance.find('img').attr('src')) > -1, 'token added') // Return to Add Token Screen - addTokenButton = await queryAsync($, 'button.btn-clear.wallet-view__add-token-button') + addTokenButton = await queryAsync($, 'button.btn-primary.wallet-view__add-token-button') assert.ok(addTokenButton[0], 'add token button present') addTokenButton[0].click() - const addCustom = await queryAsync($, '.add-token__add-custom') - assert.ok(addCustom[0], 'add custom token button present') - addCustom[0].click() + const addTokenTabs = await queryAsync($, '.add-token__header__tabs__tab') + assert.equal(addTokenTabs.length, 2, 'expected number of tabs') + assert.equal(addTokenTabs[1].textContent, 'Custom Token', 'Custom Token tab present') + assert.ok(addTokenTabs[1], 'add custom token tab present') + addTokenTabs[1].click() // Input token contract address const customInput = await queryAsync($, 'input.add-token__add-custom-input') @@ -101,14 +103,15 @@ async function runAddTokenFlowTest (assert, done) { reactTriggerChange(customInput[0]) // Click Next button - nextButton = await queryAsync($, 'button.btn-clear.add-token__button') + nextButton = await queryAsync($, 'button.btn-primary--lg') assert.equal(nextButton[0].textContent, 'Next', 'next button rendered') nextButton[0].click() // Verify symbol length error since contract address won't return symbol const errorMessage = await queryAsync($, '.add-token__add-custom-error-message') assert.ok(errorMessage[0], 'error rendered') - $('button.btn-cancel.add-token__button')[0].click() + + $('button.btn-secondary--lg')[0].click() // // Confirm Add token // assert.equal( @@ -116,8 +119,8 @@ async function runAddTokenFlowTest (assert, done) { // 'Would you like to add these tokens?', // 'confirm add token rendered' // ) - // assert.ok($('button.btn-clear.add-token__button')[0], 'confirm add token button found') - // $('button.btn-clear.add-token__button')[0].click() + // assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') + // $('button.btn-primary--lg')[0].click() // // Verify added token image // heroBalance = await queryAsync($, '.hero-balance') diff --git a/test/integration/lib/confirm-sig-requests.js b/test/integration/lib/confirm-sig-requests.js index 9737a2283..f1116d1a6 100644 --- a/test/integration/lib/confirm-sig-requests.js +++ b/test/integration/lib/confirm-sig-requests.js @@ -27,7 +27,7 @@ async function runConfirmSigRequestsTest(assert, done) { let confirmSigRowValue = await queryAsync($, '.request-signature__row-value') assert.ok(confirmSigRowValue[0].textContent.match(/^\#\sTerms\sof\sUse/)) - let confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button') + let confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') confirmSigSignButton[0].click() confirmSigHeadline = await queryAsync($, '.request-signature__headline') @@ -39,7 +39,7 @@ async function runConfirmSigRequestsTest(assert, done) { confirmSigRowValue = await queryAsync($, '.request-signature__row-value') assert.equal(confirmSigRowValue[0].textContent, '0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0') - confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button') + confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') confirmSigSignButton[0].click() confirmSigHeadline = await queryAsync($, '.request-signature__headline') @@ -49,7 +49,7 @@ async function runConfirmSigRequestsTest(assert, done) { assert.equal(confirmSigRowValue[0].textContent, 'Hi, Alice!') assert.equal(confirmSigRowValue[1].textContent, '1337') - confirmSigSignButton = await queryAsync($, '.request-signature__footer__sign-button') + confirmSigSignButton = await queryAsync($, 'button.btn-primary--lg') confirmSigSignButton[0].click() const txView = await queryAsync($, '.tx-view') diff --git a/test/integration/lib/mascara-first-time.js b/test/integration/lib/mascara-first-time.js index bcbc94ff6..564852585 100644 --- a/test/integration/lib/mascara-first-time.js +++ b/test/integration/lib/mascara-first-time.js @@ -57,9 +57,9 @@ async function runFirstTimeUsageTest (assert, done) { ;(await findAsync(app, '.first-time-flow__button')).click() // Deposit Ether Screen - const buyEthTitle = (await findAsync(app, '.buy-ether__title'))[0] - assert.equal(buyEthTitle.textContent, 'Deposit Ether', 'deposit ether screen') - ;(await findAsync(app, '.buy-ether__do-it-later')).click() + const depositEthTitle = (await findAsync(app, '.page-container__title'))[0] + assert.equal(depositEthTitle.textContent, 'Deposit Ether', 'deposit ether screen') + ;(await findAsync(app, '.page-container__header-close')).click() const menu = (await findAsync(app, '.account-menu__icon'))[0] menu.click() diff --git a/test/integration/lib/send-new-ui.js b/test/integration/lib/send-new-ui.js index 3fc7c79f8..163f3658c 100644 --- a/test/integration/lib/send-new-ui.js +++ b/test/integration/lib/send-new-ui.js @@ -21,13 +21,15 @@ global.ethQuery = { sendTransaction: () => {}, } +global.ethereumProvider = {} + async function runSendFlowTest(assert, done) { console.log('*** start runSendFlowTest') const selectState = await queryAsync($, 'select') selectState.val('send new ui') reactTriggerChange(selectState[0]) - const sendScreenButton = await queryAsync($, 'button.btn-clear.hero-balance-button') + const sendScreenButton = await queryAsync($, 'button.btn-primary.hero-balance-button') assert.ok(sendScreenButton[1], 'send screen button present') sendScreenButton[1].click() @@ -120,7 +122,7 @@ async function runSendFlowTest(assert, done) { 'send gas field should show customized gas total converted to USD' ) - const sendButton = await queryAsync($, 'button.btn-clear.page-container__footer-button') + const sendButton = await queryAsync($, 'button.btn-primary--lg.page-container__footer-button') assert.equal(sendButton[0].textContent, 'Next', 'next button rendered') sendButton[0].click() await timeout() @@ -160,7 +162,7 @@ async function runSendFlowTest(assert, done) { sendAmountFieldInputInEdit.val('1.0') reactTriggerChange(sendAmountFieldInputInEdit[0]) - const sendButtonInEdit = await queryAsync($, '.btn-clear.page-container__footer-button') + const sendButtonInEdit = await queryAsync($, '.btn-primary--lg.page-container__footer-button') assert.equal(sendButtonInEdit[0].textContent, 'Next', 'next button in edit rendered') sendButtonInEdit[0].click() diff --git a/test/unit/migrations/022-test.js b/test/unit/migrations/022-test.js new file mode 100644 index 000000000..1333d929d --- /dev/null +++ b/test/unit/migrations/022-test.js @@ -0,0 +1,32 @@ +const assert = require('assert') +const migration22 = require('../../../app/scripts/migrations/022') +const properTime = (new Date()).getTime() +const storage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + { "status": "submitted" }, + { "status": "submitted", "submittedTime": properTime }, + {"status": "confirmed"}, + ] + }, + }, +} + +describe('storage is migrated successfully where transactions that are submitted have submittedTimes', () => { + it('should add submittedTime key on the txMeta if appropriate', (done) => { + migration22.migrate(storage) + .then((migratedData) => { + const [txMeta1, txMeta2, txMeta3] = migratedData.data.TransactionController.transactions + assert.equal(migratedData.meta.version, 22) + // should have written a submitted time + assert(txMeta1.submittedTime) + // should not have written a submitted time because it already has one + assert.equal(txMeta2.submittedTime, properTime) + // should not have written a submitted time + assert(!txMeta3.submittedTime) + done() + }).catch(done) + }) +}) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index fa25168f1..eeba73e77 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -50,13 +50,13 @@ class JsonImportSubview extends Component { h('div.new-account-create-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel', { + h('button.btn-secondary.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ t('cancel'), ]), - h('button.new-account-create-form__button-create', { + h('button.btn-primary.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ t('import'), diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index bc9e9384e..13c8da722 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -48,13 +48,13 @@ PrivateKeyImportView.prototype.render = function () { h('div.new-account-import-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel.allcaps', { + h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => goHome(), }, [ t('cancel'), ]), - h('button.new-account-create-form__button-create.allcaps', { + h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ t('import'), diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index 8ef842a2a..c820cdf6d 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -20,7 +20,7 @@ class NewAccountCreateForm extends Component { render () { const { newAccountName, defaultAccountName } = this.state - + return h('div.new-account-create-form', [ @@ -38,13 +38,13 @@ class NewAccountCreateForm extends Component { h('div.new-account-create-form__buttons', {}, [ - h('button.new-account-create-form__button-cancel.allcaps', { + h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ t('cancel'), ]), - h('button.new-account-create-form__button-create.allcaps', { + h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.props.createAccount(newAccountName || defaultAccountName), }, [ t('create'), diff --git a/ui/app/actions.js b/ui/app/actions.js index bc7ee3d07..4a5962610 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -694,10 +694,10 @@ function updateSendFrom (from) { } } -function updateSendTo (to) { +function updateSendTo (to, nickname = '') { return { type: actions.UPDATE_SEND_TO, - value: to, + value: { to, nickname }, } } diff --git a/ui/app/add-token.js b/ui/app/add-token.js index b3a5bdc20..b4ea4a532 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -55,10 +55,10 @@ function AddTokenScreen () { customSymbol: '', customDecimals: '', searchQuery: '', - isCollapsed: true, selectedTokens: {}, errors: {}, autoFilled: false, + displayedTab: 'SEARCH', } this.tokenAddressDidChange = this.tokenAddressDidChange.bind(this) this.tokenSymbolDidChange = this.tokenSymbolDidChange.bind(this) @@ -192,7 +192,7 @@ AddTokenScreen.prototype.attemptToAutoFillTokenParams = async function (address) AddTokenScreen.prototype.renderCustomForm = function () { const { autoFilled, customAddress, customSymbol, customDecimals, errors } = this.state - return !this.state.isCollapsed && ( + return ( h('div.add-token__add-custom-form', [ h('div', { className: classnames('add-token__add-custom-field', { @@ -247,33 +247,36 @@ AddTokenScreen.prototype.renderTokenList = function () { }) const results = [...addressSearchResult, ...fuseSearchResult] - return Array(6).fill(undefined) - .map((_, i) => { - const { logo, symbol, name, address } = results[i] || {} - const tokenAlreadyAdded = this.checkExistingAddresses(address) - return Boolean(logo || symbol || name) && ( - h('div.add-token__token-wrapper', { - className: classnames({ - 'add-token__token-wrapper--selected': selectedTokens[address], - 'add-token__token-wrapper--disabled': tokenAlreadyAdded, - }), - onClick: () => !tokenAlreadyAdded && this.toggleToken(address, results[i]), - }, [ - h('div.add-token__token-icon', { - style: { - backgroundImage: logo && `url(images/contract/${logo})`, - }, - }), - h('div.add-token__token-data', [ - h('div.add-token__token-symbol', symbol), - h('div.add-token__token-name', name), - ]), - // tokenAlreadyAdded && ( - // h('div.add-token__token-message', 'Already added') - // ), - ]) - ) - }) + return h('div', [ + results.length > 0 && h('div.add-token__token-icons-title', t('popularTokens')), + h('div.add-token__token-icons-container', Array(6).fill(undefined) + .map((_, i) => { + const { logo, symbol, name, address } = results[i] || {} + const tokenAlreadyAdded = this.checkExistingAddresses(address) + return Boolean(logo || symbol || name) && ( + h('div.add-token__token-wrapper', { + className: classnames({ + 'add-token__token-wrapper--selected': selectedTokens[address], + 'add-token__token-wrapper--disabled': tokenAlreadyAdded, + }), + onClick: () => !tokenAlreadyAdded && this.toggleToken(address, results[i]), + }, [ + h('div.add-token__token-icon', { + style: { + backgroundImage: logo && `url(images/contract/${logo})`, + }, + }), + h('div.add-token__token-data', [ + h('div.add-token__token-symbol', symbol), + h('div.add-token__token-name', name), + ]), + // tokenAlreadyAdded && ( + // h('div.add-token__token-message', 'Already added') + // ), + ]) + ) + })), + ]) } AddTokenScreen.prototype.renderConfirmation = function () { @@ -300,7 +303,6 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token', [ h('div.add-token__wrapper', [ h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__title', t('addToken')), h('div.add-token__description', t('likeToAddTokens')), ]), h('div.add-token__content-container.add-token__confirmation-content', [ @@ -321,10 +323,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { ]), ]), h('div.add-token__buttons', [ - h('button.btn-cancel.add-token__button', { + h('button.btn-secondary--lg.add-token__cancel-button', { onClick: () => this.setState({ isShowingConfirmation: false }), }, t('back')), - h('button.btn-clear.add-token__button', { + h('button.btn-primary--lg', { onClick: () => addTokens(tokens).then(goHome), }, t('addTokens')), ]), @@ -332,52 +334,86 @@ AddTokenScreen.prototype.renderConfirmation = function () { ) } -AddTokenScreen.prototype.render = function () { - const { isCollapsed, errors, isShowingConfirmation } = this.state - const { goHome } = this.props +AddTokenScreen.prototype.displayTab = function (selectedTab) { + this.setState({ displayedTab: selectedTab }) +} - return isShowingConfirmation - ? this.renderConfirmation() - : ( - h('div.add-token', [ - h('div.add-token__wrapper', [ - h('div.add-token__title-container', [ - h('div.add-token__title', t('addToken')), - h('div.add-token__description', t('tokenWarning1')), - h('div.add-token__description', t('tokenSelection')), - ]), - h('div.add-token__content-container', [ - h('div.add-token__input-container', [ - h('input.add-token__input', { - type: 'text', - placeholder: t('search'), - onChange: e => this.setState({ searchQuery: e.target.value }), - }), - h('div.add-token__search-input-error-message', errors.tokenSelector), - ]), - h( - 'div.add-token__token-icons-container', - this.renderTokenList(), - ), +AddTokenScreen.prototype.renderTabs = function () { + const { displayedTab, errors } = this.state + + return displayedTab === 'CUSTOM_TOKEN' + ? this.renderCustomForm() + : h('div', [ + h('div.add-token__wrapper', [ + h('div.add-token__content-container', [ + h('div.add-token__info-box', [ + h('div.add-token__info-box__close'), + h('div.add-token__info-box__title', t('whatsThis')), + h('div.add-token__info-box__copy', t('keepTrackTokens')), + h('div.add-token__info-box__copy--blue', t('learnMore')), ]), - h('div.add-token__footers', [ - h('div.add-token__add-custom', { - onClick: () => this.setState({ isCollapsed: !isCollapsed }), - }, [ - t('addCustomToken'), - h(`i.fa.fa-angle-${isCollapsed ? 'down' : 'up'}`), - ]), - this.renderCustomForm(), + h('div.add-token__input-container', [ + h('input.add-token__input', { + type: 'text', + placeholder: t('searchTokens'), + onChange: e => this.setState({ searchQuery: e.target.value }), + }), + h('div.add-token__search-input-error-message', errors.tokenSelector), ]), + this.renderTokenList(), ]), - h('div.add-token__buttons', [ - h('button.btn-cancel.add-token__button', { - onClick: goHome, - }, t('cancel')), - h('button.btn-clear.add-token__button', { - onClick: this.onNext, - }, t('next')), + ]), + ]) +} + +AddTokenScreen.prototype.render = function () { + const { + isShowingConfirmation, + displayedTab, + } = this.state + const { goHome } = this.props + + return h('div.add-token', [ + h('div.add-token__header', [ + h('div.add-token__header__cancel', { + onClick: () => goHome(), + }, [ + h('i.fa.fa-angle-left.fa-lg'), + h('span', t('cancel')), ]), - ]) - ) + h('div.add-token__header__title', t('addTokens')), + !isShowingConfirmation && h('div.add-token__header__tabs', [ + + h('div.add-token__header__tabs__tab', { + className: classnames('add-token__header__tabs__tab', { + 'add-token__header__tabs__selected': displayedTab === 'SEARCH', + 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'SEARCH', + }), + onClick: () => this.displayTab('SEARCH'), + }, t('search')), + + h('div.add-token__header__tabs__tab', { + className: classnames('add-token__header__tabs__tab', { + 'add-token__header__tabs__selected': displayedTab === 'CUSTOM_TOKEN', + 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'CUSTOM_TOKEN', + }), + onClick: () => this.displayTab('CUSTOM_TOKEN'), + }, t('customToken')), + + ]), + ]), +// + isShowingConfirmation + ? this.renderConfirmation() + : this.renderTabs(), + + !isShowingConfirmation && h('div.add-token__buttons', [ + h('button.btn-secondary--lg.add-token__cancel-button', { + onClick: goHome, + }, t('cancel')), + h('button.btn-primary--lg.add-token__confirm-button', { + onClick: this.onNext, + }, t('next')), + ]), + ]) } diff --git a/ui/app/app.js b/ui/app/app.js index 6d9296131..d1b17ab5d 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -386,7 +386,7 @@ App.prototype.renderPrimary = function () { isUnlocked, } = props const isMascaraOnboarding = isMascara && isOnboarding - const isBetaUIOnboarding = betaUI && isOnboarding && !props.isPopup && !isRevealingSeedWords + const isBetaUIOnboarding = betaUI && isOnboarding if (!welcomeScreenSeen && betaUI && !isInitialized && !isUnlocked) { return h(WelcomeScreen) @@ -397,7 +397,7 @@ App.prototype.renderPrimary = function () { } // notices - if (!props.noActiveNotices) { + if (!props.noActiveNotices && !betaUI) { log.debug('rendering notice screen for unread notices.') return h(NoticeScreen, { notice: props.lastUnreadNotice, @@ -418,7 +418,7 @@ App.prototype.renderPrimary = function () { return h(HDRestoreVaultScreen, {key: 'HDRestoreVaultScreen'}) } else if (!props.isInitialized && !props.isUnlocked && !isRevealingSeedWords) { log.debug('rendering menu screen') - return props.isPopup + return !betaUI ? h(OldUIInitializeMenuScreen, {key: 'menuScreenInit'}) : h(InitializeMenuScreen, {key: 'menuScreenInit'}) } diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index d8384c19d..22ad98ce4 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -302,12 +302,16 @@ CustomizeGasModal.prototype.render = function () { }, [t('revert')]), h('div.send-v2__customize-gas__buttons', [ - h('div.send-v2__customize-gas__cancel.allcaps', { + h('button.btn-secondary.send-v2__customize-gas__cancel', { onClick: this.props.hideModal, + style: { + marginRight: '10px', + }, }, [t('cancel')]), - h(`div.send-v2__customize-gas__save${error ? '__error' : ''}.allcaps`, { + h('button.btn-primary.send-v2__customize-gas__save', { onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), + className: error && 'btn-primary--disabled', }, [t('save')]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index add67ea35..1b2d4009d 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -9,6 +9,7 @@ const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const t = require('../../i18n') +const ToAutoComplete = require('./send/to-autocomplete') module.exports = EnsInput @@ -22,12 +23,14 @@ EnsInput.prototype.render = function () { const props = this.props const opts = extend(props, { list: 'addresses', - onChange: () => { + onChange: (recipient) => { const network = this.props.network const networkHasEnsSupport = getNetworkEnsSupport(network) + if (!networkHasEnsSupport) return - const recipient = document.querySelector('input[name="address"]').value + props.onChange(recipient) + if (recipient.match(ensRE) === null) { return this.setState({ loadingEns: false, @@ -39,34 +42,13 @@ EnsInput.prototype.render = function () { this.setState({ loadingEns: true, }) - this.checkName() + this.checkName(recipient) }, }) return h('div', { - style: { width: '100%' }, + style: { width: '100%', position: 'relative' }, }, [ - h('input.large-input.send-screen-input', opts), - // The address book functionality. - h('datalist#addresses', - [ - // Corresponds to the addresses owned. - Object.keys(props.identities).map((key) => { - const identity = props.identities[key] - return h('option', { - value: identity.address, - label: identity.name, - key: identity.address, - }) - }), - // Corresponds to previously sent-to addresses. - props.addressBook.map((identity) => { - return h('option', { - value: identity.address, - label: identity.name, - key: identity.address, - }) - }), - ]), + h(ToAutoComplete, { ...opts }), this.ensIcon(), ]) } @@ -83,8 +65,7 @@ EnsInput.prototype.componentDidMount = function () { } } -EnsInput.prototype.lookupEnsName = function () { - const recipient = document.querySelector('input[name="address"]').value +EnsInput.prototype.lookupEnsName = function (recipient) { const { ensResolution } = this.state log.info(`ENS attempting to resolve name: ${recipient}`) @@ -130,8 +111,8 @@ EnsInput.prototype.ensIcon = function (recipient) { title: hoverText, style: { position: 'absolute', - padding: '9px', - transform: 'translatex(-40px)', + top: '16px', + left: '-25px', }, }, this.ensIconContents(recipient)) } diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index 75f989e86..927d73482 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -63,12 +63,12 @@ AccountDetailsModal.prototype.render = function () { h('div.account-modal-divider'), - h('button.btn-clear.account-modal__button', { + h('button.btn-primary.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), }, t('etherscanView')), // Holding on redesign for Export Private Key functionality - h('button.btn-clear.account-modal__button', { + h('button.btn-primary.account-modal__button', { onClick: () => showExportPrivateKeyModal(), }, t('exportPrivateKey')), diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index b642513d7..2de1240fc 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -94,7 +94,7 @@ DepositEtherModal.prototype.renderRow = function ({ ]), !hideButton && h('div.deposit-ether-modal__buy-row__button', [ - h('button.deposit-ether-modal__deposit-button', { + h('button.btn-primary--lg.deposit-ether-modal__deposit-button', { onClick: onButtonClick, }, [buttonLabel]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index 017177cfd..cf42e4fa2 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -81,14 +81,14 @@ ExportPrivateKeyModal.prototype.renderButton = function (className, onClick, lab ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, address, hideModal) { return h('div.export-private-key-buttons', {}, [ !privateKey && this.renderButton( - 'btn-cancel export-private-key__button export-private-key__button--cancel', + 'btn-secondary--lg export-private-key__button export-private-key__button--cancel', () => hideModal(), 'Cancel' ), (privateKey - ? this.renderButton('btn-clear export-private-key__button', () => hideModal(), t('done')) - : this.renderButton('btn-clear export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm')) + ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), t('done')) + : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm')) ), ]) diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index ccd87c0a4..f9276e8a5 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -87,6 +87,7 @@ function mapDispatchToProps (dispatch, ownProps) { amount: tokenAmountInHex, errors: { to: null, amount: null }, editingTransactionId: id, + token: ownProps.token, })) dispatch(actions.showSendTokenPage()) }, diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js index f4f6afb8f..9c0453a3b 100644 --- a/ui/app/components/pending-tx/index.js +++ b/ui/app/components/pending-tx/index.js @@ -64,13 +64,20 @@ PendingTx.prototype.componentWillMount = async function () { }) } - try { + // inspect tx data for supported special confirmation screens + let isTokenTransaction = false + if (txParams.data) { + const tokenData = abiDecoder.decodeMethod(txParams.data) + const { name: tokenMethodName } = tokenData || {} + isTokenTransaction = (tokenMethodName === 'transfer') + } + + if (isTokenTransaction) { const token = util.getContractAtAddress(txParams.to) const results = await Promise.all([ token.symbol(), token.decimals(), ]) - const [ symbol, decimals ] = results if (symbol[0] && decimals[0]) { @@ -83,11 +90,14 @@ PendingTx.prototype.componentWillMount = async function () { }) } else { this.setState({ - transactionType: TX_TYPES.SEND_ETHER, + transactionType: TX_TYPES.SEND_TOKEN, + tokenAddress: txParams.to, + tokenSymbol: null, + tokenDecimals: null, isFetching: false, }) } - } catch (e) { + } else { this.setState({ transactionType: TX_TYPES.SEND_ETHER, isFetching: false, diff --git a/ui/app/components/send/send-v2-container.js b/ui/app/components/send/send-v2-container.js index d1319b6dc..08c26a91f 100644 --- a/ui/app/components/send/send-v2-container.js +++ b/ui/app/components/send/send-v2-container.js @@ -69,13 +69,13 @@ function mapDispatchToProps (dispatch) { updateAndApproveTx: txParams => dispatch(actions.updateAndApproveTx(txParams)), updateTx: txData => dispatch(actions.updateTransaction(txData)), setSelectedAddress: address => dispatch(actions.setSelectedAddress(address)), - addToAddressBook: address => dispatch(actions.addToAddressBook(address)), + addToAddressBook: (address, nickname) => dispatch(actions.addToAddressBook(address, nickname)), updateGasTotal: newTotal => dispatch(actions.updateGasTotal(newTotal)), updateGasPrice: newGasPrice => dispatch(actions.updateGasPrice(newGasPrice)), updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)), updateSendTokenBalance: tokenBalance => dispatch(actions.updateSendTokenBalance(tokenBalance)), updateSendFrom: newFrom => dispatch(actions.updateSendFrom(newFrom)), - updateSendTo: newTo => dispatch(actions.updateSendTo(newTo)), + updateSendTo: (newTo, nickname) => dispatch(actions.updateSendTo(newTo, nickname)), updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)), updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)), diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 3f8c17932..5729f893c 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -236,7 +236,7 @@ ShapeshiftForm.prototype.render = function () { ]), - !depositAddress && h('button.shapeshift-form__shapeshift-buy-btn', { + !depositAddress && h('button.btn-primary--lg.shapeshift-form__shapeshift-buy-btn', { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 7bf34e7b6..810a52e55 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -223,10 +223,10 @@ SignatureRequest.prototype.renderFooter = function () { } return h('div.request-signature__footer', [ - h('button.request-signature__footer__cancel-button', { + h('button.btn-secondary--lg.request-signature__footer__cancel-button', { onClick: cancel, }, t('cancel')), - h('button.request-signature__footer__sign-button', { + h('button.btn-primary--lg', { onClick: sign, }, t('sign')), ]) diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index 96d776270..bf2065106 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -69,13 +69,13 @@ TxView.prototype.renderButtons = function () { return !selectedToken ? ( h('div.flex-row.flex-center.hero-balance-buttons', [ - h('button.btn-clear.hero-balance-button.allcaps', { + h('button.btn-primary.hero-balance-button', { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), }, t('deposit')), - h('button.btn-clear.hero-balance-button.allcaps', { + h('button.btn-primary.hero-balance-button', { style: { marginLeft: '0.8em', }, @@ -85,7 +85,7 @@ TxView.prototype.renderButtons = function () { ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ - h('button.btn-clear.hero-balance-button', { + h('button.btn-primary.hero-balance-button', { onClick: showSendTokenPage, }, t('send')), ]) diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 18452205c..2c6d7f784 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -168,7 +168,7 @@ WalletView.prototype.render = function () { h(TokenList), - h('button.btn-clear.wallet-view__add-token-button', { + h('button.btn-primary.wallet-view__add-token-button', { onClick: () => { showAddTokenPage() hideSidebar() diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss index 13020f62f..f5c1de67c 100644 --- a/ui/app/css/itcss/components/add-token.scss +++ b/ui/app/css/itcss/components/add-token.scss @@ -1,37 +1,118 @@ .add-token { width: 498px; + max-height: 805px; display: flex; flex-flow: column nowrap; - align-items: center; position: relative; z-index: 12; - font-family: 'DIN Next Light'; + font-family: 'Roboto'; + background: white; + border-radius: 8px; &__wrapper { background-color: $white; - box-shadow: 0 2px 4px 0 rgba($black, .08); display: flex; flex-flow: column nowrap; align-items: center; flex: 0 0 auto; } - &__title-container { + &__header { display: flex; flex-flow: column nowrap; - align-items: center; - padding: 30px 60px 12px; - border-bottom: 1px solid $gallery; + padding: 16px 16px 0px; + border-bottom: 1px solid $geyser; flex: 0 0 auto; + + &__cancel { + color: $dodger-blue; + display: flex; + align-items: center; + + span { + font-family: Roboto; + font-size: 16px; + line-height: 21px; + margin-left: 8px; + } + } + + &__title { + color: $tundora; + font-size: 32px; + font-weight: 500; + margin-top: 4px; + } + + &__tabs { + margin-left: 22px; + display: flex; + + &__tab { + height: 54px; + padding: 15px 10px; + color: $dusty-gray; + font-family: Roboto; + font-size: 18px; + line-height: 24px; + text-align: center; + } + + &__tab:first-of-type { + margin-right: 20px; + } + + &__unselected:hover { + color: $black; + border-bottom: none; + } + + &__selected { + color: $curious-blue; + border-bottom: 3px solid $curious-blue; + } + } } - &__title { - color: $scorpion; - font-size: 20px; - line-height: 26px; - text-align: center; - font-weight: 600; - margin-bottom: 12px; + &__info-box { + height: 96px; + margin: 20px 24px 0px; + border-radius: 4px; + background-color: $alabaster; + position: relative; + padding-left: 18px; + display: flex; + flex-flow: column; + + &__close::after { + content: '\00D7'; + font-size: 29px; + font-weight: 200; + color: $dusty-gray; + position: absolute; + right: 17px; + cursor: pointer; + } + + &__title { + color: $mid-gray; + font-family: Roboto; + font-size: 14px; + margin-top: 15px; + margin-bottom: 9px; + } + + &__copy, + &__copy--blue { + color: $mid-gray; + font-family: Roboto; + font-size: 12px; + line-height: 18px; + } + + &__copy--blue { + color: $curious-blue; + } } &__description { @@ -48,19 +129,17 @@ &__content-container { width: 100%; - border-bottom: 1px solid $gallery; } &__input-container { - padding: 11px 0; - width: 263px; - margin: 0 auto; + display: flex; position: relative; } &__search-input-error-message { position: absolute; bottom: -10px; + left: 22px; font-size: 12px; width: 100%; text-overflow: ellipsis; @@ -69,16 +148,24 @@ color: $red; } - &__input { - width: 100%; - border: 2px solid $gallery; + &__input, + &__add-custom-input { + height: 54px; + padding: 21px 6px; + border: 1px solid $geyser; border-radius: 4px; - padding: 5px 15px; - font-size: 14px; - line-height: 19px; + margin: 22px 24px; + position: relative; + flex: 1 0 auto; + color: $scorpion; + font-family: Roboto; + font-size: 16px; &::placeholder { - color: $silver; + color: $scorpion; + font-family: Roboto; + font-size: 16px; + line-height: 21px; } } @@ -115,13 +202,14 @@ &__add-custom-form { display: flex; flex-flow: column nowrap; - margin: 8px 0 51px; + margin: 40px 0 30px; } &__add-custom-field { - width: 290px; - margin: 0 auto; position: relative; + display: flex; + flex-flow: column; + flex: 1 0 auto; &--error { .add-token__add-custom-input { @@ -132,7 +220,8 @@ &__add-custom-error-message { position: absolute; - bottom: -21px; + bottom: 1px; + left: 22px; font-size: 12px; width: 100%; text-overflow: ellipsis; @@ -144,39 +233,50 @@ &__add-custom-label { font-size: 16px; line-height: 21px; - margin-bottom: 8px; + margin-left: 22px; + color: $scorpion; } &__add-custom-input { - width: 100%; - border: 1px solid $silver; - padding: 5px 15px; - font-size: 14px; - line-height: 19px; + margin-top: 6px; + font-size: 16px; &::placeholder { color: $silver; + font-size: 16px; } } &__add-custom-field + &__add-custom-field { - margin-top: 21px; + margin-top: 6px; } &__buttons { display: flex; flex-flow: row nowrap; - margin: 30px 0 51px; flex: 0 0 auto; align-items: center; justify-content: center; + padding-bottom: 30px; + padding-top: 20px; } - &__button { - flex: 1 0 141px; + &__confirm-button, + &__cancel-button { margin: 0 12px; - padding: 10px 22px; + padding: 10px 13px; height: 54px; + width: 133px; + margin-right: 1.2rem; + } + + &__token-icons-title { + color: #5B5D67; + font-family: Roboto; + font-size: 18px; + line-height: 24px; + margin-left: 24px; + margin-top: 8px; } &__token-icons-container { @@ -191,7 +291,7 @@ flex: 0 0 42.5%; align-items: center; padding: 12px; - margin: 2.5%; + margin: 0% 2.5% 1.5%; box-sizing: border-box; border-radius: 10px; cursor: pointer; @@ -305,13 +405,14 @@ top: 0; width: 100%; overflow: hidden; - height: 100%; + flex: 1 0 auto; &__wrapper { box-shadow: none !important; flex: 1 1 auto; width: 100%; - overflow-y: auto; + overflow-y: scroll; + height: 400px; } &__footers { @@ -334,7 +435,7 @@ } &__buttons { - padding: 12px 0; + padding: 1rem; margin: 0; border-top: 1px solid $gallery; width: 100%; diff --git a/ui/app/css/itcss/components/buttons.scss b/ui/app/css/itcss/components/buttons.scss index 8df8829f2..04e1ed96e 100644 --- a/ui/app/css/itcss/components/buttons.scss +++ b/ui/app/css/itcss/components/buttons.scss @@ -2,6 +2,76 @@ Buttons */ +.btn-primary, +.btn-primary--lg, +.btn-secondary, +.btn-secondary--lg { + background: $white; + display: flex; + justify-content: center; + align-items: center; + box-sizing: border-box; + border-radius: 4px; + font-size: 14px; + font-weight: 500; + transition: border-color .3s ease; + padding: 0 20px; + min-width: 140px; + text-transform: uppercase; +} + +.btn-primary, +.btn-primary--lg { + color: $curious-blue; + border: 2px solid $spindle; + + &:active { + background: $zumthor; + border-color: $curious-blue; + } + + &:hover { + border-color: $curious-blue; + } + + &--disabled, + &[disabled] { + cursor: auto; + opacity: .5; + pointer-events: none; + } +} + +.btn-secondary, +.btn-secondary--lg { + color: $scorpion; + border: 2px solid $dusty-gray; + + &:active { + background: $gallery; + border-color: $dusty-gray; + } + + &:hover { + border-color: $scorpion; + } + + &--disabled, + &[disabled] { + cursor: auto; + opacity: .5; + pointer-events: none; + } +} + +.btn-primary, .btn-secondary { + height: 44px; +} + +.btn-primary--lg, .btn-secondary--lg { + height: 54px; +} + .btn-green { background-color: #02c9b1; // TODO: reusable color in colors.css } @@ -130,20 +200,6 @@ button.btn-thin { font-size: 13px; } -.btn-secondary { - border: 1px solid #979797; - border-radius: 2px; - background-color: $white; - font-size: 16px; - line-height: 24px; - padding: 16px 42px; - - &[disabled] { - background-color: $white !important; - opacity: .5; - } -} - .btn-tertiary { border: 1px solid transparent; border-radius: 2px; diff --git a/ui/app/css/itcss/components/hero-balance.scss b/ui/app/css/itcss/components/hero-balance.scss index a3f051361..69cde8a0f 100644 --- a/ui/app/css/itcss/components/hero-balance.scss +++ b/ui/app/css/itcss/components/hero-balance.scss @@ -103,10 +103,11 @@ } .hero-balance-button { + min-width: initial; width: 6rem; @media #{$sub-mid-size-breakpoint-range} { - padding: 0.4rem; + padding: .4rem; width: 4rem; display: flex; flex: 1; diff --git a/ui/app/css/itcss/components/modal.scss b/ui/app/css/itcss/components/modal.scss index a8d5e8dc2..9ae3ea7fa 100644 --- a/ui/app/css/itcss/components/modal.scss +++ b/ui/app/css/itcss/components/modal.scss @@ -261,7 +261,7 @@ .account-modal__button { margin-top: 17px; padding: 10px 22px; - width: 235px; + width: 286px; } } @@ -341,9 +341,8 @@ .export-private-key__button { margin-top: 17px; - padding: 10px 22px; width: 141px; - height: 54px; + min-width: initial; } .export-private-key__button--cancel { @@ -765,15 +764,7 @@ } &__deposit-button, .shapeshift-form__shapeshift-buy-btn { - height: 54px; width: 257px; - border: 1px solid $curious-blue; - border-radius: 4px; - display: flex; - justify-content: center; - font-size: 16px; - color: $curious-blue; - background-color: $white; } .shapeshift-form-wrapper { diff --git a/ui/app/css/itcss/components/new-account.scss b/ui/app/css/itcss/components/new-account.scss index c2cefe4ad..aa7fed956 100644 --- a/ui/app/css/itcss/components/new-account.scss +++ b/ui/app/css/itcss/components/new-account.scss @@ -192,29 +192,8 @@ justify-content: space-between; } - &__button-cancel, - &__button-create { - height: 55px; + &__button { width: 150px; - border-radius: 2px; - background-color: #FFFFFF; - } - - &__button-cancel { - border: 1px solid $dusty-gray; - color: $dusty-gray; - font-family: Roboto; - font-size: 16px; - line-height: 21px; - text-align: center; + min-width: initial; } - - &__button-create { - border: 1px solid $curious-blue; - color: $curious-blue; - font-family: Roboto; - font-size: 16px; - line-height: 21px; - text-align: center; - } -}
\ No newline at end of file +} diff --git a/ui/app/css/itcss/components/request-signature.scss b/ui/app/css/itcss/components/request-signature.scss index d81099bfa..083481b8f 100644 --- a/ui/app/css/itcss/components/request-signature.scss +++ b/ui/app/css/itcss/components/request-signature.scss @@ -162,6 +162,7 @@ &__row { display: flex; flex-flow: column; + flex: 1 0 auto; } &__row-title { @@ -190,41 +191,19 @@ width: 100%; display: flex; align-items: center; - justify-content: space-evenly; + justify-content: center; font-size: 22px; position: relative; flex: 0 0 auto; border-top: 1px solid $geyser; + padding: 1.6rem; - &__cancel-button, - &__sign-button { - display: flex; - align-items: center; - justify-content: center; - flex: 1 0 auto; - font-family: Roboto; - font-size: 16px; - font-weight: 300; - height: 55px; - line-height: 32px; - cursor: pointer; - border-radius: 2px; - box-shadow: none; - max-width: 162px; - margin: 12px; + button { + width: 165px; } &__cancel-button { - background: none; - border: 1px solid $dusty-gray; - margin-right: 6px; - } - - &__sign-button { - background-color: $caribbean-green; - border-width: 0; - color: $white; - margin-left: 6px; + margin-right: 1.2rem; } } -}
\ No newline at end of file +} diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 263b362ca..89d2be891 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -782,7 +782,6 @@ &__buttons { display: flex; justify-content: space-between; - width: 181.75px; margin-right: 21.25px; } @@ -800,13 +799,8 @@ } &__cancel, &__save, &__save__error { - height: 34.64px; width: 85.74px; - border: 1px solid $dusty-gray; - border-radius: 2px; - font-family: 'DIN OT'; - font-size: 12px; - color: $dusty-gray; + min-width: initial; } &__save__error { diff --git a/ui/app/css/itcss/components/settings.scss b/ui/app/css/itcss/components/settings.scss index d60ebd934..dcc9b98d5 100644 --- a/ui/app/css/itcss/components/settings.scss +++ b/ui/app/css/itcss/components/settings.scss @@ -130,24 +130,32 @@ cursor: pointer; } -.settings__clear-button { - font-size: 16px; - border: 1px solid $curious-blue; - color: $curious-blue; - border-radius: 2px; - padding: 18px; - background-color: $white; - text-transform: uppercase; -} - -.settings__clear-button--red { - border: 1px solid $monzo; +.settings__button--red { + border-color: lighten($monzo, 10%); color: $monzo; + + &:active { + background: lighten($monzo, 55%); + border-color: $monzo; + } + + &:hover { + border-color: $monzo; + } } -.settings__clear-button--orange { - border: 1px solid rgba(247, 134, 28, 1); - color: rgba(247, 134, 28, 1); +.settings__button--orange { + border-color: lighten($ecstasy, 20%); + color: $ecstasy; + + &:active { + background: lighten($ecstasy, 40%); + border-color: $ecstasy; + } + + &:hover { + border-color: $ecstasy; + } } .settings__info-logo-wrapper { diff --git a/ui/app/css/itcss/generic/index.scss b/ui/app/css/itcss/generic/index.scss index 08e639d74..92321394b 100644 --- a/ui/app/css/itcss/generic/index.scss +++ b/ui/app/css/itcss/generic/index.scss @@ -132,7 +132,7 @@ input.large-input { height: 55px; font-size: 1rem; text-transform: uppercase; - margin-right: 1rem; + margin-right: 1.2rem; border-radius: 2px; &:last-of-type { diff --git a/ui/app/css/itcss/settings/variables.scss b/ui/app/css/itcss/settings/variables.scss index 640fd95b8..51548306f 100644 --- a/ui/app/css/itcss/settings/variables.scss +++ b/ui/app/css/itcss/settings/variables.scss @@ -51,6 +51,9 @@ $java: #29b6af; $wild-strawberry: #ff4a8d; $cornflower-blue: #7057ff; $saffron: #f6c343; +$dodger-blue: #3099f2; +$zumthor: #edf7ff; +$ecstasy: #f7861c; /* Z-Indicies diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index e6e02d057..9cba5e83b 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -39,6 +39,7 @@ function reduceMetamask (state, action) { maxModeOn: false, editingTransactionId: null, forceGasMin: null, + toNickname: '', }, coinOptions: {}, useBlockie: false, @@ -238,7 +239,8 @@ function reduceMetamask (state, action) { return extend(metamaskState, { send: { ...metamaskState.send, - to: action.value, + to: action.value.to, + toNickname: action.value.nickname, }, }) diff --git a/ui/app/selectors.js b/ui/app/selectors.js index d37c26f7e..2bdc39004 100644 --- a/ui/app/selectors.js +++ b/ui/app/selectors.js @@ -56,8 +56,9 @@ function getSelectedToken (state) { const tokens = state.metamask.tokens || [] const selectedTokenAddress = state.metamask.selectedTokenAddress const selectedToken = tokens.filter(({ address }) => address === selectedTokenAddress)[0] + const sendToken = state.metamask.send.token - return selectedToken || null + return selectedToken || sendToken || null } function getSelectedTokenExchangeRate (state) { diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index de71ce94c..620da73f8 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -7,7 +7,7 @@ const ethAbi = require('ethereumjs-abi') const ethUtil = require('ethereumjs-util') const FromDropdown = require('./components/send/from-dropdown') -const ToAutoComplete = require('./components/send/to-autocomplete') +const EnsInput = require('./components/ens-input') const CurrencyDisplay = require('./components/send/currency-display') const MemoTextArea = require('./components/send/memo-textarea') const GasFeeDisplay = require('./components/send/gas-fee-display-v2') @@ -253,7 +253,7 @@ SendTransactionScreen.prototype.renderFromRow = function () { ]) } -SendTransactionScreen.prototype.handleToChange = function (to) { +SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { const { updateSendTo, updateSendErrors, @@ -269,12 +269,12 @@ SendTransactionScreen.prototype.handleToChange = function (to) { toError = t('fromToSame') } - updateSendTo(to) + updateSendTo(to, nickname) updateSendErrors({ to: toError }) } SendTransactionScreen.prototype.renderToRow = function () { - const { toAccounts, errors, to } = this.props + const { toAccounts, errors, to, network } = this.props const { toDropdownOpen } = this.state @@ -289,7 +289,10 @@ SendTransactionScreen.prototype.renderToRow = function () { ]), h('div.send-v2__form-field', [ - h(ToAutoComplete, { + h(EnsInput, { + name: 'address', + placeholder: 'Recipient Address', + network, to, accounts: Object.entries(toAccounts).map(([key, account]) => account), dropdownOpen: toDropdownOpen, @@ -510,13 +513,13 @@ SendTransactionScreen.prototype.renderFooter = function () { const noErrors = !amountError && toError === null return h('div.page-container__footer', [ - h('button.btn-cancel.page-container__footer-button', { + h('button.btn-secondary--lg.page-container__footer-button', { onClick: () => { clearSend() goHome() }, }, t('cancel')), - h('button.btn-clear.page-container__footer-button', { + h('button.btn-primary--lg.page-container__footer-button', { disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), }, t('next')), @@ -538,11 +541,11 @@ SendTransactionScreen.prototype.render = function () { ) } -SendTransactionScreen.prototype.addToAddressBookIfNew = function (newAddress) { +SendTransactionScreen.prototype.addToAddressBookIfNew = function (newAddress, nickname = '') { const { toAccounts, addToAddressBook } = this.props if (!toAccounts.find(({ address }) => newAddress === address)) { // TODO: nickname, i.e. addToAddressBook(recipient, nickname) - addToAddressBook(newAddress) + addToAddressBook(newAddress, nickname) } } @@ -603,6 +606,7 @@ SendTransactionScreen.prototype.onSubmit = function (event) { updateTx, selectedToken, editingTransactionId, + toNickname, errors: { amount: amountError, to: toError }, } = this.props @@ -612,7 +616,7 @@ SendTransactionScreen.prototype.onSubmit = function (event) { return } - this.addToAddressBookIfNew(to) + this.addToAddressBookIfNew(to, toNickname) if (editingTransactionId) { const editedTx = this.getEditedTx() diff --git a/ui/app/settings.js b/ui/app/settings.js index 105cbb40b..78ca6c94b 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -200,7 +200,7 @@ class Settings extends Component { ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - h('button.settings__clear-button', { + h('button.btn-primary--lg.settings__button', { onClick (event) { window.logStateString((err, result) => { if (err) { @@ -225,7 +225,7 @@ class Settings extends Component { h('div.settings__content-item', t('revealSeedWords')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - h('button.settings__clear-button.settings__clear-button--red', { + h('button.btn-primary--lg.settings__button--red', { onClick (event) { event.preventDefault() revealSeedConfirmation() @@ -245,7 +245,7 @@ class Settings extends Component { h('div.settings__content-item', t('useOldUI')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - h('button.settings__clear-button.settings__clear-button--orange', { + h('button.btn-primary--lg.settings__button--orange', { onClick (event) { event.preventDefault() setFeatureFlagToBeta() @@ -264,7 +264,7 @@ class Settings extends Component { h('div.settings__content-item', t('resetAccount')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ - h('button.settings__clear-button.settings__clear-button--orange', { + h('button.btn-primary--lg.settings__button--orange', { onClick (event) { event.preventDefault() showResetAccountConfirmationModal() @@ -72,6 +72,15 @@ normalize-path "^2.0.1" through2 "^2.0.3" +"@sentry/cli@^1.30.3": + version "1.30.3" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-1.30.3.tgz#02d0f7781c1ee5e1be5a4312a325fbe8b1b37231" + dependencies: + https-proxy-agent "^2.1.1" + node-fetch "^1.7.3" + progress "2.0.0" + proxy-from-env "^1.0.0" + "@types/node@*": version "8.5.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-8.5.2.tgz#83b8103fa9a2c2e83d78f701a9aa7c9539739aa5" @@ -201,6 +210,12 @@ agent-base@2: extend "~3.0.0" semver "~5.0.1" +agent-base@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" + dependencies: + es6-promisify "^5.0.0" + ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" @@ -3711,6 +3726,16 @@ es6-map@^0.1.3: es6-symbol "~3.1.1" event-emitter "~0.3.5" +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + dependencies: + es6-promise "^4.0.3" + es6-set@~0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" @@ -5919,6 +5944,13 @@ https-proxy-agent@1: debug "2" extend "3" +https-proxy-agent@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz#7fbba856be8cd677986f42ebd3664f6317257887" + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + human-standard-token-abi@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/human-standard-token-abi/-/human-standard-token-abi-1.0.2.tgz#207d7846796ee5bb85fdd336e769cb38045b2ae0" @@ -7984,7 +8016,7 @@ nock@^9.0.14: qs "^6.5.1" semver "^5.3.0" -node-fetch@^1.0.1, node-fetch@~1.7.1: +node-fetch@^1.0.1, node-fetch@^1.7.3, node-fetch@~1.7.1: version "1.7.3" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" dependencies: @@ -8991,7 +9023,7 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" -progress@^2.0.0: +progress@2.0.0, progress@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" @@ -9067,6 +9099,10 @@ proxy-agent@~2.0.0: pac-proxy-agent "1" socks-proxy-agent "2" +proxy-from-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -9245,6 +9281,10 @@ raphael@^2.2.0: dependencies: eve-raphael "0.5.0" +raven-js@^3.24.0: + version "3.24.0" + resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.24.0.tgz#59464d8bc4b3812ae87a282e9bb98ecad5b4b047" + raw-body@2, raw-body@2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" |