From 14fa80c105373587b5f8c9837954a657e597fd6e Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 1 Jul 2020 05:52:36 -0230 Subject: [PATCH 01/14] Set min-height: 0 on page-container__bottom to fix overflow behaviour of add token list (#8874) --- ui/app/components/ui/page-container/index.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/app/components/ui/page-container/index.scss b/ui/app/components/ui/page-container/index.scss index 21f6ca0c5..98bbcd9d1 100644 --- a/ui/app/components/ui/page-container/index.scss +++ b/ui/app/components/ui/page-container/index.scss @@ -46,6 +46,7 @@ flex: 1; display: flex; flex-direction: column; + min-height: 0; } &__footer { From e4410724e9bc8950789346f856d3d45b53a560cd Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 14:08:43 -0300 Subject: [PATCH 02/14] Show `origin` in connect flow rather than site name (#8885) The designs for the connect flow show the site `origin` below the site icon rather than the site name. This was done for security reasons, and because the site name is often set to an unwieldy long string. This was accidentally undone in #8815 in the process of fixing a separate bug. The origin has now been restored. More specific PropTypes have been set on each use of the `domainMetadata` prop as well. --- ...ission-page-container-content.component.js | 9 ++++++++- .../permission-page-container.component.js | 8 +++++++- .../permissions-connect-header.component.js | 8 ++++---- .../choose-account.component.js | 9 ++++++++- .../permissions-connect.component.js | 10 ++++++++-- .../permissions-connect.container.js | 19 +++++++++++++------ .../permissions-redirect.component.js | 8 +++++++- 7 files changed, 55 insertions(+), 16 deletions(-) diff --git a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js index 268c973bf..feb6eaa9a 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container-content/permission-page-container-content.component.js @@ -7,7 +7,13 @@ import CheckBox from '../../../ui/check-box' export default class PermissionPageContainerContent extends PureComponent { static propTypes = { - domainMetadata: PropTypes.object.isRequired, + domainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), selectedPermissions: PropTypes.object.isRequired, onPermissionToggle: PropTypes.func.isRequired, selectedIdentities: PropTypes.array, @@ -145,6 +151,7 @@ export default class PermissionPageContainerContent extends PureComponent { ? t('allowExternalExtensionTo', [domainMetadata.extensionId]) : t('allowThisSiteTo') } + siteOrigin={domainMetadata.origin} />
{ this.renderRequestedPermissions() } diff --git a/ui/app/components/app/permission-page-container/permission-page-container.component.js b/ui/app/components/app/permission-page-container/permission-page-container.component.js index 3020b82b5..0779f2226 100644 --- a/ui/app/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/app/components/app/permission-page-container/permission-page-container.component.js @@ -14,7 +14,13 @@ export default class PermissionPageContainer extends Component { allIdentitiesSelected: PropTypes.bool, request: PropTypes.object, requestMetadata: PropTypes.object, - targetDomainMetadata: PropTypes.object.isRequired, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } static defaultProps = { diff --git a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js index e32f8a0b1..c1bc5d775 100644 --- a/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js +++ b/ui/app/components/app/permissions-connect-header/permissions-connect-header.component.js @@ -5,25 +5,25 @@ import SiteIcon from '../../ui/site-icon' export default class PermissionsConnectHeader extends Component { static propTypes = { icon: PropTypes.string, - iconName: PropTypes.string, + iconName: PropTypes.string.isRequired, + siteOrigin: PropTypes.string.isRequired, headerTitle: PropTypes.node, headerText: PropTypes.string, } static defaultProps = { icon: null, - iconName: '', headerTitle: '', headerText: '', } renderHeaderIcon () { - const { icon, iconName } = this.props + const { icon, iconName, siteOrigin } = this.props return (
-
{iconName}
+
{siteOrigin}
) } diff --git a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js index 720fd0bb0..606b2ecc9 100644 --- a/ui/app/pages/permissions-connect/choose-account/choose-account.component.js +++ b/ui/app/pages/permissions-connect/choose-account/choose-account.component.js @@ -25,7 +25,13 @@ export default class ChooseAccount extends Component { cancelPermissionsRequest: PropTypes.func.isRequired, permissionsRequestId: PropTypes.string.isRequired, selectedAccountAddresses: PropTypes.object.isRequired, - targetDomainMetadata: PropTypes.object, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } state = { @@ -197,6 +203,7 @@ export default class ChooseAccount extends Component { ? t('selectAccounts') : t('connectAccountOrCreate') } + siteOrigin={targetDomainMetadata.origin} /> {this.renderAccountsListHeader()} {this.renderAccountsList()} diff --git a/ui/app/pages/permissions-connect/permissions-connect.component.js b/ui/app/pages/permissions-connect/permissions-connect.component.js index 068d846dd..4119e04a6 100644 --- a/ui/app/pages/permissions-connect/permissions-connect.component.js +++ b/ui/app/pages/permissions-connect/permissions-connect.component.js @@ -31,7 +31,13 @@ export default class PermissionConnect extends Component { connectPath: PropTypes.string.isRequired, confirmPermissionPath: PropTypes.string.isRequired, page: PropTypes.string.isRequired, - targetDomainMetadata: PropTypes.object, + targetDomainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } static defaultProps = { @@ -95,7 +101,7 @@ export default class PermissionConnect extends Component { if ( permissionsRequest && - savedMetadata.name !== targetDomainMetadata?.name + savedMetadata.origin !== targetDomainMetadata?.origin ) { return { targetDomainMetadata } } diff --git a/ui/app/pages/permissions-connect/permissions-connect.container.js b/ui/app/pages/permissions-connect/permissions-connect.container.js index 31a727cb5..30a76ec55 100644 --- a/ui/app/pages/permissions-connect/permissions-connect.container.js +++ b/ui/app/pages/permissions-connect/permissions-connect.container.js @@ -43,13 +43,20 @@ const mapStateToProps = (state, ownProps) => { const nativeCurrency = getNativeCurrency(state) const domainMetadata = getDomainMetadata(state) - const targetDomainMetadata = origin - ? domainMetadata[origin] || { - origin, - name: (new URL(origin)).hostname, - icon: null, + + let targetDomainMetadata = null + if (origin) { + if (domainMetadata[origin]) { + targetDomainMetadata = { ...domainMetadata[origin], origin } + } else { + const targetUrl = new URL(origin) + targetDomainMetadata = { + host: targetUrl.host, + name: targetUrl.hostname, + origin, + } } - : null + } const accountsWithLabels = getAccountsWithLabels(state) diff --git a/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js b/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js index 3795f348c..ac39de104 100644 --- a/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js +++ b/ui/app/pages/permissions-connect/redirect/permissions-redirect.component.js @@ -33,5 +33,11 @@ export default function PermissionsRedirect ({ domainMetadata }) { } PermissionsRedirect.propTypes = { - domainMetadata: PropTypes.object.isRequired, + domainMetadata: PropTypes.shape({ + extensionId: PropTypes.string, + icon: PropTypes.string, + host: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + origin: PropTypes.string.isRequired, + }), } From dd209c8fd27cba3dd71d3f26f89899b408b65575 Mon Sep 17 00:00:00 2001 From: Erik Marks <25517051+rekmarks@users.noreply.github.com> Date: Thu, 2 Jul 2020 11:05:16 -0700 Subject: [PATCH 03/14] @metamask/test-dapp@2.2.0 (#8888) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 6e73f61c2..d8779ac5a 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "@babel/register": "^7.5.5", "@metamask/eslint-config": "^1.1.0", "@metamask/forwarder": "^1.1.0", - "@metamask/test-dapp": "^2.1.1", + "@metamask/test-dapp": "^2.2.0", "@sentry/cli": "^1.49.0", "@storybook/addon-actions": "^5.3.14", "@storybook/addon-backgrounds": "^5.3.14", diff --git a/yarn.lock b/yarn.lock index bf3cbe901..64dcd8121 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1711,10 +1711,10 @@ pump "^3.0.0" safe-event-emitter "^1.0.1" -"@metamask/test-dapp@^2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-2.1.1.tgz#c3b79f93c8a698b0904171c5143d0bca1307653a" - integrity sha512-ed0Ma9TLc+wkQYJK5TWslphp58JSi4Rer84LK2RxW1p4aS2LsGKS30pKMFUegj+g9g//7tyh+uFE87pXu4vPkA== +"@metamask/test-dapp@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@metamask/test-dapp/-/test-dapp-2.2.0.tgz#e48ea589db7ab028ea222ae47ee814c4687e02c6" + integrity sha512-KX8ZhR/yLBO6yzx/9/BDxHdrTV6nNoOb8LvpUGm8GiLu6jOXETKZj0qfgvL5quWnQ/LRJMEXeuOZWjtXgcVofg== "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" From 259d19850fd0692b1abfffe77bccaec2ee828eea Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Thu, 2 Jul 2020 12:58:12 -0700 Subject: [PATCH 04/14] Account for a custom nonce of zero (#8883) * Account for a custom nonce of zero * Remove default value for customNonceValue --- app/scripts/controllers/transactions/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 43e13b77a..344f9a972 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -443,14 +443,14 @@ export default class TransactionController extends EventEmitter { const txMeta = this.txStateManager.getTx(txId) const fromAddress = txMeta.txParams.from // wait for a nonce - let { customNonceValue = null } = txMeta + let { customNonceValue } = txMeta customNonceValue = Number(customNonceValue) nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams // if txMeta has lastGasPrice then it is a retry at same nonce with higher // gas price transaction and their for the nonce should not be calculated const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce - const customOrNonce = customNonceValue || nonce + const customOrNonce = (customNonceValue === 0) ? customNonceValue : customNonceValue || nonce txMeta.txParams.nonce = ethUtil.addHexPrefix(customOrNonce.toString(16)) // add nonce debugging information to txMeta From 68bcf38a65441db04645fb9895567bac29ec6e08 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Thu, 2 Jul 2020 15:13:23 -0500 Subject: [PATCH 05/14] fix language code format mismatch (#8889) --- ui/app/hooks/useTransactionTimeRemaining.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/hooks/useTransactionTimeRemaining.js b/ui/app/hooks/useTransactionTimeRemaining.js index c1d5ddd25..1f959c82f 100644 --- a/ui/app/hooks/useTransactionTimeRemaining.js +++ b/ui/app/hooks/useTransactionTimeRemaining.js @@ -50,7 +50,7 @@ export function useTransactionTimeRemaining ( const featureFlags = useSelector(getFeatureFlags) const transactionTimeFeatureActive = featureFlags?.transactionTime - const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style: 'narrow' }) + const rtf = new Intl.RelativeTimeFormat(locale.replace('_', '-'), { numeric: 'auto', style: 'narrow' }) // Memoize this value so it can be used as a dependency in the effect below const initialTimeEstimate = useMemo(() => { From a294ca71257d7c85111d13ea7e636aa23dd5d689 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 18:01:04 -0300 Subject: [PATCH 06/14] Set empty active tab if origin is invalid (#8890) The `activeTab` state is now set to an empty object if the `origin` of the active tab is missing or invalid. It can be invalid if the URL passed to the `URL` constructor is missing a scheme (e.g. `about: blank`). There are currently no cases where the rest of the data in `activeTab` is useful in the absence of an `origin`. This will make upcoming UI logic changes a bit simpler than they would be otherwise. Now we can assume that if any property is set on `activeTab`, it must have a valid `origin`. --- app/scripts/ui.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 5e8cc8e66..3b7b6ea3c 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -86,6 +86,11 @@ async function queryCurrentActiveTab (windowType) { const { title, url } = activeTab const { origin, protocol } = url ? new URL(url) : {} + if (!origin || origin === 'null') { + resolve({}) + return + } + resolve({ title, origin, protocol, url }) }) }) From d9a27fcf5220f214ccc8f48345eb62b630f507f1 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 18:26:30 -0300 Subject: [PATCH 07/14] Prevent showing connected accounts without origin (#8891) There was a case where the `activeTab.origin` was not set, yet the user could still navigate to the "Connected accounts" modal, which assumes that `activeTab.origin` is set. This would happen in Firefox when the user opened the popup on a page internal to Firefox (e.g. `about:blank`). The connected status indicator would still be shown, but the UI would crash when it was clicked. The connected status indicator is now hidden whenever `activeTab.origin` is falsy. The 'Unconnected account' alert has also been made impossible to trigger in that circumstance. --- ui/app/components/app/menu-bar/menu-bar.js | 2 +- ui/app/store/actions.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/app/components/app/menu-bar/menu-bar.js b/ui/app/components/app/menu-bar/menu-bar.js index 99bc50afa..282307f59 100644 --- a/ui/app/components/app/menu-bar/menu-bar.js +++ b/ui/app/components/app/menu-bar/menu-bar.js @@ -26,7 +26,7 @@ export default function MenuBar () { const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false) const origin = useSelector(getOriginOfCurrentTab) - const showStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && origin !== extension.runtime.id + const showStatus = getEnvironmentType() === ENVIRONMENT_TYPE_POPUP && origin && origin !== extension.runtime.id return (
diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index f139d71a0..d05b03214 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -1191,8 +1191,8 @@ export function showAccountDetail (address) { const activeTabOrigin = state.activeTab.origin const selectedAddress = getSelectedAddress(state) const permittedAccountsForCurrentTab = getPermittedAccountsForCurrentTab(state) - const currentTabIsConnectedToPreviousAddress = permittedAccountsForCurrentTab.includes(selectedAddress) - const currentTabIsConnectedToNextAddress = permittedAccountsForCurrentTab.includes(address) + const currentTabIsConnectedToPreviousAddress = Boolean(activeTabOrigin) && permittedAccountsForCurrentTab.includes(selectedAddress) + const currentTabIsConnectedToNextAddress = Boolean(activeTabOrigin) && permittedAccountsForCurrentTab.includes(address) const switchingToUnconnectedAddress = currentTabIsConnectedToPreviousAddress && !currentTabIsConnectedToNextAddress try { From b25f4bbe4abb69f839c8f4caef29a608404eb9f1 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 18:26:45 -0300 Subject: [PATCH 08/14] Prevent manually connecting to extension UI (#8893) The `activeTab.id` property is relied upon in the connected sites modal to prevent the user from manually connecting to the MetaMask extension itself. Unfortunately the `id` property was never set. `id` is now set on the `activeTab` state, so manually connecting to the extension UI is now impossible. --- app/scripts/ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 3b7b6ea3c..822ea73a4 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -83,7 +83,7 @@ async function queryCurrentActiveTab (windowType) { extension.tabs.query({ active: true, currentWindow: true }, (tabs) => { const [activeTab] = tabs - const { title, url } = activeTab + const { id, title, url } = activeTab const { origin, protocol } = url ? new URL(url) : {} if (!origin || origin === 'null') { @@ -91,7 +91,7 @@ async function queryCurrentActiveTab (windowType) { return } - resolve({ title, origin, protocol, url }) + resolve({ id, title, origin, protocol, url }) }) }) } From 4855d1b423c4ba0326601a5cd640e74ee7288911 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 19:18:22 -0300 Subject: [PATCH 09/14] Allow localized messages to not use substitutions (#8895) The `getMessage` function in `i18n-helper` was assuming that any substitutions passed into the transaction function were used by the corresponding localized message. However, some messages are intentionally ignoring substitutions passed in. This was done to simplify the UI logic, so the same substitutions could be passed in for many different messages, even if some don't use them. For example, `transactionCancelSuccess` is passed two substitutions but only uses the second one. `transactionErrored` is passed in two, but uses neither. `getMessage` has been updated to no longer make that assumption. It will now only throw an error if the localized message expects a substitution that was not given. A given substitution that is unused results in no error. --- ui/app/helpers/utils/i18n-helper.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ui/app/helpers/utils/i18n-helper.js b/ui/app/helpers/utils/i18n-helper.js index 496bd4524..a88995425 100644 --- a/ui/app/helpers/utils/i18n-helper.js +++ b/ui/app/helpers/utils/i18n-helper.js @@ -48,15 +48,17 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => { // perform substitutions if (hasSubstitutions) { const parts = phrase.split(/(\$\d)/g) - const partsToReplace = phrase.match(/(\$\d)/g) - - if (partsToReplace.length > substitutions.length) { - throw new Error(`Insufficient number of substitutions for message: '${phrase}'`) - } const substitutedParts = parts.map((part) => { const subMatch = part.match(/\$(\d)/) - return subMatch ? substitutions[Number(subMatch[1]) - 1] : part + if (!subMatch) { + return part + } + const substituteIndex = Number(subMatch[1]) - 1 + if (substitutions[substituteIndex]) { + return substitutions[substituteIndex] + } + throw new Error(`Insufficient number of substitutions for message: '${phrase}'`) }) phrase = hasReactSubstitutions From d3aa9f862079bcc6f589e4a49ff554158f415da2 Mon Sep 17 00:00:00 2001 From: Erik Marks <25517051+rekmarks@users.noreply.github.com> Date: Thu, 2 Jul 2020 17:33:49 -0700 Subject: [PATCH 10/14] eth-keyring-controller@6.0.1 (#8897) --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d8779ac5a..48bf624c7 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,7 @@ "eth-json-rpc-filters": "^4.1.1", "eth-json-rpc-infura": "^4.0.2", "eth-json-rpc-middleware": "^5.0.1", - "eth-keyring-controller": "^6.0.0", + "eth-keyring-controller": "^6.0.1", "eth-method-registry": "^1.2.0", "eth-phishing-detect": "^1.1.4", "eth-query": "^2.1.2", diff --git a/yarn.lock b/yarn.lock index 64dcd8121..3220fb053 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10215,10 +10215,10 @@ eth-keyring-controller@^5.3.0, eth-keyring-controller@^5.6.1: loglevel "^1.5.0" obs-store "^4.0.3" -eth-keyring-controller@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/eth-keyring-controller/-/eth-keyring-controller-6.0.0.tgz#4629c7b9f08e9c2f24ecfa0a296fc40ea0fa98af" - integrity sha512-+tdXXwTklX0KX50YwlSriTU/6Xc0Ury0jmcp1mMcJfKSBFSKyWCmPmrhdkMxE9LRd4lbt4qx9LS5wZ3Ia05cLg== +eth-keyring-controller@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eth-keyring-controller/-/eth-keyring-controller-6.0.1.tgz#6a4cdd5802b0587320c711be6c1752b2a88221aa" + integrity sha512-60j71F1HgLcvwzg7U5R45bA/kgQSUlmiZrsUIIhW4qS7QOYqJn0OQ64enf0ZaxMMPVVcKSfCDersYJiqm/yrlw== dependencies: bip39 "^2.4.0" bluebird "^3.5.0" From f5d4ab1cc19fdfe0a1eacc5efd42dba814a57168 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 21:34:48 -0300 Subject: [PATCH 11/14] Include relative time polyfill locale data (#8896) We were including the polyfill for the `Intl.RelativeTimeFormat` API, but we weren't including any locale data. This polyfill doesn't work without the locale data for whichever locale you're formatting. The data for all locales we support is now included. The locale data is loaded from disk as-needed (during app startup, and upon each change in locale). --- development/build/static.js | 16 ++++++++++++++++ ui/app/helpers/utils/i18n-helper.js | 18 ++++++++++++++++++ ui/app/store/actions.js | 5 +++-- ui/index.js | 7 ++++++- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/development/build/static.js b/development/build/static.js index de206d1f1..62dbeaa62 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -3,6 +3,8 @@ const path = require('path') const watch = require('gulp-watch') const glob = require('fast-glob') +const locales = require('../../app/_locales/index.json') + const { createTask, composeSeries } = require('./task') module.exports = createStaticAssetTasks @@ -45,6 +47,20 @@ const copyTargets = [ }, ] +const languageTags = new Set() +for (const locale of locales) { + const { code } = locale + const tag = code.split('_')[0] + languageTags.add(tag) +} + +for (const tag of languageTags) { + copyTargets.push({ + src: `./node_modules/@formatjs/intl-relativetimeformat/dist/locale-data/${tag}.json`, + dest: `intl/${tag}/relative-time-format-data.json`, + }) +} + const copyTargetsDev = [ ...copyTargets, { diff --git a/ui/app/helpers/utils/i18n-helper.js b/ui/app/helpers/utils/i18n-helper.js index a88995425..01a369229 100644 --- a/ui/app/helpers/utils/i18n-helper.js +++ b/ui/app/helpers/utils/i18n-helper.js @@ -79,3 +79,21 @@ export async function fetchLocale (localeCode) { } } +const relativeTimeFormatLocaleData = new Set() + +export async function loadRelativeTimeFormatLocaleData (localeCode) { + const languageTag = localeCode.split('_')[0] + if ( + Intl.RelativeTimeFormat && + typeof Intl.RelativeTimeFormat.__addLocaleData === 'function' && + !relativeTimeFormatLocaleData.has(languageTag) + ) { + const localeData = await fetchRelativeTimeFormatData(languageTag) + Intl.RelativeTimeFormat.__addLocaleData(localeData) + } +} + +async function fetchRelativeTimeFormatData (languageTag) { + const response = await window.fetch(`./intl/${languageTag}/relative-time-format-data.json`) + return await response.json() +} diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index d05b03214..dd9188687 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -4,7 +4,7 @@ import getBuyEthUrl from '../../../app/scripts/lib/buy-eth-url' import { checksumAddress } from '../helpers/utils/util' import { calcTokenBalance, estimateGas } from '../pages/send/send.utils' import ethUtil from 'ethereumjs-util' -import { fetchLocale } from '../helpers/utils/i18n-helper' +import { fetchLocale, loadRelativeTimeFormatLocaleData } from '../helpers/utils/i18n-helper' import { getMethodDataAsync } from '../helpers/utils/transactions.util' import { fetchSymbolAndDecimals } from '../helpers/utils/token-util' import switchDirection from '../helpers/utils/switch-direction' @@ -2012,8 +2012,9 @@ export function setIpfsGateway (val) { } export function updateCurrentLocale (key) { - return (dispatch) => { + return async (dispatch) => { dispatch(showLoadingIndication()) + await loadRelativeTimeFormatLocaleData(key) return fetchLocale(key) .then((localeMessages) => { log.debug(`background.setCurrentLocale`) diff --git a/ui/index.js b/ui/index.js index 8f868f317..44f5fd500 100644 --- a/ui/index.js +++ b/ui/index.js @@ -10,7 +10,7 @@ import txHelper from './lib/tx-helper' import { getEnvironmentType } from '../app/scripts/lib/util' import { ALERT_TYPES } from '../app/scripts/controllers/alert' import { ENVIRONMENT_TYPE_POPUP } from '../app/scripts/lib/enums' -import { fetchLocale } from './app/helpers/utils/i18n-helper' +import { fetchLocale, loadRelativeTimeFormatLocaleData } from './app/helpers/utils/i18n-helper' import switchDirection from './app/helpers/utils/switch-direction' import { getPermittedAccountsForCurrentTab, getSelectedAddress } from './app/selectors' import { ALERT_STATE } from './app/ducks/alerts/unconnected-account' @@ -48,6 +48,11 @@ async function startApp (metamaskState, backgroundConnection, opts) { : {} const enLocaleMessages = await fetchLocale('en') + await loadRelativeTimeFormatLocaleData('en') + if (metamaskState.currentLocale) { + await loadRelativeTimeFormatLocaleData(metamaskState.currentLocale) + } + if (metamaskState.textDirection === 'rtl') { await switchDirection('rtl') } From 3832d694a45d05fe91631df8016a05057f9d7de3 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 21:51:41 -0300 Subject: [PATCH 12/14] Replace percentage opacity value (#8898) The CSS `opacity` rule accepts percentages on newer browsers, but some older browser versions we support (e.g. Firefox v60) doesn't support them. A number is now used instead, which is supported by all browsers we support. --- ui/app/components/ui/popover/index.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/app/components/ui/popover/index.scss b/ui/app/components/ui/popover/index.scss index 1742c7754..a34f99e50 100644 --- a/ui/app/components/ui/popover/index.scss +++ b/ui/app/components/ui/popover/index.scss @@ -73,7 +73,7 @@ width: 100%; height: 100%; background: black; - opacity: 20%; + opacity: .2; } &-content { From 03bbd400d98430c232f0aebd5095486e20dc2345 Mon Sep 17 00:00:00 2001 From: MetaMask Bot Date: Thu, 2 Jul 2020 17:16:23 +0000 Subject: [PATCH 13/14] Version v8.0.1 --- CHANGELOG.md | 2 ++ app/manifest/_base.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa6b76751..044949ed7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Develop Branch +## 8.0.1 Thu Jul 02 2020 + ## 8.0.0 Mon Jun 23 2020 - [#7004](https://github.com/MetaMask/metamask-extension/pull/7004): Add permission system - [#7261](https://github.com/MetaMask/metamask-extension/pull/7261): Search accounts by name diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 83ad55d90..1d567a273 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "8.0.0", + "version": "8.0.1", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", From 66d9c824e51ee8902c55856851273e7c58771be0 Mon Sep 17 00:00:00 2001 From: Mark Stacey Date: Thu, 2 Jul 2020 22:21:15 -0300 Subject: [PATCH 14/14] Update changelog for v8.0.1 (#8899) --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 044949ed7..c80389505 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ ## Current Develop Branch ## 8.0.1 Thu Jul 02 2020 +- [#8874](https://github.com/MetaMask/metamask-extension/pull/8874): Fx overflow behaviour of add token list +- [#8885](https://github.com/MetaMask/metamask-extension/pull/8885): Show `origin` in connect flow rather than site name +- [#8883](https://github.com/MetaMask/metamask-extension/pull/8883): Allow setting a custom nonce of zero +- [#8889](https://github.com/MetaMask/metamask-extension/pull/8889): Fix language code format mismatch +- [#8891](https://github.com/MetaMask/metamask-extension/pull/8891): Prevent showing connected accounts without origin +- [#8893](https://github.com/MetaMask/metamask-extension/pull/8893): Prevent manually connecting to extension UI +- [#8895](https://github.com/MetaMask/metamask-extension/pull/8895): Allow localized messages to not use substitutions +- [#8897](https://github.com/MetaMask/metamask-extension/pull/8897): Update eth-keyring-controller to fix erasure of imported/hardware account names +- [#8896](https://github.com/MetaMask/metamask-extension/pull/8896): Include relative time polyfill locale data +- [#8898](https://github.com/MetaMask/metamask-extension/pull/8898): Replace percentage opacity value ## 8.0.0 Mon Jun 23 2020 - [#7004](https://github.com/MetaMask/metamask-extension/pull/7004): Add permission system