diff --git a/.github/scripts/label-prs.ts b/.github/scripts/label-prs.ts new file mode 100644 index 000000000000..8d05779d7bd9 --- /dev/null +++ b/.github/scripts/label-prs.ts @@ -0,0 +1,177 @@ +import * as core from '@actions/core'; +import { context, getOctokit } from '@actions/github'; +import { GitHub } from '@actions/github/lib/utils'; + +main().catch((error: Error): void => { + console.error(error); + process.exit(1); +}); + +async function main(): Promise { + const token = process.env.GITHUB_TOKEN; + + if (!token) { + core.setFailed('GITHUB_TOKEN not found'); + process.exit(1); + } + + const octokit = getOctokit(token); + + const headRef = context.payload.pull_request?.head.ref || ''; + + let issueNumber = await getIssueNumberFromPullRequestBody(); + if (issueNumber === "") { + bailIfIsBranchNameInvalid(headRef); + bailIfIsNotFeatureBranch(headRef); + issueNumber = getIssueNumberFromBranchName(headRef); + } + + if (Number(issueNumber) === 0) { + process.exit(0); + } + + await updateLabels(octokit, issueNumber); +} + +async function getIssueNumberFromPullRequestBody(): Promise { + console.log("Checking if the PR's body references an issue..."); + + let ISSUE_LINK_IN_PR_DESCRIPTION_REGEX = + /(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\s#\d+/gi; + + const prBody = await getPullRequestBody(); + + let matches = prBody.match(ISSUE_LINK_IN_PR_DESCRIPTION_REGEX); + if (!matches || matches?.length === 0) { + console.log( + 'No direct link can be drawn between the PR and an issue from the PR body because no issue number was referenced.', + ); + return ""; + } + + if (matches?.length > 1) { + console.log( + 'No direct link can be drawn between the PR and an issue from the PR body because more than one issue number was referenced.', + ); + return ""; + } + + const ISSUE_NUMBER_REGEX = /\d+/; + const issueNumber = matches[0].match(ISSUE_NUMBER_REGEX)?.[0] || ''; + + console.log(`Found issue number ${issueNumber} in PR body.`); + + return issueNumber; +} + +async function getPullRequestBody(): Promise { + if (context.eventName !== 'pull_request') { + console.log('This action should only run on pull_request events.'); + process.exit(1); + } + + const prBody = context.payload.pull_request?.body || ''; + return prBody; +} + +function bailIfIsBranchNameInvalid(branchName: string): void { + const BRANCH_REGEX = + /^(main|develop|(ci|chore|docs|feat|feature|fix|perf|refactor|revert|style)\/\d*(?:[-](?![-])\w*)*|Version-v\d+\.\d+\.\d+)$/; + const isValidBranchName = new RegExp(BRANCH_REGEX).test(branchName); + + if (!isValidBranchName) { + console.log('This branch name does not follow the convention.'); + console.log( + 'Here are some example branch names that are accepted: "fix/123-description", "feat/123-longer-description", "feature/123", "main", "develop", "Version-v10.24.2".', + ); + console.log( + 'No issue could be linked to this PR, so no labels were copied', + ); + + process.exit(0); + } +} + +function bailIfIsNotFeatureBranch(branchName: string): void { + if ( + branchName === 'main' || + branchName === 'develop' || + branchName.startsWith('Version-v') + ) { + console.log(`${branchName} is not a feature branch.`); + console.log( + 'No issue could be linked to this PR, so no labels were copied', + ); + process.exit(0); + } +} + +async function updateLabels(octokit: InstanceType, issueNumber: string): Promise { + interface ILabel { + name: string; + }; + + const owner = context.repo.owner; + const repo = context.repo.repo; + + const issue = await octokit.rest.issues.get({ + owner: owner, + repo: repo, + issue_number: Number(issueNumber), + }); + + const getNameFromLabel = (label: ILabel): string => label.name + + const issueLabels = issue.data.labels.map(label => getNameFromLabel(label as ILabel)); + + const prNumber = context.payload.number; + + const pr = await octokit.rest.issues.get({ + owner: owner, + repo: repo, + issue_number: prNumber, + }); + + const startingPRLabels = pr.data.labels.map(label => getNameFromLabel(label as ILabel)); + + const dedupedFinalPRLabels = [ + ...new Set([...startingPRLabels, ...issueLabels]), + ]; + + const hasIssueAdditionalLabels = !sortedArrayEqual( + startingPRLabels, + dedupedFinalPRLabels, + ); + if (hasIssueAdditionalLabels) { + await octokit.rest.issues.update({ + owner, + repo, + issue_number: prNumber, + labels: dedupedFinalPRLabels, + }); + } +} + +function getIssueNumberFromBranchName(branchName: string): string { + console.log('Checking if the branch name references an issue...'); + + let issueNumber: string; + if (branchName.split('/').length > 1) { + issueNumber = branchName.split('/')[1].split('-')[0]; + } else { + issueNumber = branchName.split('-')[0]; + } + + console.log(`Found issue number ${issueNumber} in branch name.`); + + return issueNumber; +} + +function sortedArrayEqual(array1: string[], array2: string[]): boolean { + const lengthsAreEqual = array1.length === array2.length; + const everyElementMatchesByIndex = array1.every( + (value: string, index: number): boolean => value === array2[index], + ); + + return lengthsAreEqual && everyElementMatchesByIndex; +} diff --git a/.github/workflows/label-prs.yml b/.github/workflows/label-prs.yml new file mode 100644 index 000000000000..f915a881abc9 --- /dev/null +++ b/.github/workflows/label-prs.yml @@ -0,0 +1,32 @@ +name: Label PR + +on: + pull_request: + types: [assigned, opened, edited, synchronize, reopened] + +jobs: + label-pr: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + + - name: Install Yarn + run: npm install -g yarn + + - name: Install dependencies + run: yarn + + - name: Run PR labelling script + run: npm run label-prs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/app/scripts/background.js b/app/scripts/background.js index 082a13b6734d..2b04d2cd8cfe 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -9,6 +9,9 @@ import debounce from 'debounce-stream'; import log from 'loglevel'; import browser from 'webextension-polyfill'; import { storeAsStream } from '@metamask/obs-store'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import { ApprovalType } from '@metamask/controller-utils'; +///: END:ONLY_INCLUDE_IN import PortStream from 'extension-port-stream'; import { ethErrors } from 'eth-rpc-errors'; @@ -18,9 +21,6 @@ import { ENVIRONMENT_TYPE_FULLSCREEN, EXTENSION_MESSAGES, PLATFORM_FIREFOX, - ///: BEGIN:ONLY_INCLUDE_IN(snaps) - MESSAGE_TYPE, - ///: END:ONLY_INCLUDE_IN } from '../../shared/constants/app'; import { REJECT_NOTIFICATION_CLOSE, @@ -713,7 +713,9 @@ export function setupController( // User Interface setup // - updateBadge(); + controller.txController.initApprovals().then(() => { + updateBadge(); + }); controller.txController.on( METAMASK_CONTROLLER_EVENTS.UPDATE_BADGE, updateBadge, @@ -800,11 +802,11 @@ export function setupController( ({ id, type }) => { switch (type) { ///: BEGIN:ONLY_INCLUDE_IN(snaps) - case MESSAGE_TYPE.SNAP_DIALOG_ALERT: - case MESSAGE_TYPE.SNAP_DIALOG_PROMPT: + case ApprovalType.SnapDialogAlert: + case ApprovalType.SnapDialogPrompt: controller.approvalController.accept(id, null); break; - case MESSAGE_TYPE.SNAP_DIALOG_CONFIRMATION: + case ApprovalType.SnapDialogConfirmation: controller.approvalController.accept(id, false); break; ///: END:ONLY_INCLUDE_IN diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 63eaf085dcc5..92166eac28a3 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -2,6 +2,7 @@ import EventEmitter from 'events'; import { ObservableStore } from '@metamask/obs-store'; import { v4 as uuid } from 'uuid'; import log from 'loglevel'; +import { ApprovalType } from '@metamask/controller-utils'; import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; import { MINUTE } from '../../../shared/constants/time'; import { AUTO_LOCK_TIMEOUT_ALARM } from '../../../shared/constants/alarms'; @@ -13,8 +14,6 @@ import { ORIGIN_METAMASK, } from '../../../shared/constants/app'; -const APPROVAL_REQUEST_TYPE = 'unlock'; - export default class AppStateController extends EventEmitter { /** * @param {object} opts @@ -408,7 +407,7 @@ export default class AppStateController extends EventEmitter { { id: this._approvalRequestId, origin: ORIGIN_METAMASK, - type: APPROVAL_REQUEST_TYPE, + type: ApprovalType.Unlock, }, true, ) diff --git a/app/scripts/controllers/network/network-controller.ts b/app/scripts/controllers/network/network-controller.ts index 463565a5484e..4a79eaf1ad67 100644 --- a/app/scripts/controllers/network/network-controller.ts +++ b/app/scripts/controllers/network/network-controller.ts @@ -307,10 +307,9 @@ function isErrorWithCode(error: unknown): error is { code: string | number } { * @param value - The value to check. */ function assertNetworkId(value: any): asserts value is NetworkId { - assert( - /^\d+$/u.test(value) && !Number.isNaN(Number(value)), - 'value is not a number', - ); + if (!/^\d+$/u.test(value) || Number.isNaN(Number(value))) { + throw new Error('value is not a number'); + } } /** @@ -624,12 +623,14 @@ export class NetworkController extends EventEmitter { supportsEIP1559 = results[1]; networkStatus = NetworkStatus.Available; } catch (error) { - if (isErrorWithCode(error) && isErrorWithMessage(error)) { + if (isErrorWithCode(error)) { let responseBody; - try { - responseBody = JSON.parse(error.message); - } catch { - // error.message must not be JSON + if (isInfura && isErrorWithMessage(error)) { + try { + responseBody = JSON.parse(error.message); + } catch { + // error.message must not be JSON + } } if ( diff --git a/app/scripts/controllers/network/provider-api-tests/shared-tests.ts b/app/scripts/controllers/network/provider-api-tests/shared-tests.ts index 6337bb56a789..cf34302ceeda 100644 --- a/app/scripts/controllers/network/provider-api-tests/shared-tests.ts +++ b/app/scripts/controllers/network/provider-api-tests/shared-tests.ts @@ -295,9 +295,8 @@ export function testsForProviderType(providerType: ProviderType) { // tests on the core side. { name: 'net_listening', numberOfParameters: 0 }, - // TODO: Methods to add back when we add testing for subscribe middleware - // { name: 'eth_subscribe', numberOfParameters: 1 }, - // { name: 'eth_unsubscribe', numberOfParameters: 1 }, + { name: 'eth_subscribe', numberOfParameters: 1 }, + { name: 'eth_unsubscribe', numberOfParameters: 1 }, { name: 'custom_rpc_method', numberOfParameters: 1 }, { name: 'net_peerCount', numberOfParameters: 0 }, { name: 'parity_nextNonce', numberOfParameters: 1 }, diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index e31215171bd4..cd962e566d8c 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -5,6 +5,7 @@ import EthQuery from 'ethjs-query'; import { ethErrors } from 'eth-rpc-errors'; import { Common, Hardfork } from '@ethereumjs/common'; import { TransactionFactory } from '@ethereumjs/tx'; +import { ApprovalType } from '@metamask/controller-utils'; import NonceTracker from 'nonce-tracker'; import log from 'loglevel'; import BigNumber from 'bignumber.js'; @@ -51,10 +52,7 @@ import { determineTransactionType, isEIP1559Transaction, } from '../../../../shared/modules/transaction.utils'; -import { - ORIGIN_METAMASK, - MESSAGE_TYPE, -} from '../../../../shared/constants/app'; +import { ORIGIN_METAMASK } from '../../../../shared/constants/app'; import { calcGasTotal, getSwapsTokensReceivedFromTxMeta, @@ -396,6 +394,22 @@ export default class TransactionController extends EventEmitter { }); } + /** + * Creates approvals for all unapproved transactions in the txStateManager. + * + * @returns {Promise} + */ + async initApprovals() { + const unapprovedTxs = this.txStateManager.getUnapprovedTxList(); + return Promise.all( + Object.values(unapprovedTxs).map((txMeta) => + this._requestApproval(txMeta, { + shouldShowRequest: false, + }), + ), + ); + } + // ==================================================================================================================================================== /** @@ -2648,13 +2662,16 @@ export default class TransactionController extends EventEmitter { ); } - _requestApproval(txMeta) { + async _requestApproval( + txMeta, + { shouldShowRequest } = { shouldShowRequest: true }, + ) { const id = this._getApprovalId(txMeta); const { origin } = txMeta; - const type = MESSAGE_TYPE.TRANSACTION; + const type = ApprovalType.Transaction; const requestData = { txId: txMeta.id }; - this.messagingSystem + return this.messagingSystem .call( 'ApprovalController:addRequest', { @@ -2663,7 +2680,7 @@ export default class TransactionController extends EventEmitter { type, requestData, }, - true, + shouldShowRequest, ) .catch(() => { // Intentionally ignored as promise not currently used diff --git a/app/scripts/controllers/transactions/index.test.js b/app/scripts/controllers/transactions/index.test.js index 12e39d5acdcd..02eb957daa01 100644 --- a/app/scripts/controllers/transactions/index.test.js +++ b/app/scripts/controllers/transactions/index.test.js @@ -3,6 +3,7 @@ import EventEmitter from 'events'; import { toBuffer } from 'ethereumjs-util'; import { TransactionFactory } from '@ethereumjs/tx'; import { ObservableStore } from '@metamask/obs-store'; +import { ApprovalType } from '@metamask/controller-utils'; import sinon from 'sinon'; import { @@ -29,10 +30,7 @@ import { GasRecommendations, } from '../../../../shared/constants/gas'; import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller'; -import { - MESSAGE_TYPE, - ORIGIN_METAMASK, -} from '../../../../shared/constants/app'; +import { ORIGIN_METAMASK } from '../../../../shared/constants/app'; import { NetworkStatus } from '../../../../shared/constants/network'; import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../shared/lib/transactions-controller-utils'; import TransactionController from '.'; @@ -513,7 +511,7 @@ describe('Transaction Controller', function () { id: String(txMeta.id), origin: ORIGIN_METAMASK, requestData: { txId: txMeta.id }, - type: MESSAGE_TYPE.TRANSACTION, + type: ApprovalType.Transaction, }, true, // Show popup ]); @@ -551,7 +549,7 @@ describe('Transaction Controller', function () { id: String(secondTxMeta.id), origin: ORIGIN_METAMASK, requestData: { txId: secondTxMeta.id }, - type: MESSAGE_TYPE.TRANSACTION, + type: ApprovalType.Transaction, }, true, // Show popup ]); @@ -2994,4 +2992,58 @@ describe('Transaction Controller', function () { assert.equal(result.type, TransactionType.simpleSend); }); }); + + describe('initApprovals', function () { + it('adds unapprovedTxs as approvals', async function () { + const firstTxId = '1'; + txController.addTransaction( + { + id: firstTxId, + origin: ORIGIN_METAMASK, + status: TransactionStatus.unapproved, + metamaskNetworkId: currentNetworkId, + txParams: { + to: VALID_ADDRESS, + from: VALID_ADDRESS_TWO, + }, + }, + noop, + ); + const secondTxId = '2'; + txController.addTransaction( + { + id: secondTxId, + origin: ORIGIN_METAMASK, + status: TransactionStatus.unapproved, + metamaskNetworkId: currentNetworkId, + txParams: { + to: VALID_ADDRESS, + from: VALID_ADDRESS_TWO, + }, + }, + noop, + ); + await txController.initApprovals(); + assert.deepEqual(messengerMock.call.getCall(0).args, [ + 'ApprovalController:addRequest', + { + id: firstTxId, + origin: ORIGIN_METAMASK, + requestData: { txId: firstTxId }, + type: ApprovalType.Transaction, + }, + false, + ]); + assert.deepEqual(messengerMock.call.getCall(1).args, [ + 'ApprovalController:addRequest', + { + id: secondTxId, + origin: ORIGIN_METAMASK, + requestData: { txId: secondTxId }, + type: ApprovalType.Transaction, + }, + false, + ]); + }); + }); }); diff --git a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js index f63412b61c62..03b3f5714973 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js @@ -1,6 +1,7 @@ import { ethErrors, errorCodes } from 'eth-rpc-errors'; import validUrl from 'valid-url'; import { omit } from 'lodash'; +import { ApprovalType } from '@metamask/controller-utils'; import { MESSAGE_TYPE, UNKNOWN_TICKER_SYMBOL, @@ -158,7 +159,7 @@ async function addEthereumChainHandler( try { await requestUserApproval({ origin, - type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, + type: ApprovalType.SwitchEthereumChain, requestData: { rpcUrl: existingNetwork.rpcUrl, chainId: existingNetwork.chainId, @@ -244,7 +245,7 @@ async function addEthereumChainHandler( try { await requestUserApproval({ origin, - type: MESSAGE_TYPE.ADD_ETHEREUM_CHAIN, + type: ApprovalType.AddEthereumChain, requestData: { chainId: _chainId, rpcPrefs: { blockExplorerUrl: firstValidBlockExplorerUrl }, @@ -275,7 +276,7 @@ async function addEthereumChainHandler( try { await requestUserApproval({ origin, - type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, + type: ApprovalType.SwitchEthereumChain, requestData: { rpcUrl: firstValidRPCUrl, chainId: _chainId, diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index 4755a2c3d16d..6d71ba602347 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -1,5 +1,6 @@ import { ethErrors } from 'eth-rpc-errors'; import { omit } from 'lodash'; +import { ApprovalType } from '@metamask/controller-utils'; import { MESSAGE_TYPE } from '../../../../../shared/constants/app'; import { CHAIN_ID_TO_TYPE_MAP, @@ -109,7 +110,7 @@ async function switchEthereumChainHandler( try { const approvedRequestData = await requestUserApproval({ origin, - type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, + type: ApprovalType.SwitchEthereumChain, requestData, }); if ( diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 48e18e5a3278..8378cb02a92a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -63,6 +63,7 @@ import { ///: END:ONLY_INCLUDE_IN import { SignatureController } from '@metamask/signature-controller'; +import { ApprovalType } from '@metamask/controller-utils'; import { AssetType, TransactionStatus, @@ -94,7 +95,6 @@ import { UI_NOTIFICATIONS } from '../../shared/notifications'; import { MILLISECOND, SECOND } from '../../shared/constants/time'; import { ORIGIN_METAMASK, - MESSAGE_TYPE, ///: BEGIN:ONLY_INCLUDE_IN(snaps) SNAP_DIALOG_TYPES, ///: END:ONLY_INCLUDE_IN @@ -256,9 +256,13 @@ export default class MetamaskController extends EventEmitter { }), showApprovalRequest: opts.showUserConfirmation, typesExcludedFromRateLimiting: [ - MESSAGE_TYPE.ETH_SIGN, - MESSAGE_TYPE.PERSONAL_SIGN, - MESSAGE_TYPE.ETH_SIGN_TYPED_DATA, + ApprovalType.EthSign, + ApprovalType.PersonalSign, + ApprovalType.EthSignTypedData, + ApprovalType.Transaction, + ApprovalType.WatchAsset, + ApprovalType.EthGetEncryptionPublicKey, + ApprovalType.EthDecrypt, ], }); @@ -1206,6 +1210,8 @@ export default class MetamaskController extends EventEmitter { ?.disabledRpcMethodPreferences?.eth_sign, getAllState: this.getState.bind(this), securityProviderRequest: this.securityProviderRequest.bind(this), + getCurrentChainId: () => + this.networkController.store.getState().providerConfig.chainId, }); this.signatureController.hub.on('cancelWithReason', (message, reason) => { diff --git a/builds.yml b/builds.yml index 6adcb0d98e2c..414641af0343 100644 --- a/builds.yml +++ b/builds.yml @@ -213,6 +213,8 @@ env: # if it's not inside process.env # Also see DEBUG and METAMASK_DEBUG - NODE_DEBUG: '' + # Used by react-devtools-core + - EDITOR_URL: '' ### # Meta variables diff --git a/development/generate-migration.sh b/development/generate-migration.sh index 0e08b942142b..791563e3ea33 100755 --- a/development/generate-migration.sh +++ b/development/generate-migration.sh @@ -1,12 +1,24 @@ #! /bin/bash + +validate-number(){ + re='^[0-9]+$' + if [[ ! $1 =~ $re ]]; then + echo "Error: The value must be a number." >&2 + exit 1 + fi +} + g-migration() { [[ -z "$1" ]] && { echo "Migration version is required!" ; exit 1; } local vnum=$1 + + validate-number "$vnum" + if (($1 < 100)); then vnum=0$1 fi - touch app/scripts/migrations/"$vnum".js - cp app/scripts/migrations/template.js app/scripts/migrations/"$vnum".js + touch app/scripts/migrations/"$vnum".ts + cp app/scripts/migrations/template.ts app/scripts/migrations/"$vnum".ts touch app/scripts/migrations/"$vnum".test.js cp app/scripts/migrations/template.test.js app/scripts/migrations/"$vnum".test.js diff --git a/development/lib/variables.js b/development/lib/variables.js index b2fb61212304..a3b3937590d1 100644 --- a/development/lib/variables.js +++ b/development/lib/variables.js @@ -29,7 +29,11 @@ class Variables { assert( value !== DeclaredOnly, new TypeError( - `Tried to access a declared, but not defined environmental variable "${key}"`, + `Tried to access a declared, but not defined environmental variable "${key}" +\tWhy am I seeing this: "${key}" is declared in builds.yml, but had no actual value when we tried loading it. +\tHow do I fix this: You could provide a default value for the variable in builds.yml under "env" property and commit to git. For example: +\t\tenv: +\t\t - ${key}: ''`, ), ); return value; @@ -46,7 +50,9 @@ class Variables { assert( this.isDeclared(key), new TypeError( - `Tried to access an environmental variable "${key}" that wasn't declared in builds.yml`, + `Tried to access an environmental variable "${key}" that wasn't declared in builds.yml +\tWhy am I seeing this: We've made use of new variables be explicit to keep track of all of them in one place +\tHow do I fix this: Adding your variable in builds.yml under "env" property and committing to git will fix this`, ), ); return this.#definitions.get(key); diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2581ffd89a12..bff7adb06fbe 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -3910,6 +3910,64 @@ "setTimeout": true } }, + "react-focus-lock": { + "globals": { + "addEventListener": true, + "console.error": true, + "console.warn": true, + "document": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react": true, + "react-focus-lock>focus-lock": true, + "react-focus-lock>react-clientside-effect": true, + "react-focus-lock>use-callback-ref": true, + "react-focus-lock>use-sidecar": true + } + }, + "react-focus-lock>focus-lock": { + "globals": { + "HTMLIFrameElement": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_POSITION_CONTAINED_BY": true, + "Node.DOCUMENT_POSITION_CONTAINS": true, + "Node.ELEMENT_NODE": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "wait-on>rxjs>tslib": true + } + }, + "react-focus-lock>react-clientside-effect": { + "packages": { + "react": true, + "react-focus-lock>react-clientside-effect>@babel/runtime": true + } + }, + "react-focus-lock>use-callback-ref": { + "packages": { + "react": true + } + }, + "react-focus-lock>use-sidecar": { + "globals": { + "console.error": true + }, + "packages": { + "react": true, + "react-focus-lock>use-sidecar>detect-node-es": true, + "wait-on>rxjs>tslib": true + } + }, "react-idle-timer": { "globals": { "clearTimeout": true, @@ -4235,6 +4293,7 @@ }, "packages": { "browserify>process": true, + "browserify>util": true, "semver>lru-cache": true } }, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index f0fa38c5fc0f..c5eee11b6676 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -4362,6 +4362,64 @@ "setTimeout": true } }, + "react-focus-lock": { + "globals": { + "addEventListener": true, + "console.error": true, + "console.warn": true, + "document": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react": true, + "react-focus-lock>focus-lock": true, + "react-focus-lock>react-clientside-effect": true, + "react-focus-lock>use-callback-ref": true, + "react-focus-lock>use-sidecar": true + } + }, + "react-focus-lock>focus-lock": { + "globals": { + "HTMLIFrameElement": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_POSITION_CONTAINED_BY": true, + "Node.DOCUMENT_POSITION_CONTAINS": true, + "Node.ELEMENT_NODE": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "wait-on>rxjs>tslib": true + } + }, + "react-focus-lock>react-clientside-effect": { + "packages": { + "react": true, + "react-focus-lock>react-clientside-effect>@babel/runtime": true + } + }, + "react-focus-lock>use-callback-ref": { + "packages": { + "react": true + } + }, + "react-focus-lock>use-sidecar": { + "globals": { + "console.error": true + }, + "packages": { + "react": true, + "react-focus-lock>use-sidecar>detect-node-es": true, + "wait-on>rxjs>tslib": true + } + }, "react-idle-timer": { "globals": { "clearTimeout": true, @@ -4801,6 +4859,7 @@ }, "packages": { "browserify>process": true, + "browserify>util": true, "semver>lru-cache": true } }, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index f0fa38c5fc0f..c5eee11b6676 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -4362,6 +4362,64 @@ "setTimeout": true } }, + "react-focus-lock": { + "globals": { + "addEventListener": true, + "console.error": true, + "console.warn": true, + "document": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react": true, + "react-focus-lock>focus-lock": true, + "react-focus-lock>react-clientside-effect": true, + "react-focus-lock>use-callback-ref": true, + "react-focus-lock>use-sidecar": true + } + }, + "react-focus-lock>focus-lock": { + "globals": { + "HTMLIFrameElement": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_POSITION_CONTAINED_BY": true, + "Node.DOCUMENT_POSITION_CONTAINS": true, + "Node.ELEMENT_NODE": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "wait-on>rxjs>tslib": true + } + }, + "react-focus-lock>react-clientside-effect": { + "packages": { + "react": true, + "react-focus-lock>react-clientside-effect>@babel/runtime": true + } + }, + "react-focus-lock>use-callback-ref": { + "packages": { + "react": true + } + }, + "react-focus-lock>use-sidecar": { + "globals": { + "console.error": true + }, + "packages": { + "react": true, + "react-focus-lock>use-sidecar>detect-node-es": true, + "wait-on>rxjs>tslib": true + } + }, "react-idle-timer": { "globals": { "clearTimeout": true, @@ -4801,6 +4859,7 @@ }, "packages": { "browserify>process": true, + "browserify>util": true, "semver>lru-cache": true } }, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2581ffd89a12..bff7adb06fbe 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -3910,6 +3910,64 @@ "setTimeout": true } }, + "react-focus-lock": { + "globals": { + "addEventListener": true, + "console.error": true, + "console.warn": true, + "document": true, + "removeEventListener": true, + "setTimeout": true + }, + "packages": { + "@babel/runtime": true, + "prop-types": true, + "react": true, + "react-focus-lock>focus-lock": true, + "react-focus-lock>react-clientside-effect": true, + "react-focus-lock>use-callback-ref": true, + "react-focus-lock>use-sidecar": true + } + }, + "react-focus-lock>focus-lock": { + "globals": { + "HTMLIFrameElement": true, + "Node.DOCUMENT_FRAGMENT_NODE": true, + "Node.DOCUMENT_NODE": true, + "Node.DOCUMENT_POSITION_CONTAINED_BY": true, + "Node.DOCUMENT_POSITION_CONTAINS": true, + "Node.ELEMENT_NODE": true, + "console.error": true, + "console.warn": true, + "document": true, + "getComputedStyle": true, + "setTimeout": true + }, + "packages": { + "wait-on>rxjs>tslib": true + } + }, + "react-focus-lock>react-clientside-effect": { + "packages": { + "react": true, + "react-focus-lock>react-clientside-effect>@babel/runtime": true + } + }, + "react-focus-lock>use-callback-ref": { + "packages": { + "react": true + } + }, + "react-focus-lock>use-sidecar": { + "globals": { + "console.error": true + }, + "packages": { + "react": true, + "react-focus-lock>use-sidecar>detect-node-es": true, + "wait-on>rxjs>tslib": true + } + }, "react-idle-timer": { "globals": { "clearTimeout": true, @@ -4235,6 +4293,7 @@ }, "packages": { "browserify>process": true, + "browserify>util": true, "semver>lru-cache": true } }, diff --git a/lavamoat/build-system/policy-override.json b/lavamoat/build-system/policy-override.json index 895e28eae296..15dc64c54820 100644 --- a/lavamoat/build-system/policy-override.json +++ b/lavamoat/build-system/policy-override.json @@ -81,22 +81,26 @@ }, "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils": { "packages": { - "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils>eslint-visitor-keys": true + "eslint>@eslint-community/eslint-utils": true, + "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils>eslint-visitor-keys": true, + "semver": true } }, "eslint-plugin-jest>@typescript-eslint/utils": { "builtin": { + "assert": true, "path": true }, "packages": { "eslint-plugin-jest>@typescript-eslint/experimental-utils>@typescript-eslint/types": true, - "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils": true, + "eslint>@eslint-community/eslint-utils": true, "eslint-plugin-jest>@typescript-eslint/utils>@typescript-eslint/types": true, "eslint-plugin-jest>@typescript-eslint/utils>@typescript-eslint/scope-manager": true, "eslint-plugin-jest>@typescript-eslint/utils>webpack>eslint-scope": true, "eslint-plugin-mocha>eslint-utils": true, "@typescript-eslint/parser>@typescript-eslint/types": true, "eslint": true, + "semver": true, "@typescript-eslint/parser>@typescript-eslint/scope-manager": true, "eslint>eslint-scope": true, "eslint>eslint-utils": true, diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index d5b552bdc5ac..fd2759c0b15c 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -55,19 +55,10 @@ "define": true }, "packages": { - "@babel/core>@ampproject/remapping>@jridgewell/gen-mapping": true, + "terser>@jridgewell/source-map>@jridgewell/gen-mapping": true, "terser>@jridgewell/source-map>@jridgewell/trace-mapping": true } }, - "@babel/core>@ampproject/remapping>@jridgewell/gen-mapping": { - "globals": { - "define": true - }, - "packages": { - "terser>@jridgewell/source-map>@jridgewell/gen-mapping>@jridgewell/set-array": true, - "terser>@jridgewell/source-map>@jridgewell/gen-mapping>@jridgewell/sourcemap-codec": true - } - }, "@babel/core>@babel/generator": { "globals": { "console.error": true @@ -2702,6 +2693,7 @@ }, "eslint-plugin-jest>@typescript-eslint/utils": { "builtin": { + "assert": true, "path": true }, "packages": { @@ -2711,11 +2703,12 @@ "eslint-plugin-jest>@typescript-eslint/experimental-utils>@typescript-eslint/types": true, "eslint-plugin-jest>@typescript-eslint/utils>@typescript-eslint/scope-manager": true, "eslint-plugin-jest>@typescript-eslint/utils>@typescript-eslint/types": true, - "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils": true, "eslint-plugin-jest>@typescript-eslint/utils>webpack>eslint-scope": true, "eslint-plugin-mocha>eslint-utils": true, + "eslint>@eslint-community/eslint-utils": true, "eslint>eslint-scope": true, "eslint>eslint-utils": true, + "semver": true, "webpack>eslint-scope": true } }, @@ -2738,7 +2731,9 @@ }, "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils": { "packages": { - "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils>eslint-visitor-keys": true + "eslint-plugin-jest>@typescript-eslint/utils>eslint-utils>eslint-visitor-keys": true, + "eslint>@eslint-community/eslint-utils": true, + "semver": true } }, "eslint-plugin-jsdoc": { @@ -6804,6 +6799,9 @@ } }, "semver": { + "builtin": { + "util.inspect": true + }, "globals": { "console.error": true, "process": true @@ -7367,7 +7365,7 @@ }, "stylelint>postcss-html>htmlparser2>domutils>dom-serializer": { "packages": { - "stylelint>postcss-html>htmlparser2>domutils>dom-serializer>domelementtype": true, + "stylelint>postcss-html>htmlparser2>domelementtype": true, "stylelint>postcss-html>htmlparser2>entities": true } }, @@ -7995,14 +7993,7 @@ }, "globals": { "console.warn": true, - "process.env.BROWSERSLIST": true, - "process.env.BROWSERSLIST_CONFIG": true, - "process.env.BROWSERSLIST_DANGEROUS_EXTEND": true, - "process.env.BROWSERSLIST_DISABLE_CACHE": true, - "process.env.BROWSERSLIST_ENV": true, - "process.env.BROWSERSLIST_IGNORE_OLD_DATA": true, - "process.env.BROWSERSLIST_STATS": true, - "process.env.NODE_ENV": true, + "process.env": true, "process.versions.node": true }, "packages": { diff --git a/package.json b/package.json index afaf7c54acff..5c2920ed622c 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,9 @@ "test-storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"yarn storybook:build && npx http-server storybook-build --port 6006 \" \"wait-on tcp:6006 && yarn test-storybook --maxWorkers=2\"", "githooks:install": "husky install", "fitness-functions": "ts-node development/fitness-functions/index.ts", - "generate-beta-commit": "node ./development/generate-beta-commit.js" + "generate-beta-commit": "node ./development/generate-beta-commit.js", + "validate-branch-name": "validate-branch-name", + "label-prs": "ts-node ./.github/scripts/label-prs.ts" }, "resolutions": { "analytics-node/axios": "^0.21.2", @@ -211,6 +213,8 @@ "request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch" }, "dependencies": { + "@actions/core": "^1.10.0", + "@actions/github": "^5.1.1", "@babel/runtime": "^7.5.5", "@download/blockies": "^1.0.3", "@ensdomains/content-hash": "^2.5.6", @@ -227,6 +231,7 @@ "@keystonehq/metamask-airgapped-keyring": "^0.9.2", "@lavamoat/snow": "^1.5.0", "@material-ui/core": "^4.11.0", + "@metamask-institutional/portfolio-dashboard": "1.1.2", "@metamask/address-book-controller": "^2.0.0", "@metamask/announcement-controller": "^3.0.0", "@metamask/approval-controller": "^2.1.0", @@ -248,7 +253,7 @@ "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^7.0.0", "@metamask/logo": "^3.1.1", - "@metamask/message-manager": "^4.0.0", + "@metamask/message-manager": "^5.0.0", "@metamask/metamask-eth-abis": "^3.0.0", "@metamask/notification-controller": "^2.0.0", "@metamask/obs-store": "^8.1.0", @@ -261,7 +266,7 @@ "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.32.2", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", - "@metamask/signature-controller": "^1.0.0", + "@metamask/signature-controller": "^2.0.0", "@metamask/slip44": "^3.0.0", "@metamask/smart-transactions-controller": "^3.1.0", "@metamask/snaps-controllers": "^0.32.2", @@ -317,6 +322,7 @@ "fuse.js": "^3.2.0", "globalthis": "^1.0.1", "human-standard-token-abi": "^2.0.0", + "husky": "^8.0.3", "immer": "^9.0.6", "is-retry-allowed": "^2.2.0", "jest-junit": "^14.0.1", @@ -339,6 +345,7 @@ "qrcode.react": "^1.0.1", "react": "^16.12.0", "react-dom": "^16.12.0", + "react-focus-lock": "^2.9.4", "react-idle-timer": "^4.2.5", "react-inspector": "^2.3.0", "react-markdown": "^6.0.3", @@ -386,22 +393,22 @@ "@metamask/phishing-warning": "^2.1.0", "@metamask/test-dapp": "^6.0.0", "@sentry/cli": "^1.58.0", - "@storybook/addon-a11y": "^6.5.13", - "@storybook/addon-actions": "^6.5.13", - "@storybook/addon-essentials": "^6.5.13", + "@storybook/addon-a11y": "^6.5.16", + "@storybook/addon-actions": "^6.5.16", + "@storybook/addon-essentials": "^6.5.16", "@storybook/addon-knobs": "^6.4.0", - "@storybook/addons": "^6.5.13", - "@storybook/api": "^6.5.13", - "@storybook/builder-webpack5": "^6.5.13", - "@storybook/client-api": "^6.5.13", - "@storybook/components": "^6.5.13", - "@storybook/core": "^6.5.13", - "@storybook/core-events": "^6.5.13", - "@storybook/manager-webpack5": "^6.5.13", - "@storybook/react": "^6.5.13", + "@storybook/addons": "^6.5.16", + "@storybook/api": "^6.5.16", + "@storybook/builder-webpack5": "^6.5.16", + "@storybook/client-api": "^6.5.16", + "@storybook/components": "^6.5.16", + "@storybook/core": "^6.5.16", + "@storybook/core-events": "^6.5.16", + "@storybook/manager-webpack5": "^6.5.16", + "@storybook/react": "^6.5.16", "@storybook/storybook-deployer": "^2.8.16", - "@storybook/test-runner": "^0.9.2", - "@storybook/theming": "^6.5.13", + "@storybook/test-runner": "^0.9.4", + "@storybook/theming": "^6.5.16", "@testing-library/jest-dom": "^5.11.10", "@testing-library/react": "^10.4.8", "@testing-library/react-hooks": "^8.0.1", @@ -433,7 +440,7 @@ "@types/yargs": "^17.0.8", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", - "@whitespace/storybook-addon-html": "^5.1.1", + "@whitespace/storybook-addon-html": "^5.1.4", "addons-linter": "^5.2.0", "babel-plugin-module-resolver": "^5.0.0", "babelify": "^10.0.0", @@ -466,7 +473,7 @@ "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-react": "^7.23.1", "eslint-plugin-react-hooks": "^4.2.0", - "eslint-plugin-storybook": "^0.6.4", + "eslint-plugin-storybook": "^0.6.10", "fancy-log": "^1.3.3", "fast-glob": "^3.2.2", "fs-extra": "^8.1.0", @@ -534,7 +541,7 @@ "source-map": "^0.7.2", "source-map-explorer": "^2.4.2", "squirrelly": "^8.0.8", - "storybook-dark-mode": "^1.1.0", + "storybook-dark-mode": "^2.1.1", "stream-browserify": "^3.0.0", "string.prototype.matchall": "^4.0.2", "style-loader": "^0.21.0", @@ -576,6 +583,7 @@ "@metamask/eth-ledger-bridge-keyring>hdkey>secp256k1": false, "@storybook/api>core-js": false, "@storybook/core>@storybook/core-client>@storybook/ui>core-js-pure": false, + "@storybook/test-runner>@storybook/core-common>esbuild": false, "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>keccak": false, "eth-json-rpc-filters>eth-json-rpc-middleware>ethereumjs-util>secp256k1": false, "eth-json-rpc-middleware>eth-sig-util>ethereumjs-util>keccak": false, diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index 0835e9241e9f..8a0079ed04f9 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,3 +1,3 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/test-snaps/5.2.0/', + TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/test-snaps/5.3.0/', }; diff --git a/test/e2e/snaps/test-snap-getentropy.spec.js b/test/e2e/snaps/test-snap-getentropy.spec.js new file mode 100644 index 000000000000..c29da48d1e68 --- /dev/null +++ b/test/e2e/snaps/test-snap-getentropy.spec.js @@ -0,0 +1,108 @@ +const { withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); +const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); + +describe('Test Snap getEntropy', function () { + it('can use snap_getEntropy inside a snap', async function () { + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: 25000000000000000000, + }, + ], + }; + await withFixtures( + { + fixtures: new FixtureBuilder().build(), + ganacheOptions, + failOnConsoleError: false, + title: this.test.title, + }, + async ({ driver }) => { + await driver.navigate(); + + // enter pw into extension + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + // navigate to test snaps page and connect + await driver.driver.get(TEST_SNAPS_WEBSITE_URL); + await driver.delay(1000); + const snapButton = await driver.findElement('#connectGetEntropySnap'); + await driver.scrollToElement(snapButton); + await driver.delay(1000); + await driver.clickElement('#connectGetEntropySnap'); + await driver.delay(1000); + + // switch to metamask extension and click connect + let windowHandles = await driver.waitUntilXWindowHandles( + 2, + 1000, + 10000, + ); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement({ + text: 'Connect', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Approve & install' }); + + await driver.clickElement({ + text: 'Approve & install', + tag: 'button', + }); + + await driver.waitForSelector({ text: 'Ok' }); + + await driver.clickElement({ + text: 'Ok', + tag: 'button', + }); + + // click send inputs on test snap page + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // wait for npm installation success + await driver.waitForSelector({ + css: '#connectGetEntropySnap', + text: 'Reconnect to getEntropy Snap', + }); + + // find and click on send test + await driver.pasteIntoField('#entropyMessage', '1234'); + await driver.delay(500); + const snapButton2 = await driver.findElement('#signEntropyMessage'); + await driver.scrollToElement(snapButton2); + await driver.delay(500); + await driver.clickElement('#signEntropyMessage'); + + // Switch to approve signature message window and approve + windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + await driver.clickElement({ + text: 'Approve', + tag: 'button', + }); + + // switch back to test-snaps page + windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); + await driver.switchToWindowWithTitle('Test Snaps', windowHandles); + + // check the results of the message signature using waitForSelector + await driver.waitForSelector({ + css: '#entropySignResult', + text: '"0xb9c20d675976e12c8bb53c3fd8fdff2dee11ad2b132eb453b5a8f35b0553c52d3bcac0fd3324d22ff0c53b3445ef48c119ba6435bc9bfb03234806719599aa6f6245593238c734bcf9d94d2873cacdd65a3176be3ae7e5b84f95fdd4487a395f"', + }); + }, + ); + }); +}); diff --git a/ui/components/app/add-network/add-network.js b/ui/components/app/add-network/add-network.js index d8eae27ee20a..d0eca654b4c6 100644 --- a/ui/components/app/add-network/add-network.js +++ b/ui/components/app/add-network/add-network.js @@ -1,6 +1,7 @@ import React, { useContext, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; +import { ApprovalType } from '@metamask/controller-utils'; import { I18nContext } from '../../../contexts/i18n'; import Box from '../../ui/box'; import { @@ -26,7 +27,6 @@ import { import { ENVIRONMENT_TYPE_FULLSCREEN, ENVIRONMENT_TYPE_POPUP, - MESSAGE_TYPE, ORIGIN_METAMASK, } from '../../../../shared/constants/app'; import { requestUserApproval } from '../../../store/actions'; @@ -66,7 +66,7 @@ const AddNetwork = () => { unapprovedConfirmations?.find((confirmation) => { return ( confirmation.origin === 'metamask' && - confirmation.type === MESSAGE_TYPE.ADD_ETHEREUM_CHAIN + confirmation.type === ApprovalType.AddEthereumChain ); }); if (!showPopover && anAddNetworkConfirmationFromMetaMaskExists) { @@ -258,7 +258,7 @@ const AddNetwork = () => { await dispatch( requestUserApproval({ origin: ORIGIN_METAMASK, - type: MESSAGE_TYPE.ADD_ETHEREUM_CHAIN, + type: ApprovalType.AddEthereumChain, requestData: { chainId: item.chainId, rpcUrl: item.rpcUrl, diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.js index 0890f679bf20..c4a57667d6c2 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-defaults/advanced-gas-fee-defaults.js @@ -4,20 +4,19 @@ import { useSelector, useDispatch } from 'react-redux'; import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment'; import { EditGasModes } from '../../../../../shared/constants/gas'; import Box from '../../../ui/box'; -import Typography from '../../../ui/typography'; import CheckBox from '../../../ui/check-box'; import { DISPLAY, FLEX_DIRECTION, TextColor, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import { getAdvancedGasFeeValues } from '../../../../selectors'; import { setAdvancedGasFee } from '../../../../store/actions'; import { useGasFeeContext } from '../../../../contexts/gasFee'; - import { useAdvancedGasFeePopoverContext } from '../context'; import { useI18nContext } from '../../../../hooks/useI18nContext'; +import { Text } from '../../../component-library'; const AdvancedGasFeeDefaults = () => { const t = useI18nContext(); @@ -87,8 +86,9 @@ const AdvancedGasFeeDefaults = () => { onClick={handleUpdateDefaultSettings} disabled={gasErrors.maxFeePerGas || gasErrors.maxPriorityFeePerGas} /> - @@ -97,7 +97,7 @@ const AdvancedGasFeeDefaults = () => { : t('advancedGasFeeDefaultOptIn', [ {t('newValues')}, ])} - + ); diff --git a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.js b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.js index e26720b01a8c..9c8af1bb7b12 100644 --- a/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.js +++ b/ui/components/app/advanced-gas-fee-popover/advanced-gas-fee-gas-limit/advanced-gas-fee-gas-limit.js @@ -2,14 +2,14 @@ import React, { useEffect, useState } from 'react'; import { useGasFeeContext } from '../../../../contexts/gasFee'; import { bnGreaterThan, bnLessThan } from '../../../../helpers/utils/util'; -import { TypographyVariant } from '../../../../helpers/constants/design-system'; +import { TextVariant } from '../../../../helpers/constants/design-system'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { MAX_GAS_LIMIT_DEC } from '../../../../pages/send/send.constants'; import Button from '../../../ui/button'; import FormField from '../../../ui/form-field'; -import Typography from '../../../ui/typography'; import { useAdvancedGasFeePopoverContext } from '../context'; +import { Text } from '../../../component-library'; const validateGasLimit = (gasLimit, minimumGasLimitDec) => { return bnLessThan(gasLimit, minimumGasLimitDec) || @@ -58,9 +58,10 @@ const AdvancedGasFeeGasLimit = () => { } return ( - { > {t('edit')} - + ); }; diff --git a/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.component.js b/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.component.js index cda7f4d734ac..1cfd8b7e5f71 100644 --- a/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.component.js +++ b/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.component.js @@ -3,6 +3,8 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { debounce } from 'lodash'; import Tooltip from '../../ui/tooltip'; +import { Icon, IconName } from '../../component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; export default class AdvancedGasInputs extends Component { static contextTypes = { @@ -138,7 +140,11 @@ export default class AdvancedGasInputs extends Component {
{label} - +
diff --git a/ui/components/app/advanced-gas-inputs/index.scss b/ui/components/app/advanced-gas-inputs/index.scss index 1f1630485aab..cc472897f739 100644 --- a/ui/components/app/advanced-gas-inputs/index.scss +++ b/ui/components/app/advanced-gas-inputs/index.scss @@ -22,12 +22,11 @@ @include H8; } - .fa-info-circle { - color: var(--color-icon-alternative); + .info-circle { cursor: pointer; } - .fa-info-circle:hover { + .info-circle:hover { color: var(--color-icon-muted); } } diff --git a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js index cbcac50eb375..1a64b0aa0bbb 100644 --- a/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js +++ b/ui/components/app/alerts/unconnected-account-alert/unconnected-account-alert.js @@ -22,6 +22,7 @@ import Checkbox from '../../../ui/check-box'; import Tooltip from '../../../ui/tooltip'; import ConnectedAccountsList from '../../connected-accounts-list'; import { useI18nContext } from '../../../../hooks/useI18nContext'; +import { Icon, IconName } from '../../../component-library'; const { ERROR, LOADING } = ALERT_STATE; @@ -68,7 +69,7 @@ const UnconnectedAccountAlert = () => { title={t('alertDisableTooltip')} wrapperClassName="unconnected-account-alert__checkbox-label-tooltip" > - +
diff --git a/ui/components/app/confirm-data/confirm-data.js b/ui/components/app/confirm-data/confirm-data.js index a82e715101ae..b5030e0e10b7 100644 --- a/ui/components/app/confirm-data/confirm-data.js +++ b/ui/components/app/confirm-data/confirm-data.js @@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'; import { Color, TextVariant, - TEXT_TRANSFORM, + TextTransform, } from '../../../helpers/constants/design-system'; import { getKnownMethodData } from '../../../selectors'; import { useI18nContext } from '../../../hooks/useI18nContext'; @@ -42,7 +42,7 @@ const ConfirmData = ({ txData, dataComponent }) => { {`${t('functionType')}:`} @@ -51,7 +51,7 @@ const ConfirmData = ({ txData, dataComponent }) => { as="span" color={Color.textDefault} paddingLeft={1} - textTransform={TEXT_TRANSFORM.CAPITALIZE} + textTransform={TextTransform.Capitalize} variant={TextVariant.bodySmBold} > {`${functionType} ${functionParams}`} diff --git a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js index b5dcc0abe7de..c09ad91ac452 100644 --- a/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js +++ b/ui/components/app/confirm-gas-display/confirm-legacy-gas-display/confirm-legacy-gas-display.js @@ -26,6 +26,7 @@ import { import { useDraftTransactionGasValues } from '../../../../hooks/useDraftTransactionGasValues'; import { getNativeCurrency } from '../../../../ducks/metamask/metamask'; import MultilayerFeeMessage from '../../multilayer-fee-message/multi-layer-fee-message'; +import { Icon, IconName } from '../../../component-library'; const renderHeartBeatIfNotInTest = () => process.env.IN_TEST ? null : ; @@ -95,7 +96,7 @@ const ConfirmLegacyGasDisplay = () => { contentText={t('transactionDetailDappGasTooltip')} position="top" > - + ) : ( @@ -123,7 +124,7 @@ const ConfirmLegacyGasDisplay = () => { } position="top" > - + ) diff --git a/ui/components/app/confirm-hexdata/confirm-hexdata.js b/ui/components/app/confirm-hexdata/confirm-hexdata.js index de76017edf89..e85e46a5bddc 100644 --- a/ui/components/app/confirm-hexdata/confirm-hexdata.js +++ b/ui/components/app/confirm-hexdata/confirm-hexdata.js @@ -8,9 +8,9 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { useTransactionFunctionType } from '../../../hooks/useTransactionFunctionType'; import { Color, - OVERFLOW_WRAP, + OverflowWrap, TextVariant, - TEXT_TRANSFORM, + TextTransform, } from '../../../helpers/constants/design-system'; import Box from '../../ui/box'; import { Text } from '../../component-library'; @@ -42,7 +42,7 @@ const ConfirmHexData = ({ txData, dataHexComponent }) => { {`${t('functionType')}:`} @@ -51,7 +51,7 @@ const ConfirmHexData = ({ txData, dataHexComponent }) => { as="span" color={Color.textDefault} paddingLeft={1} - textTransform={TEXT_TRANSFORM.CAPITALIZE} + textTransform={TextTransform.Capitalize} variant={TextVariant.bodySmBold} > {`${functionType} ${functionParams}`} @@ -63,13 +63,13 @@ const ConfirmHexData = ({ txData, dataHexComponent }) => { as="h3" paddingBottom={3} paddingTop={2} - textTransform={TEXT_TRANSFORM.UPPERCASE} + textTransform={TextTransform.Uppercase} variant={TextVariant.bodySm} > {`${t('parameters')}:`}
{JSON.stringify(params, null, 2)}
@@ -80,14 +80,14 @@ const ConfirmHexData = ({ txData, dataHexComponent }) => { as="h3" paddingBottom={3} paddingTop={2} - textTransform={TEXT_TRANSFORM.UPPERCASE} + textTransform={TextTransform.Uppercase} variant={TextVariant.bodySm} > {`${t('hexData')}: ${toBuffer(txParams?.data).length} bytes`}
diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js index 5c4f5d632d5c..e8d4402e8b73 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-warning/confirm-page-container-warning.component.js @@ -1,10 +1,16 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { Icon, IconName } from '../../../../component-library'; +import { IconColor } from '../../../../../helpers/constants/design-system'; const ConfirmPageContainerWarning = (props) => { return (
- +
{props.warning}
diff --git a/ui/components/app/edit-gas-display/edit-gas-display.component.js b/ui/components/app/edit-gas-display/edit-gas-display.component.js index b33bd65c21e8..6bd1ed4cc3e1 100644 --- a/ui/components/app/edit-gas-display/edit-gas-display.component.js +++ b/ui/components/app/edit-gas-display/edit-gas-display.component.js @@ -7,8 +7,8 @@ import { EditGasModes } from '../../../../shared/constants/gas'; import Button from '../../ui/button'; import { - TEXT_ALIGN, - FONT_WEIGHT, + TextAlign, + FontWeight, TextColor, TextVariant, } from '../../../helpers/constants/design-system'; @@ -101,7 +101,7 @@ export default function EditGasDisplay({ color={TextColor.textDefault} variant={TextVariant.bodySm} as="h6" - fontWeight={FONT_WEIGHT.BOLD} + fontWeight={FontWeight.Bold} > {t('speedUpTooltipText')}{' '} {estimatedMinimumNative} diff --git a/ui/components/app/home-notification/home-notification.component.js b/ui/components/app/home-notification/home-notification.component.js index 1344c74ea1ca..cb56dc0fac9d 100644 --- a/ui/components/app/home-notification/home-notification.component.js +++ b/ui/components/app/home-notification/home-notification.component.js @@ -4,6 +4,8 @@ import PropTypes from 'prop-types'; import Button from '../../ui/button'; import Checkbox from '../../ui/check-box'; import Tooltip from '../../ui/tooltip'; +import { Icon, IconName } from '../../component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; const HomeNotification = ({ acceptText, @@ -39,7 +41,7 @@ const HomeNotification = ({ title={infoText} wrapperClassName="home-notification__tooltip-wrapper" > - + ) : null}
diff --git a/ui/components/app/home-notification/index.scss b/ui/components/app/home-notification/index.scss index 64672e85d071..ad3b3ddfd945 100644 --- a/ui/components/app/home-notification/index.scss +++ b/ui/components/app/home-notification/index.scss @@ -36,10 +36,6 @@ cursor: pointer; } - .fa-info-circle { - color: var(--color-icon-default); - } - &__checkbox-wrapper { display: flex; flex-direction: row; diff --git a/ui/components/app/modals/account-details-modal/account-details-modal.test.js b/ui/components/app/modals/account-details-modal/account-details-modal.test.js index 72bf233c26f0..7b85c27bb5f3 100644 --- a/ui/components/app/modals/account-details-modal/account-details-modal.test.js +++ b/ui/components/app/modals/account-details-modal/account-details-modal.test.js @@ -24,7 +24,7 @@ describe('Account Details Modal', () => { global.platform = { openTab: jest.fn() }; it('should set account label when changing default account label', () => { - const { queryByTestId } = renderWithProvider( + const { queryByTestId, getByPlaceholderText } = renderWithProvider( , mockStore, ); @@ -35,7 +35,7 @@ describe('Account Details Modal', () => { fireEvent.click(editButton); expect(queryByTestId('editable-input')).toBeInTheDocument(); - const editableInput = queryByTestId('editable-input'); + const editableInput = getByPlaceholderText('Account name'); const newAccountLabel = 'New Label'; fireEvent.change(editableInput, { diff --git a/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap b/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap index b66a360acc04..6dc2d4854b42 100644 --- a/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap +++ b/ui/components/app/nft-details/__snapshots__/nft-details.test.js.snap @@ -56,12 +56,12 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` >

MUNK #1

# 1 @@ -88,7 +88,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" >
@@ -96,7 +96,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
1/18/2023
@@ -106,7 +106,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" > @@ -114,7 +114,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
0.0049 ETH
@@ -124,12 +124,12 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box box--display-flex box--flex-direction-row" >
@@ -153,7 +153,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = ` class="box nft-details__contract-wrapper box--display-flex box--flex-direction-row" >
0xDc7...6414
@@ -183,7 +183,7 @@ exports[`NFT Details should match minimal props and state snapshot 1`] = `
Disclaimer: MetaMask pulls the media file from the source url. This url sometimes is changed by the marketplace the NFT was minted on.
diff --git a/ui/components/app/nft-details/nft-details.js b/ui/components/app/nft-details/nft-details.js index 336d5a96c5be..bbdd1df12897 100644 --- a/ui/components/app/nft-details/nft-details.js +++ b/ui/components/app/nft-details/nft-details.js @@ -5,15 +5,14 @@ import { useHistory } from 'react-router-dom'; import { isEqual } from 'lodash'; import Box from '../../ui/box'; import Card from '../../ui/card'; -import Typography from '../../ui/typography/typography'; import { TextColor, IconColor, - TypographyVariant, - FONT_WEIGHT, + TextVariant, + FontWeight, JustifyContent, FLEX_DIRECTION, - OVERFLOW_WRAP, + OverflowWrap, DISPLAY, BLOCK_SIZES, } from '../../../helpers/constants/design-system'; @@ -53,7 +52,7 @@ import { TokenStandard, } from '../../../../shared/constants/transaction'; import NftDefaultImage from '../nft-default-image'; -import { ButtonIcon, IconName } from '../../component-library'; +import { ButtonIcon, IconName, Text } from '../../component-library'; import Tooltip from '../../ui/tooltip'; import { decWEIToDecETH } from '../../../../shared/modules/conversion.utils'; @@ -201,42 +200,45 @@ export default function NftDetails({ nft }) { justifyContent={JustifyContent.spaceBetween} >
- {name} - - + #{tokenId} - +
{description ? (
- {t('description')} - - + {description} - +
) : null} {inPopUp ? null : renderSendButton()} @@ -246,87 +248,78 @@ export default function NftDetails({ nft }) { {lastSale ? ( <> - {t('lastSold')} - +
- {formattedTimestamp} - +
- {t('lastPriceSold')} - + - {`${Number(decWEIToDecETH(lastSale.total_price))} ${ lastSale.payment_token.symbol }`} - + ) : null} - {t('source')} - - + )} - + {imageThumbnail ? ( - {t('link')} - - + {imageThumbnail} - + ) : null} - {t('contractAddress')} - + - {shortenAddress(address)} - + {inPopUp ? renderSendButton() : null} - {t('nftDisclaimer')} - + diff --git a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js index ab7b6365adf8..84d90c5d7550 100644 --- a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js +++ b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js @@ -9,10 +9,12 @@ import { FONT_WEIGHT, DISPLAY, TextColor, + IconColor, } from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; import Button from '../../ui/button'; import { EXPERIMENTAL_ROUTE } from '../../../helpers/constants/routes'; +import { Icon, IconName } from '../../component-library'; export default function NftsDetectionNotice() { const t = useI18nContext(); @@ -23,12 +25,10 @@ export default function NftsDetectionNotice() { - diff --git a/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap index 43e1f1a76604..6031f8d0ba5e 100644 --- a/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap +++ b/ui/components/app/selected-account/__snapshots__/selected-account-component.test.js.snap @@ -29,14 +29,6 @@ exports[`SelectedAccount Component should match snapshot 1`] = ` class="selected-account__address" > 0x0DC...E7bc - diff --git a/ui/components/app/signature-request-original/signature-request-original.component.js b/ui/components/app/signature-request-original/signature-request-original.component.js index cfabd20bb815..0cc27dd42125 100644 --- a/ui/components/app/signature-request-original/signature-request-original.component.js +++ b/ui/components/app/signature-request-original/signature-request-original.component.js @@ -3,7 +3,6 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { ObjectInspector } from 'react-inspector'; import LedgerInstructionField from '../ledger-instruction-field'; - import { MESSAGE_TYPE } from '../../../../shared/constants/app'; import { getURLHostName, diff --git a/ui/components/app/tab-bar/tab-bar.stories.js b/ui/components/app/tab-bar/tab-bar.stories.js index 2861437a3c58..c4f18c48a4b5 100644 --- a/ui/components/app/tab-bar/tab-bar.stories.js +++ b/ui/components/app/tab-bar/tab-bar.stories.js @@ -54,7 +54,7 @@ export default { key: 'experimental', }, { - icon: , + icon: , content: 'About', key: 'about', }, diff --git a/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js b/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js new file mode 100644 index 000000000000..5eb2e730d43f --- /dev/null +++ b/ui/components/app/transaction-decoding/components/ui/accreditation/accrediation.component.stories.js @@ -0,0 +1,20 @@ +import React from 'react'; +import Accreditation from './accreditation.component'; + +export default { + title: 'Components/App/Accrediation', // title should follow the folder structure location of the component. Don't use spaces. + + argTypes: { + fetchVia: { + control: 'string', + }, + address: { control: 'string' }, + }, + args: { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'Default'; diff --git a/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js b/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js index e79f227b97a8..cf0f40073c55 100644 --- a/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js +++ b/ui/components/app/transaction-decoding/components/ui/accreditation/accreditation.component.js @@ -12,6 +12,7 @@ import { TypographyVariant } from '../../../../../../helpers/constants/design-sy import Button from '../../../../../ui/button'; import Typography from '../../../../../ui/typography'; +import { Icon, IconName } from '../../../../../component-library'; const Accreditation = ({ fetchVia, address }) => { const t = useContext(I18nContext); @@ -55,7 +56,7 @@ const Accreditation = ({ fetchVia, address }) => { return (
- +
diff --git a/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js b/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js index cfd8a39d1012..dcb8f1c0713d 100644 --- a/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js +++ b/ui/components/app/transaction-detail-item/transaction-detail-item.stories.js @@ -3,6 +3,7 @@ import InfoTooltip from '../../ui/info-tooltip/info-tooltip'; import { TextColor } from '../../../helpers/constants/design-system'; +import { Icon, IconName } from '../../component-library'; import README from './README.mdx'; import TransactionDetailItem from '.'; @@ -45,7 +46,7 @@ DefaultStory.args = { <> Estimated gas fee - + ), diff --git a/ui/components/app/transaction-detail/transaction-detail.stories.js b/ui/components/app/transaction-detail/transaction-detail.stories.js index 0a44d22fb7a9..4e34ff627d1f 100644 --- a/ui/components/app/transaction-detail/transaction-detail.stories.js +++ b/ui/components/app/transaction-detail/transaction-detail.stories.js @@ -2,6 +2,7 @@ import React from 'react'; import InfoTooltip from '../../ui/info-tooltip/info-tooltip'; import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component'; import GasTiming from '../gas-timing/gas-timing.component'; +import { Icon, IconName } from '../../component-library'; import README from './README.mdx'; import TransactionDetail from '.'; @@ -27,7 +28,7 @@ const rows = [ <> Estimated gas fee - + } diff --git a/ui/components/app/whats-new-popup/whats-new-popup.js b/ui/components/app/whats-new-popup/whats-new-popup.js index 12f81a60cfb5..707a2d286b9c 100644 --- a/ui/components/app/whats-new-popup/whats-new-popup.js +++ b/ui/components/app/whats-new-popup/whats-new-popup.js @@ -3,6 +3,7 @@ import { useHistory } from 'react-router-dom'; import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { debounce } from 'lodash'; import { getCurrentLocale } from '../../../ducks/locale/locale'; import { I18nContext } from '../../../contexts/i18n'; import { useEqualityCheck } from '../../../hooks/useEqualityCheck'; @@ -238,6 +239,16 @@ export default function WhatsNewPopup({ onClose }) { const trackEvent = useContext(MetaMetricsContext); + const handleDebouncedScroll = debounce((target) => { + setShouldShowScrollButton( + target.scrollHeight - target.scrollTop !== target.clientHeight, + ); + }, 100); + + const handleScroll = (e) => { + handleDebouncedScroll(e.target); + }; + const handleScrollDownClick = (e) => { e.stopPropagation(); idRefMap[notifications[notifications.length - 1].id].current.scrollIntoView( @@ -245,7 +256,6 @@ export default function WhatsNewPopup({ onClose }) { behavior: 'smooth', }, ); - setShouldShowScrollButton(false); }; useEffect(() => { const observer = new window.IntersectionObserver( @@ -300,6 +310,7 @@ export default function WhatsNewPopup({ onClose }) { popoverRef={popoverRef} showScrollDown={shouldShowScrollButton && notifications.length > 1} onScrollDownButtonClick={handleScrollDownClick} + onScroll={handleScroll} >
{notifications.map(({ id }, index) => { diff --git a/ui/components/component-library/avatar-icon/__snapshots__/avatar-icon.test.js.snap b/ui/components/component-library/avatar-icon/__snapshots__/avatar-icon.test.tsx.snap similarity index 100% rename from ui/components/component-library/avatar-icon/__snapshots__/avatar-icon.test.js.snap rename to ui/components/component-library/avatar-icon/__snapshots__/avatar-icon.test.tsx.snap diff --git a/ui/components/component-library/avatar-icon/avatar-icon.constants.js b/ui/components/component-library/avatar-icon/avatar-icon.constants.js deleted file mode 100644 index 142bba1110af..000000000000 --- a/ui/components/component-library/avatar-icon/avatar-icon.constants.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Size } from '../../../helpers/constants/design-system'; - -export const AVATAR_ICON_SIZES = { - XS: Size.XS, - SM: Size.SM, - MD: Size.MD, - LG: Size.LG, - XL: Size.XL, -}; diff --git a/ui/components/component-library/avatar-icon/avatar-icon.js b/ui/components/component-library/avatar-icon/avatar-icon.js deleted file mode 100644 index d3ce05f165d3..000000000000 --- a/ui/components/component-library/avatar-icon/avatar-icon.js +++ /dev/null @@ -1,97 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import classnames from 'classnames'; -import { - BorderColor, - Size, - DISPLAY, - AlignItems, - JustifyContent, - BackgroundColor, - IconColor, - TextColor, -} from '../../../helpers/constants/design-system'; - -import Box from '../../ui/box/box'; - -import { IconName, Icon } from '../icon'; -import { AvatarBase } from '../avatar-base'; - -import { AVATAR_ICON_SIZES } from './avatar-icon.constants'; - -export const AvatarIcon = React.forwardRef( - ( - { - size = Size.MD, - color = TextColor.primaryDefault, - backgroundColor = BackgroundColor.primaryMuted, - className, - iconProps, - iconName, - ...props - }, - ref, - ) => ( - - - - ), -); - -AvatarIcon.propTypes = { - /** - * - * The name of the icon to display. Should be one of IconName - */ - iconName: PropTypes.oneOf(Object.values(IconName)).isRequired, - /** - * Props for the icon inside AvatarIcon. All Icon props can be used - */ - iconProps: PropTypes.object, - /** - * The size of the AvatarIcon - * Possible values could be 'SIZES.XS' 16px, 'SIZES.SM' 24px, 'SIZES.MD' 32px, 'SIZES.LG' 40px, 'SIZES.XL' 48px - * Defaults to SIZES.MD - */ - size: PropTypes.oneOf(Object.values(AVATAR_ICON_SIZES)), - /** - * The background color of the AvatarIcon - * Defaults to BackgroundColor.primaryMuted - */ - backgroundColor: PropTypes.oneOf(Object.values(BackgroundColor)), - /** - * The color of the text inside the AvatarIcon - * Defaults to TextColor.primaryDefault - */ - color: PropTypes.oneOf([ - ...Object.values(TextColor), - ...Object.values(IconColor), - ]), - /** - * Additional classNames to be added to the AvatarIcon - */ - className: PropTypes.string, - /** - * AvatarIcon also accepts all Box props including but not limited to - * className, as(change root element of HTML element) and margin props - */ - ...Box.propTypes, -}; - -AvatarIcon.displayName = 'AvatarIcon'; diff --git a/ui/components/component-library/avatar-icon/avatar-icon.stories.js b/ui/components/component-library/avatar-icon/avatar-icon.stories.tsx similarity index 80% rename from ui/components/component-library/avatar-icon/avatar-icon.stories.js rename to ui/components/component-library/avatar-icon/avatar-icon.stories.tsx index a32e8f28498d..1795099c5748 100644 --- a/ui/components/component-library/avatar-icon/avatar-icon.stories.js +++ b/ui/components/component-library/avatar-icon/avatar-icon.stories.tsx @@ -1,6 +1,6 @@ import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; import { - Size, DISPLAY, AlignItems, BackgroundColor, @@ -12,8 +12,9 @@ import Box from '../../ui/box/box'; import { IconName } from '..'; +import { AvatarBaseSize } from '../avatar-base/avatar-base.types'; import README from './README.mdx'; -import { AvatarIcon, AVATAR_ICON_SIZES } from '.'; +import { AvatarIcon } from '.'; const marginSizeControlOptions = [ undefined, @@ -48,7 +49,7 @@ export default { }, size: { control: 'select', - options: Object.values(AVATAR_ICON_SIZES), + options: Object.values(AvatarBaseSize), }, backgroundColor: { control: 'select', @@ -83,24 +84,24 @@ export default { }, }, args: { - size: Size.MD, + size: AvatarBaseSize.Md, }, -}; +} as ComponentMeta; -const Template = (args) => { - return ; +const Template: ComponentStory = (args) => { + return ; }; export const DefaultStory = Template.bind({}); DefaultStory.storyName = 'Default'; -export const SizeStory = (args) => ( +export const SizeStory: ComponentStory = (args) => ( - - - - - + + + + + ); SizeStory.storyName = 'Size'; @@ -109,80 +110,82 @@ SizeStory.args = { iconName: IconName.Confirmation, }; -export const IconNameStory = (args) => ( +export const IconNameStory: ComponentStory = (args) => ( ); IconNameStory.storyName = 'Icon Name'; -export const ColorAndBackgroundColor = (args) => ( +export const ColorAndBackgroundColor: ComponentStory = ( + args, +) => ( ); diff --git a/ui/components/component-library/avatar-icon/avatar-icon.test.js b/ui/components/component-library/avatar-icon/avatar-icon.test.tsx similarity index 67% rename from ui/components/component-library/avatar-icon/avatar-icon.test.js rename to ui/components/component-library/avatar-icon/avatar-icon.test.tsx index e334dd81bd5a..e316e166eb5e 100644 --- a/ui/components/component-library/avatar-icon/avatar-icon.test.js +++ b/ui/components/component-library/avatar-icon/avatar-icon.test.tsx @@ -7,7 +7,8 @@ import { BackgroundColor, IconColor, } from '../../../helpers/constants/design-system'; -import { AvatarIcon, AVATAR_ICON_SIZES } from '.'; +import { AvatarBaseSize } from '../avatar-base/avatar-base.types'; +import { AvatarIcon } from '.'; describe('AvatarIcon', () => { it('should render correctly', () => { @@ -26,45 +27,45 @@ describe('AvatarIcon', () => { <> , ); - expect(getByTestId(AVATAR_ICON_SIZES.XS)).toHaveClass( - `mm-avatar-base--size-${AVATAR_ICON_SIZES.XS}`, + expect(getByTestId(AvatarBaseSize.Xs)).toHaveClass( + `mm-avatar-base--size-${AvatarBaseSize.Xs}`, ); - expect(getByTestId(AVATAR_ICON_SIZES.SM)).toHaveClass( - `mm-avatar-base--size-${AVATAR_ICON_SIZES.SM}`, + expect(getByTestId(AvatarBaseSize.Sm)).toHaveClass( + `mm-avatar-base--size-${AvatarBaseSize.Sm}`, ); - expect(getByTestId(AVATAR_ICON_SIZES.MD)).toHaveClass( - `mm-avatar-base--size-${AVATAR_ICON_SIZES.MD}`, + expect(getByTestId(AvatarBaseSize.Md)).toHaveClass( + `mm-avatar-base--size-${AvatarBaseSize.Md}`, ); - expect(getByTestId(AVATAR_ICON_SIZES.LG)).toHaveClass( - `mm-avatar-base--size-${AVATAR_ICON_SIZES.LG}`, + expect(getByTestId(AvatarBaseSize.Lg)).toHaveClass( + `mm-avatar-base--size-${AvatarBaseSize.Lg}`, ); - expect(getByTestId(AVATAR_ICON_SIZES.XL)).toHaveClass( - `mm-avatar-base--size-${AVATAR_ICON_SIZES.XL}`, + expect(getByTestId(AvatarBaseSize.Xl)).toHaveClass( + `mm-avatar-base--size-${AvatarBaseSize.Xl}`, ); }); @@ -106,9 +107,11 @@ describe('AvatarIcon', () => { ); }); it('should forward a ref to the root html element', () => { - const ref = React.createRef(); + const ref = React.createRef(); render(); expect(ref.current).not.toBeNull(); - expect(ref.current.nodeName).toBe('DIV'); + if (ref.current) { + expect(ref.current.nodeName).toBe('DIV'); + } }); }); diff --git a/ui/components/component-library/avatar-icon/avatar-icon.tsx b/ui/components/component-library/avatar-icon/avatar-icon.tsx new file mode 100644 index 000000000000..321e958940e7 --- /dev/null +++ b/ui/components/component-library/avatar-icon/avatar-icon.tsx @@ -0,0 +1,53 @@ +import React, { Ref } from 'react'; +import classnames from 'classnames'; +import { + BorderColor, + DISPLAY, + AlignItems, + JustifyContent, + BackgroundColor, + IconColor, + TextColor, +} from '../../../helpers/constants/design-system'; + +import { Icon } from '../icon'; +import { AvatarBase, AvatarBaseSize } from '../avatar-base'; + +import { AvatarIconProps } from './avatar-icon.types'; + +export const AvatarIcon = React.forwardRef( + ( + { + size = AvatarBaseSize.Md, + color = TextColor.primaryDefault, + backgroundColor = BackgroundColor.primaryMuted, + className = '', + iconProps, + iconName, + ...props + }: AvatarIconProps, + ref: Ref, + ) => ( + + + + ), +); + +AvatarIcon.displayName = 'AvatarIcon'; diff --git a/ui/components/component-library/avatar-icon/avatar-icon.types.ts b/ui/components/component-library/avatar-icon/avatar-icon.types.ts new file mode 100644 index 000000000000..fb07706800d1 --- /dev/null +++ b/ui/components/component-library/avatar-icon/avatar-icon.types.ts @@ -0,0 +1,52 @@ +import { + BackgroundColor, + BorderColor, + IconColor, + TextColor, +} from '../../../helpers/constants/design-system'; +import { IconName, IconProps } from '../icon'; +import { AvatarBaseSize } from '../avatar-base/avatar-base.types'; +import { ValidTag } from '../text/text.types'; +import type { BoxProps } from '../../ui/box/box.d'; + +export interface AvatarIconProps extends BoxProps { + /** + * The name of the icon to display. Should be one of IconName + */ + iconName: IconName; + /** + * Props for the icon inside AvatarIcon. All Icon props can be used + */ + iconProps?: Omit & { + 'data-testid'?: string; + }; + /** + * The size of the AvatarIcon + * Possible values could be 'AvatarBaseSize.Xs' 16px, 'AvatarBaseSize.Sm' 24px, 'AvatarBaseSize.Md' 32px, 'AvatarBaseSize.Lg' 40px, 'AvatarBaseSize.Xl' 48px + * Defaults to AvatarBaseSize.Md + */ + size?: AvatarBaseSize; + /** + * The background color of the AvatarIcon + * Defaults to BackgroundColor.primaryMuted + */ + backgroundColor?: BackgroundColor; + /** + * The color of the text inside the AvatarIcon + * Defaults to TextColor.primaryDefault + */ + color?: TextColor | IconColor; + /** + * Additional classNames to be added to the AvatarIcon + */ + className?: string; + /** + * The background color of the AvatarBase + * Defaults to Color.borderDefault + */ + borderColor?: BorderColor; + /** + * Changes the root html element tag of the Text component. + */ + as?: ValidTag; +} diff --git a/ui/components/component-library/avatar-icon/index.js b/ui/components/component-library/avatar-icon/index.js deleted file mode 100644 index 22612fd57096..000000000000 --- a/ui/components/component-library/avatar-icon/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { AvatarIcon } from './avatar-icon'; -export { AVATAR_ICON_SIZES } from './avatar-icon.constants'; diff --git a/ui/components/component-library/avatar-icon/index.ts b/ui/components/component-library/avatar-icon/index.ts new file mode 100644 index 000000000000..7cf542bb3348 --- /dev/null +++ b/ui/components/component-library/avatar-icon/index.ts @@ -0,0 +1,2 @@ +export { AvatarIcon } from './avatar-icon'; +export type { AvatarIconProps } from './avatar-icon.types'; diff --git a/ui/components/component-library/icon/icon.types.ts b/ui/components/component-library/icon/icon.types.ts index 27e3717b0e86..02af6173b804 100644 --- a/ui/components/component-library/icon/icon.types.ts +++ b/ui/components/component-library/icon/icon.types.ts @@ -1,5 +1,6 @@ import type { BoxProps } from '../../ui/box/box.d'; import { IconColor } from '../../../helpers/constants/design-system'; +import { AvatarBaseSize } from '../avatar-base/avatar-base.types'; export enum IconSize { Xs = 'xs', @@ -178,7 +179,7 @@ export interface IconProps extends BoxProps { * Possible values could be IconSize.Xs (12px), IconSize.Sm (16px), IconSize.Md (20px), IconSize.Lg (24px), IconSize.Xl (32px), IconSize.Inherit (inherits font-size). * Default value is IconSize.Md (20px). */ - size?: IconSize; + size?: IconSize | AvatarBaseSize; /** * The color of the icon. * Defaults to IconColor.inherit. diff --git a/ui/components/component-library/index.js b/ui/components/component-library/index.js index 5c38ef3b16d3..e0af0db26ce2 100644 --- a/ui/components/component-library/index.js +++ b/ui/components/component-library/index.js @@ -5,7 +5,7 @@ export { AvatarAccountDiameter, } from './avatar-account'; export { AvatarFavicon, AVATAR_FAVICON_SIZES } from './avatar-favicon'; -export { AvatarIcon, AVATAR_ICON_SIZES } from './avatar-icon'; +export { AvatarIcon } from './avatar-icon'; export { AvatarNetwork, AVATAR_NETWORK_SIZES } from './avatar-network'; export { AvatarToken } from './avatar-token'; export { @@ -13,7 +13,7 @@ export { BadgeWrapperPosition, BadgeWrapperAnchorElementShape, } from './badge-wrapper'; -export { AvatarBase } from './avatar-base'; +export { AvatarBase, AvatarBaseSize } from './avatar-base'; export { Button, BUTTON_VARIANT, BUTTON_SIZES } from './button'; export { ButtonBase, BUTTON_BASE_SIZES } from './button-base'; export { ButtonIcon, ButtonIconSize } from './button-icon'; @@ -34,6 +34,7 @@ export { TextField, TEXT_FIELD_TYPES, TEXT_FIELD_SIZES } from './text-field'; export { TextFieldSearch } from './text-field-search'; export { ModalContent, ModalContentSize } from './modal-content'; export { ModalOverlay } from './modal-overlay'; +export { ModalFocus } from './modal-focus'; // Molecules export { BannerBase } from './banner-base'; diff --git a/ui/components/component-library/modal-focus/README.mdx b/ui/components/component-library/modal-focus/README.mdx new file mode 100644 index 000000000000..3ec22f5514b9 --- /dev/null +++ b/ui/components/component-library/modal-focus/README.mdx @@ -0,0 +1,248 @@ +import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; + +import { ModalFocus } from './modal-focus'; + +# ModalFocus + +`ModalFocus` traps the focus within the modal. This greatly improves the experience for screen readers and keyboard only users. + + + + + +## Props + +The `ModalFocus` is built with [react-focus-lock](https://github.com/theKashey/react-focus-lock) and accepts all of the props from that library. + + + +### Children + +Use the `children` prop to render the component to lock focus to + + + + + +```jsx +import React from 'react'; +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { ModalFocus } from '../../component-library'; + +const [open, setOpen] = React.useState(false); + +; + +{ + open && ( + + +

Modal focus children

+ +

+ Use the keyboard to try tabbing around you will notice that the focus + is locked to the content within modal focus +

+ +
+
+ ); +} +``` + +### Initial Focus Ref + +Use the `initialFocusRef` to pass the `ref` of the element to receive focus initially + + + + + +```jsx +import React from 'react'; +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { ModalFocus } from '../../component-library'; + +const [open, setOpen] = React.useState(false); +const ref = React.useRef < HTMLButtonElement > null; + +; + +{ + open && ( + + + +

Initial focus is on the close button

+ +
+
+ ); +} +``` + +### Final Focus Ref + +Use the `finalFocusRef` to pass the `ref` of the element to return focus to when `ModalFocus` unmounts + + + + + +```jsx +import React from 'react'; +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { ModalFocus } from '../../component-library'; + +const [open, setOpen] = React.useState(false); +const ref = React.useRef < HTMLInputElement > null; + +; +; + +{ + open && ( + + +

Focus will be returned to the input once closed

+ +
+
+ ); +} +``` + +### Restore Focus + +Use the `restoreFocus` to restore focus to the element that triggered the `ModalFocus` once it unmounts + + + + + +```jsx +import React from 'react'; +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { ModalFocus } from '../../component-library'; + +const [open, setOpen] = React.useState(false); + +; +{ + open && ( + + +

Focus will be restored to the open button once closed

+ +
+
+ ); +} +``` + +### Auto Focus + +Use the `autoFocus` to auto focus to the first focusable element within the `ModalFocus` once it mounts + +Defaults to `true` + + + + + +```jsx +import React from 'react'; +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import Box from '../../ui/box'; + +import { ModalFocus } from '../../component-library'; + +const [open, setOpen] = React.useState(false); + +; +{ + open && ( + + +

auto focus set to false

+ +
+
+ ); +} +``` diff --git a/ui/components/component-library/modal-focus/index.ts b/ui/components/component-library/modal-focus/index.ts new file mode 100644 index 000000000000..32d54eed1a32 --- /dev/null +++ b/ui/components/component-library/modal-focus/index.ts @@ -0,0 +1,2 @@ +export { ModalFocus } from './modal-focus'; +export type { ModalFocusProps } from './modal-focus.types'; diff --git a/ui/components/component-library/modal-focus/modal-focus.stories.tsx b/ui/components/component-library/modal-focus/modal-focus.stories.tsx new file mode 100644 index 000000000000..5ae6e2c3df88 --- /dev/null +++ b/ui/components/component-library/modal-focus/modal-focus.stories.tsx @@ -0,0 +1,158 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import Box from '../../ui/box'; + +import { + BorderColor, + DISPLAY, + FLEX_DIRECTION, +} from '../../../helpers/constants/design-system'; + +import { ModalFocus } from './modal-focus'; +import README from './README.mdx'; + +export default { + title: 'Components/ComponentLibrary/ModalFocus', + component: ModalFocus, + parameters: { + docs: { + page: README, + }, + }, + args: { + children: ( + <> +

Modal focus children

+ +

+ Use the keyboard to try tabbing around you will notice that the focus + is locked to the content within modal focus +

+ + ), + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => { + const [open, setOpen] = React.useState(false); + return ( + <> + + {open && ( + + + {args.children} + + + + )} + + ); +}; + +export const DefaultStory = Template.bind({}); +DefaultStory.storyName = 'Default'; + +export const Children = Template.bind({}); +Children.args = { + children: ( + <> +

Modal focus children

+ + ), +}; +export const InitialFocusRef = (args) => { + const ref = React.useRef(null); + const [open, setOpen] = React.useState(false); + return ( + <> + + {open && ( + + + + {args.children} + + + + )} + + ); +}; +InitialFocusRef.args = { + children:

Initial focus is on the close button

, +}; + +export const FinalFocusRef = (args) => { + const ref = React.useRef(null); + const [open, setOpen] = React.useState(false); + return ( + <> + + + + + {open && ( + + +

Focus will be returned to the input once closed

+ +
+
+ )} + + ); +}; + +export const RestoreFocus = (args) => { + const ref = React.useRef(null); + const [open, setOpen] = React.useState(false); + return ( + <> + + {open && ( + + +

Focus will be restored to the open button once closed

+ +
+
+ )} + + ); +}; + +export const AutoFocus = Template.bind({}); +AutoFocus.args = { + autoFocus: false, + children:

auto focus set to false

, +}; diff --git a/ui/components/component-library/modal-focus/modal-focus.test.tsx b/ui/components/component-library/modal-focus/modal-focus.test.tsx new file mode 100644 index 000000000000..efdf4439d799 --- /dev/null +++ b/ui/components/component-library/modal-focus/modal-focus.test.tsx @@ -0,0 +1,61 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render } from '@testing-library/react'; +import React from 'react'; + +import { ModalFocus } from './modal-focus'; + +describe('ModalFocus', () => { + it('should render with children inside the ModalFocus', () => { + const { getByText } = render( + +
modal focus
+
, + ); + expect(getByText('modal focus')).toBeDefined(); + }); + + it('should render with the initial element focused', () => { + const { getByTestId } = render( + + + , + ); + expect(getByTestId('input')).toHaveFocus(); + }); + + it('should render with focused with autoFocus is set to false', () => { + const { getByTestId } = render( + + + , + ); + expect(getByTestId('input')).not.toHaveFocus(); + }); + + it('should focus initialFocusRef on render', () => { + const ref: React.RefObject = React.createRef(); + const { getByTestId } = render( + + + + + , + ); + expect(getByTestId('input')).toHaveFocus(); + }); + + it('should focus final focus ref when closed', () => { + const finalRef: React.RefObject = React.createRef(); + const { rerender, getByRole } = render( + <> + + +
modal focus
+
+ , + ); + expect(finalRef.current).not.toHaveFocus(); + rerender(); + expect(getByRole('button')).toHaveFocus(); + }); +}); diff --git a/ui/components/component-library/modal-focus/modal-focus.tsx b/ui/components/component-library/modal-focus/modal-focus.tsx new file mode 100644 index 000000000000..f8152d527435 --- /dev/null +++ b/ui/components/component-library/modal-focus/modal-focus.tsx @@ -0,0 +1,46 @@ +import React, { useCallback } from 'react'; +import ReactFocusLock from 'react-focus-lock'; +import type { ModalFocusProps } from './modal-focus.types'; + +/** + * Based on the ModalFocusScope component from chakra-ui + * https://github.com/chakra-ui/chakra-ui/blob/main/packages/components/modal/src/modal-focus.tsx + */ + +const FocusTrap: typeof ReactFocusLock = + (ReactFocusLock as any).default ?? ReactFocusLock; + +export const ModalFocus: React.FC = ({ + initialFocusRef, + finalFocusRef, + restoreFocus, + children, + autoFocus, + ...props +}) => { + const onActivation = useCallback(() => { + if (initialFocusRef?.current) { + initialFocusRef.current.focus(); + } + }, [initialFocusRef]); + + const onDeactivation = useCallback(() => { + finalFocusRef?.current?.focus(); + }, [finalFocusRef]); + + const returnFocus = restoreFocus && !finalFocusRef; + + return ( + + {children} + + ); +}; + +ModalFocus.displayName = 'ModalFocus'; diff --git a/ui/components/component-library/modal-focus/modal-focus.types.ts b/ui/components/component-library/modal-focus/modal-focus.types.ts new file mode 100644 index 000000000000..c36da41fa655 --- /dev/null +++ b/ui/components/component-library/modal-focus/modal-focus.types.ts @@ -0,0 +1,35 @@ +import React from 'react'; + +export interface FocusableElement { + focus(options?: FocusOptions): void; +} + +export interface ModalFocusProps { + /** + * The `ref` of the element to receive focus initially + */ + initialFocusRef?: React.RefObject; + /** + * The `ref` of the element to return focus to when `ModalFocus` + * unmounts + */ + finalFocusRef?: React.RefObject; + /** + * If `true`, focus will be restored to the element that + * triggered the `ModalFocus` once it unmounts + * + * @default false + */ + restoreFocus?: boolean; + /** + * The node to lock focus to + */ + children: React.ReactNode; + /** + * If `true`, the first focusable element within the `children` + * will auto-focused once `ModalFocus` mounts + * + * @default false + */ + autoFocus?: boolean; +} diff --git a/ui/components/component-library/modal-header/__snapshots__/modal-header.test.tsx.snap b/ui/components/component-library/modal-header/__snapshots__/modal-header.test.tsx.snap index d5c717bcf6cc..e6ff624afc49 100644 --- a/ui/components/component-library/modal-header/__snapshots__/modal-header.test.tsx.snap +++ b/ui/components/component-library/modal-header/__snapshots__/modal-header.test.tsx.snap @@ -9,11 +9,11 @@ exports[`ModalHeader should render ModalHeader correctly 1`] = `
-

Modal header -

+
diff --git a/ui/components/component-library/modal-header/modal-header.tsx b/ui/components/component-library/modal-header/modal-header.tsx index 9cd4ca5d3ed3..864bb65398ed 100644 --- a/ui/components/component-library/modal-header/modal-header.tsx +++ b/ui/components/component-library/modal-header/modal-header.tsx @@ -1,6 +1,13 @@ import React from 'react'; import classnames from 'classnames'; -import { HeaderBase, Text, ButtonIcon, ButtonIconSize, IconName } from '..'; +import { + HeaderBase, + Text, + ButtonIcon, + ButtonIconSize, + IconName, + ValidTag, +} from '..'; import { TextVariant, TextAlign, @@ -50,7 +57,11 @@ export const ModalHeader: React.FC = ({ {...props} > {typeof children === 'string' ? ( - + {children} ) : ( diff --git a/ui/components/component-library/modal-overlay/__snapshots__/modal-overlay.test.tsx.snap b/ui/components/component-library/modal-overlay/__snapshots__/modal-overlay.test.tsx.snap index 10f22ae8d9b9..7041d8a3b4b1 100644 --- a/ui/components/component-library/modal-overlay/__snapshots__/modal-overlay.test.tsx.snap +++ b/ui/components/component-library/modal-overlay/__snapshots__/modal-overlay.test.tsx.snap @@ -3,6 +3,7 @@ exports[`ModalOverlay should match snapshot 1`] = `
diff --git a/ui/components/component-library/modal-overlay/modal-overlay.scss b/ui/components/component-library/modal-overlay/modal-overlay.scss index afa528a1853c..5ef170df05b2 100644 --- a/ui/components/component-library/modal-overlay/modal-overlay.scss +++ b/ui/components/component-library/modal-overlay/modal-overlay.scss @@ -1,7 +1,8 @@ .mm-modal-overlay { - position: absolute; + position: fixed; top: 0; left: 0; right: 0; bottom: 0; + z-index: $modal-z-index; } diff --git a/ui/components/component-library/modal-overlay/modal-overlay.tsx b/ui/components/component-library/modal-overlay/modal-overlay.tsx index 76b9586cba88..c8da17592b0a 100644 --- a/ui/components/component-library/modal-overlay/modal-overlay.tsx +++ b/ui/components/component-library/modal-overlay/modal-overlay.tsx @@ -21,6 +21,7 @@ export const ModalOverlay: React.FC = ({ width={BLOCK_SIZES.FULL} height={BLOCK_SIZES.FULL} onClick={onClick} + aria-hidden="true" {...props} /> ); diff --git a/ui/components/component-library/text/text.types.ts b/ui/components/component-library/text/text.types.ts index 68fe42128f8c..1f2e96bfe5cc 100644 --- a/ui/components/component-library/text/text.types.ts +++ b/ui/components/component-library/text/text.types.ts @@ -41,6 +41,7 @@ export enum ValidTag { Ul = 'ul', Label = 'label', Input = 'input', + Header = 'header', } export interface TextProps extends BoxProps { diff --git a/ui/components/institutional/custody-labels/custody-labels.js b/ui/components/institutional/custody-labels/custody-labels.js index 4cbd4acd0988..3f9d8700e02e 100644 --- a/ui/components/institutional/custody-labels/custody-labels.js +++ b/ui/components/institutional/custody-labels/custody-labels.js @@ -2,10 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Text, Label } from '../../component-library'; import { - TEXT_TRANSFORM, + TextTransform, BackgroundColor, TextColor, - FONT_WEIGHT, + FontWeight, BorderRadius, TypographyVariant, } from '../../../helpers/constants/design-system'; @@ -25,7 +25,7 @@ const CustodyLabels = (props) => { {filteredLabels.map((item) => ( { paddingRight={2} backgroundColor={BackgroundColor.backgroundAlternative} color={TextColor.textMuted} - fontWeight={FONT_WEIGHT.NORMAL} + fontWeight={FontWeight.Normal} borderRadius={BorderRadius.SM} variant={TypographyVariant.H9} > diff --git a/ui/components/multichain/account-details/account-details-authenticate.js b/ui/components/multichain/account-details/account-details-authenticate.js index 240b618a4e8b..c76bde71bdd6 100644 --- a/ui/components/multichain/account-details/account-details-authenticate.js +++ b/ui/components/multichain/account-details/account-details-authenticate.js @@ -3,8 +3,8 @@ import { useDispatch, useSelector } from 'react-redux'; import PropTypes from 'prop-types'; import { DISPLAY, + FontWeight, SEVERITIES, - TextColor, TextVariant, } from '../../../helpers/constants/design-system'; import { @@ -56,19 +56,10 @@ export const AccountDetailsAuthenticate = ({ address, onCancel }) => { value={password} variant={TextVariant.bodySm} type="password" - inputProps={{ - onKeyPress: handleKeyPress, - }} + inputProps={{ onKeyPress: handleKeyPress }} + labelProps={{ fontWeight: FontWeight.Medium }} + autoFocus /> - {warning ? ( - - {warning} - - ) : null} {t('privateKeyWarning')} diff --git a/ui/components/multichain/account-details/account-details.js b/ui/components/multichain/account-details/account-details.js index 70fa9e862a31..67244de38d92 100644 --- a/ui/components/multichain/account-details/account-details.js +++ b/ui/components/multichain/account-details/account-details.js @@ -79,7 +79,10 @@ export const AccountDetails = ({ address }) => { setAttemptingExport(false)} + onClick={() => { + dispatch(hideWarning()); + setAttemptingExport(false); + }} iconName={IconName.ArrowLeft} size={Size.SM} /> diff --git a/ui/components/multichain/account-details/account-details.test.js b/ui/components/multichain/account-details/account-details.test.js index baec78f200a9..4caed5b0fd1e 100644 --- a/ui/components/multichain/account-details/account-details.test.js +++ b/ui/components/multichain/account-details/account-details.test.js @@ -45,7 +45,7 @@ describe('AccountDetails', () => { const editButton = screen.getByTestId('editable-label-button'); fireEvent.click(editButton); - const editableInput = screen.getByTestId('editable-input'); + const editableInput = screen.getByPlaceholderText('Account name'); const newAccountLabel = 'New Label'; fireEvent.change(editableInput, { target: { value: newAccountLabel } }); diff --git a/ui/components/multichain/account-list-item/account-list-item.js b/ui/components/multichain/account-list-item/account-list-item.js index a102680178d8..731016718bd0 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -22,7 +22,7 @@ import { } from '../../component-library'; import { Color, - TEXT_ALIGN, + TextAlign, AlignItems, DISPLAY, TextVariant, @@ -170,7 +170,7 @@ export const AccountListItem = ({ marginInlineEnd={2} /> ) : null} - + { // Focus on the search box when the popover is opened useEffect(() => { if (inputRef.current) { - inputRef.current.rootNode.querySelector('input[type=search]').focus(); + inputRef.current.rootNode.querySelector('input[type=search]')?.focus(); } }, [inputRef]); diff --git a/ui/components/multichain/account-picker/account-picker.js b/ui/components/multichain/account-picker/account-picker.js index c0a6ba190448..1cf0d33144f2 100644 --- a/ui/components/multichain/account-picker/account-picker.js +++ b/ui/components/multichain/account-picker/account-picker.js @@ -14,12 +14,12 @@ import { BackgroundColor, BorderRadius, DISPLAY, - FONT_WEIGHT, + FontWeight, IconColor, Size, } from '../../../helpers/constants/design-system'; -export const AccountPicker = ({ address, name, onClick }) => { +export const AccountPicker = ({ address, name, onClick, disabled }) => { const useBlockie = useSelector((state) => state.metamask.useBlockie); return ( @@ -34,6 +34,7 @@ export const AccountPicker = ({ address, name, onClick }) => { gap: 2, alignItems: AlignItems.center, }} + disabled={disabled} > { size={Size.XS} borderColor={BackgroundColor.backgroundDefault} // we currently don't have white color for border hence using backgroundDefault as the border /> - + {name} - +
+ G +
+

+ Goerli +

+ + +
{ +export const AppHeader = ({ location }) => { const trackEvent = useContext(MetaMetricsContext); const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false); const [multichainProductTourStep, setMultichainProductTourStep] = useState(1); @@ -87,6 +91,33 @@ export const AppHeader = ({ onClick }) => { .querySelector('[dir]') ?.getAttribute('dir'); + // Disable the network and account pickers if the user is in + // a critical flow + const sendStage = useSelector(getSendStage); + const isConfirmationPage = Boolean( + matchPath(location.pathname, { + path: CONFIRM_TRANSACTION_ROUTE, + exact: false, + }), + ); + const isTransactionEditPage = [ + SEND_STAGES.EDIT, + SEND_STAGES.DRAFT, + SEND_STAGES.ADD_RECIPIENT, + ].includes(sendStage); + const isSwapsPage = Boolean( + matchPath(location.pathname, { path: SWAPS_ROUTE, exact: false }), + ); + const isSwapsBuildQuotePage = Boolean( + matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }), + ); + + const disablePickers = + isConfirmationPage || + isTransactionEditPage || + (isSwapsPage && !isSwapsBuildQuotePage); + const disableNetworkPicker = isSwapsPage || disablePickers; + // Callback for network dropdown const networkOpenCallback = useCallback(() => { dispatch(toggleNetworkMenu()); @@ -113,12 +144,7 @@ export const AppHeader = ({ onClick }) => { > { - if (onClick) { - await onClick(); - } - history.push(DEFAULT_ROUTE); - }} + onClick={async () => history.push(DEFAULT_ROUTE)} /> ) : null} @@ -160,14 +186,21 @@ export const AppHeader = ({ onClick }) => { size={Size.SM} onClick={networkOpenCallback} display={[DISPLAY.FLEX, DISPLAY.NONE]} // show on popover hide on desktop + disabled={disableNetworkPicker} /> - + {popupStatus ? null : ( +
+ +
+ )} {showProductTour && popupStatus && multichainProductTourStep === 1 ? ( @@ -200,6 +233,7 @@ export const AppHeader = ({ onClick }) => { }, }); }} + disabled={disablePickers} /> { padding={2} gap={2} > - dispatch(toggleNetworkMenu())} - className="multichain-app-header__contents__network-picker" - /> +
+ dispatch(toggleNetworkMenu())} + className="multichain-app-header__contents__network-picker" + /> +
{ - if (onClick) { - await onClick(); - } history.push(DEFAULT_ROUTE); }} /> @@ -341,7 +374,7 @@ export const AppHeader = ({ onClick }) => { AppHeader.propTypes = { /** - * The onClick handler to be passed to the MetaMask Logo in the App Header + * The location object for the application */ - onClick: PropTypes.func, + location: PropTypes.object, }; diff --git a/ui/components/multichain/app-header/app-header.scss b/ui/components/multichain/app-header/app-header.scss index 1bf3cbd8213d..e7a341711782 100644 --- a/ui/components/multichain/app-header/app-header.scss +++ b/ui/components/multichain/app-header/app-header.scss @@ -30,7 +30,7 @@ } &__network-picker { - max-width: 200px; + max-width: 250px; } &--avatar-network { diff --git a/ui/components/multichain/app-header/app-header.stories.js b/ui/components/multichain/app-header/app-header.stories.js index c8ae6a8103a4..ea2da201972e 100644 --- a/ui/components/multichain/app-header/app-header.stories.js +++ b/ui/components/multichain/app-header/app-header.stories.js @@ -11,10 +11,13 @@ export default { decorators: [(story) => {story()}], component: AppHeader, argTypes: { - onClick: { - action: 'onClick', + location: { + control: 'object', }, }, + args: { + location: { pathname: '' }, + }, }; const customNetworkUnlockedData = { ...testData, diff --git a/ui/components/multichain/app-header/app-header.test.js b/ui/components/multichain/app-header/app-header.test.js index d2885587e56e..cca6bfe2d87a 100644 --- a/ui/components/multichain/app-header/app-header.test.js +++ b/ui/components/multichain/app-header/app-header.test.js @@ -2,6 +2,7 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import { SEND_STAGES } from '../../../ducks/send'; import { AppHeader } from '.'; describe('App Header', () => { @@ -100,11 +101,17 @@ describe('App Header', () => { appState: { onboardedInThisUISession: false, }, + send: { + stage: SEND_STAGES.INACTIVE, + }, }; const mockStore = configureStore(); const store = mockStore(mockState); - const { container } = renderWithProvider(, store); + const { container } = renderWithProvider( + , + store, + ); expect(container).toMatchSnapshot(); }); }); diff --git a/ui/components/multichain/multichain-token-list-item/multichain-token-list-item.js b/ui/components/multichain/multichain-token-list-item/multichain-token-list-item.js index e122ea4e974d..e8fe85f80ae4 100644 --- a/ui/components/multichain/multichain-token-list-item/multichain-token-list-item.js +++ b/ui/components/multichain/multichain-token-list-item/multichain-token-list-item.js @@ -7,12 +7,12 @@ import { BorderColor, DISPLAY, FLEX_DIRECTION, - FONT_WEIGHT, + FontWeight, JustifyContent, Size, TextColor, TextVariant, - TEXT_ALIGN, + TextAlign, } from '../../../helpers/constants/design-system'; import { AvatarNetwork, @@ -121,7 +121,7 @@ export const MultichainTokenListItem = ({ theme={dataTheme === 'light' ? 'dark' : 'light'} > @@ -130,10 +130,10 @@ export const MultichainTokenListItem = ({
{secondary} diff --git a/ui/components/multichain/network-list-item/network-list-item.js b/ui/components/multichain/network-list-item/network-list-item.js index a66bbc0bec04..6430fca6d858 100644 --- a/ui/components/multichain/network-list-item/network-list-item.js +++ b/ui/components/multichain/network-list-item/network-list-item.js @@ -11,6 +11,7 @@ import { JustifyContent, TextColor, BLOCK_SIZES, + BackgroundColor, } from '../../../helpers/constants/design-system'; import { AvatarNetwork, @@ -20,9 +21,27 @@ import { } from '../../component-library'; import { useI18nContext } from '../../../hooks/useI18nContext'; import Tooltip from '../../ui/tooltip/tooltip'; +import { + GOERLI_DISPLAY_NAME, + LINEA_TESTNET_DISPLAY_NAME, + SEPOLIA_DISPLAY_NAME, +} from '../../../../shared/constants/network'; const MAXIMUM_CHARACTERS_WITHOUT_TOOLTIP = 17; +function getAvatarNetworkColor(name) { + switch (name) { + case GOERLI_DISPLAY_NAME: + return BackgroundColor.goerli; + case LINEA_TESTNET_DISPLAY_NAME: + return BackgroundColor.lineaTestnet; + case SEPOLIA_DISPLAY_NAME: + return BackgroundColor.sepolia; + default: + return undefined; + } +} + export const NetworkListItem = ({ name, iconSrc, @@ -60,7 +79,11 @@ export const NetworkListItem = ({ backgroundColor={Color.primaryDefault} /> )} - + { diff --git a/ui/components/multichain/network-list-menu/index.scss b/ui/components/multichain/network-list-menu/index.scss index fbd2ed7ba617..19f83c1aaadb 100644 --- a/ui/components/multichain/network-list-menu/index.scss +++ b/ui/components/multichain/network-list-menu/index.scss @@ -1,4 +1,9 @@ .multichain-network-list-menu { max-height: 200px; overflow: auto; + + /* Overrides the popover's default behavior */ + &-content-wrapper { + border-radius: 0; + } } diff --git a/ui/components/multichain/network-list-menu/network-list-menu.js b/ui/components/multichain/network-list-menu/network-list-menu.js index 460f7ce1dff2..fffe5647bfb0 100644 --- a/ui/components/multichain/network-list-menu/network-list-menu.js +++ b/ui/components/multichain/network-list-menu/network-list-menu.js @@ -26,7 +26,11 @@ import { DISPLAY, JustifyContent, } from '../../../helpers/constants/design-system'; -import { Button, BUTTON_VARIANT, Text } from '../../component-library'; +import { + BUTTON_SECONDARY_SIZES, + ButtonSecondary, + Text, +} from '../../component-library'; import { ADD_POPULAR_CUSTOM_NETWORK } from '../../../helpers/constants/routes'; import { getEnvironmentType } from '../../../../app/scripts/lib/util'; import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../shared/constants/app'; @@ -64,7 +68,12 @@ export const NetworkListMenu = ({ onClose }) => { }, [showTestNetworks, showTestNetworksRef]); return ( - + <> {networks.map((network) => { @@ -158,8 +167,8 @@ export const NetworkListMenu = ({ onClose }) => { /> - + diff --git a/ui/components/ui/account-list/account-list.js b/ui/components/ui/account-list/account-list.js index 2cfdf70d2aae..1bcd5f99b00f 100644 --- a/ui/components/ui/account-list/account-list.js +++ b/ui/components/ui/account-list/account-list.js @@ -8,6 +8,8 @@ import Identicon from '../identicon'; import UserPreferencedCurrencyDisplay from '../../app/user-preferenced-currency-display'; import { PRIMARY } from '../../../helpers/constants/common'; import Tooltip from '../tooltip'; +import { Icon, IconName } from '../../component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; const AccountList = ({ selectNewAccountViaModal, @@ -61,7 +63,12 @@ const AccountList = ({
} > - +
) : null} @@ -114,7 +121,12 @@ const AccountList = ({ addressLastConnectedMap[address] }`} > - + ) : null} diff --git a/ui/components/ui/account-list/index.scss b/ui/components/ui/account-list/index.scss index c00b08e0e443..c5e97f1830c3 100644 --- a/ui/components/ui/account-list/index.scss +++ b/ui/components/ui/account-list/index.scss @@ -113,14 +113,11 @@ } } - .fa-info-circle { - color: var(--color-icon-muted); + .info-circle { cursor: pointer; - margin-inline-start: 8px; - font-size: 0.9rem; } - .fa-info-circle:hover { + .info-circle:hover { color: var(--color-icon-default); } diff --git a/ui/components/ui/box/box.d.ts b/ui/components/ui/box/box.d.ts index 3baeba841179..f36843f4b4ba 100644 --- a/ui/components/ui/box/box.d.ts +++ b/ui/components/ui/box/box.d.ts @@ -10,7 +10,6 @@ import { IconColor, DISPLAY, JustifyContent, - TEXT_ALIGN, FLEX_DIRECTION, FLEX_WRAP, BorderRadius, @@ -36,13 +35,7 @@ export type BoxFlexWrapArray = [ BoxFlexWrap?, ]; -export type BoxTextAlign = (typeof TEXT_ALIGN)[keyof typeof TEXT_ALIGN] | null; -export type BoxTextAlignArray = [ - BoxTextAlign, - BoxTextAlign?, - BoxTextAlign?, - BoxTextAlign?, -]; +export type TextAlignArray = [TextAlign, TextAlign?, TextAlign?, TextAlign?]; export type BoxDisplay = (typeof DISPLAY)[keyof typeof DISPLAY] | null; export type BoxDisplayArray = [ @@ -287,10 +280,10 @@ export interface BoxProps extends React.HTMLAttributes { justifyContent?: JustifyContent | JustifyContentArray; /** * The text-align of the Box component. - * Use TEXT_ALIGN const from '../../../helpers/constants/design-system'; + * Use TextAlign const from '../../../helpers/constants/design-system'; * Accepts responsive props in the form of an array. */ - textAlign?: BoxTextAlign | BoxTextAlignArray; + textAlign?: TextAlign | TextAlignArray; /** * The display of the Box component. * Use DISPLAY const from '../../../helpers/constants/design-system'; diff --git a/ui/components/ui/definition-list/definition-list.js b/ui/components/ui/definition-list/definition-list.js index bfe3b4b1acbf..60aa5cf5cf2a 100644 --- a/ui/components/ui/definition-list/definition-list.js +++ b/ui/components/ui/definition-list/definition-list.js @@ -8,8 +8,10 @@ import { FONT_WEIGHT, OVERFLOW_WRAP, TextColor, + IconColor, } from '../../../helpers/constants/design-system'; import Tooltip from '../tooltip'; +import { Icon, IconName, IconSize } from '../../component-library'; const MARGIN_MAP = { [Size.XS]: 0, @@ -48,7 +50,12 @@ export default function DefinitionList({ position="top" containerClassName="definition-list__tooltip-wrapper" > - + )} diff --git a/ui/components/ui/definition-list/definition-list.scss b/ui/components/ui/definition-list/definition-list.scss index 1517d46b7868..2a99ab126701 100644 --- a/ui/components/ui/definition-list/definition-list.scss +++ b/ui/components/ui/definition-list/definition-list.scss @@ -5,12 +5,6 @@ display: flex; align-items: center; - & i { - color: var(--color-icon-default); - margin-left: 6px; - font-size: $font-size-h8; - } - & #{$self}__tooltip-wrapper { display: flex !important; align-items: center; diff --git a/ui/components/ui/deprecated-test-networks/deprecated-test-networks.js b/ui/components/ui/deprecated-test-networks/deprecated-test-networks.js index 310d19bc34c8..1c8aaa180316 100644 --- a/ui/components/ui/deprecated-test-networks/deprecated-test-networks.js +++ b/ui/components/ui/deprecated-test-networks/deprecated-test-networks.js @@ -12,7 +12,7 @@ import Box from '../box/box'; import ActionableMessage from '../actionable-message/actionable-message'; import { getCurrentChainId } from '../../../selectors'; import { getCompletedOnboarding } from '../../../ducks/metamask/metamask'; -import { Text } from '../../component-library'; +import { Text, Icon, IconName, IconSize } from '../../component-library'; export default function DeprecatedTestNetworks() { const currentChainID = useSelector(getCurrentChainId); @@ -45,7 +45,7 @@ export default function DeprecatedTestNetworks() { className="deprecated-test-networks__content" > - + - + { if (event.key === 'Enter') { this.handleSubmit(isValidAccountName); } }} - onChange={(event) => this.setState({ value: event.target.value })} + onChange={(event) => { + this.setState({ value: event.target.value }); + }} data-testid="editable-input" - className={classnames('large-input', 'editable-label__input', { - 'editable-label__input--error': !isValidAccountName, - })} + error={!isValidAccountName} + helpText={errorMessage} autoFocus + placeholder={this.context.t('accountName')} /> this.handleSubmit(isValidAccountName)} /> -
- {errorMessage} -
- +
); } renderReadonly() { return ( -
-
{this.state.value}
+ + {this.state.value} this.setState({ isEditing: true })} color={Color.iconDefault} /> -
+
); } diff --git a/ui/components/ui/editable-label/index.scss b/ui/components/ui/editable-label/index.scss deleted file mode 100644 index d4b0b79836c1..000000000000 --- a/ui/components/ui/editable-label/index.scss +++ /dev/null @@ -1,46 +0,0 @@ -.editable-label { - display: flex; - align-items: center; - justify-content: center; - position: relative; - flex-flow: wrap; - - &__value { - max-width: 250px; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - &__input { - @include H6; - - color: var(--color-text-default); - background-color: var(--color-background-default); - width: 250px; - text-align: center; - border: 1px solid var(--color-border-default); - - &--error { - border: 1px solid var(--color-error-default); - } - } - - &__icon-button { - margin-left: 10px; - left: 100%; - } - - &__error { - @include H7; - - left: 8px; - color: var(--color-error-default); - width: 100%; - text-align: center; - } - - &__error-amount { - margin-top: 5px; - } -} diff --git a/ui/components/ui/popover/index.scss b/ui/components/ui/popover/index.scss index 760c73212b45..2b53cf892f51 100644 --- a/ui/components/ui/popover/index.scss +++ b/ui/components/ui/popover/index.scss @@ -51,7 +51,7 @@ display: flex; justify-content: center; align-items: center; - z-index: 1050; + z-index: $modal-z-index; } &-footer { diff --git a/ui/components/ui/slider/slider.component.js b/ui/components/ui/slider/slider.component.js index 2dc67e08b722..58166506235e 100644 --- a/ui/components/ui/slider/slider.component.js +++ b/ui/components/ui/slider/slider.component.js @@ -4,13 +4,12 @@ import MaterialSlider from '@material-ui/core/Slider'; import { withStyles } from '@material-ui/core/styles'; import { - Color, - FONT_WEIGHT, - TypographyVariant, + TextColor, + TextVariant, } from '../../../helpers/constants/design-system'; import InfoTooltip from '../info-tooltip/info-tooltip'; -import Typography from '../typography/typography'; +import { Text } from '../../component-library'; const styles = { root: { @@ -68,34 +67,24 @@ const Slider = ({
{titleText && ( - + {titleText} - + )} {tooltipText && ( )} {valueText && ( - + {valueText} - + )}
{titleDetail && (
- + {titleDetail} - +
)}
@@ -103,12 +92,9 @@ const Slider = ({
{infoText && ( - + {infoText} - + )}
diff --git a/ui/components/ui/tooltip/tooltip.stories.js b/ui/components/ui/tooltip/tooltip.stories.js index 476792b07425..9eb054443fb1 100644 --- a/ui/components/ui/tooltip/tooltip.stories.js +++ b/ui/components/ui/tooltip/tooltip.stories.js @@ -1,6 +1,7 @@ import React from 'react'; import Box from '../box/box'; -import { Text } from '../../component-library'; +import { Icon, IconName, Text } from '../../component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; import Tooltip from '.'; export default { @@ -60,10 +61,7 @@ export const DefaultStory = (args) => ( Hover over the info icon to see the tooltip - + ); @@ -74,10 +72,7 @@ export const HTML = (args) => ( This tooltips content is html - + ); diff --git a/ui/components/ui/ui-components.scss b/ui/components/ui/ui-components.scss index 9558e3ea41c5..6f012fb2a1dd 100644 --- a/ui/components/ui/ui-components.scss +++ b/ui/components/ui/ui-components.scss @@ -16,7 +16,6 @@ @import 'definition-list/definition-list'; @import 'dialog/dialog'; @import 'dropdown/dropdown'; -@import 'editable-label/index'; @import 'error-message/index'; @import 'icon-border/icon-border'; @import 'icon-button/icon-button'; diff --git a/ui/css/design-system/z-index.scss b/ui/css/design-system/z-index.scss index 38086904a678..0fd57acc1582 100644 --- a/ui/css/design-system/z-index.scss +++ b/ui/css/design-system/z-index.scss @@ -10,3 +10,4 @@ $main-container-z-index: 18; $send-card-z-index: 20; $sidebar-z-index: 26; $sidebar-overlay-z-index: 25; +$modal-z-index: 1050; diff --git a/ui/helpers/constants/settings.js b/ui/helpers/constants/settings.js index 2fbc8e713126..f7297238ff98 100644 --- a/ui/helpers/constants/settings.js +++ b/ui/helpers/constants/settings.js @@ -1,3 +1,4 @@ +import { IconName } from '../../components/component-library'; import { ICON_NAMES } from '../../components/component-library/icon/deprecated'; import { ALERTS_ROUTE, @@ -259,28 +260,28 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('metamaskVersion'), descriptionMessage: (t) => t('builtAroundTheWorld'), route: `${ABOUT_US_ROUTE}#version`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { tabMessage: (t) => t('about'), sectionMessage: (t) => t('links'), descriptionMessage: (t) => t('links'), route: `${ABOUT_US_ROUTE}#links`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { tabMessage: (t) => t('about'), sectionMessage: (t) => t('privacyMsg'), descriptionMessage: (t) => t('privacyMsg'), route: `${ABOUT_US_ROUTE}#privacy-policy`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { tabMessage: (t) => t('about'), sectionMessage: (t) => t('terms'), descriptionMessage: (t) => t('terms'), route: `${ABOUT_US_ROUTE}#terms`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { @@ -288,7 +289,7 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('attributions'), descriptionMessage: (t) => t('attributions'), route: `${ABOUT_US_ROUTE}#attributions`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { @@ -296,7 +297,7 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('supportCenter'), descriptionMessage: (t) => t('supportCenter'), route: `${ABOUT_US_ROUTE}#supportcenter`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { @@ -304,7 +305,7 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('visitWebSite'), descriptionMessage: (t) => t('visitWebSite'), route: `${ABOUT_US_ROUTE}#visitwebsite`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { @@ -312,14 +313,14 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('contactUs'), descriptionMessage: (t) => t('contactUs'), route: `${ABOUT_US_ROUTE}#contactus`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { tabMessage: (t) => t('about'), sectionMessage: (t) => t('betaTerms'), descriptionMessage: (t) => t('betaTerms'), route: `${ABOUT_US_ROUTE}#beta-terms`, - icon: 'fa fa-info-circle', + iconName: IconName.Info, }, { tabMessage: (t) => t('experimental'), diff --git a/ui/helpers/utils/accounts.js b/ui/helpers/utils/accounts.js index 6bfa68d8636b..4f953bf6618e 100644 --- a/ui/helpers/utils/accounts.js +++ b/ui/helpers/utils/accounts.js @@ -10,6 +10,8 @@ export function getAccountNameErrorMessage( (item) => item.name === newAccountName, ); + const isEmptyAccountName = newAccountName === ''; + const localizedWordForAccount = context .t('newAccountNumberName') .replace(' $1', ''); @@ -24,7 +26,7 @@ export function getAccountNameErrorMessage( const isValidAccountName = newAccountName === defaultAccountName || // What is written in the text field is the same as the placeholder - (!isDuplicateAccountName && !isReservedAccountName); + (!isDuplicateAccountName && !isReservedAccountName && !isEmptyAccountName); let errorMessage; if (isValidAccountName) { @@ -33,6 +35,8 @@ export function getAccountNameErrorMessage( errorMessage = context.t('accountNameDuplicate'); } else if (isReservedAccountName) { errorMessage = context.t('accountNameReserved'); + } else if (isEmptyAccountName) { + errorMessage = context.t('required'); } return { isValidAccountName, errorMessage }; diff --git a/ui/helpers/utils/confirm-tx.util.ts b/ui/helpers/utils/confirm-tx.util.ts index 4c4e0c4e03a7..a67a89dfb4fa 100644 --- a/ui/helpers/utils/confirm-tx.util.ts +++ b/ui/helpers/utils/confirm-tx.util.ts @@ -2,7 +2,6 @@ import currencyFormatter from 'currency-formatter'; import currencies from 'currency-formatter/currencies'; import { BigNumber } from 'bignumber.js'; -import { unconfirmedTransactionsCountSelector } from '../../selectors'; import { Numeric } from '../../../shared/modules/Numeric'; import { EtherDenomination } from '../../../shared/constants/common'; import { TransactionMeta } from '../../../shared/constants/transaction'; @@ -86,22 +85,6 @@ export function convertTokenToFiat({ return tokenInFiat.round(2).toString(); } -/** - * This is a selector and probably doesn't belong here but its staying for now - * Note: I did not go so far as to type the entirety of the MetaMask state tree - * which definitely needs to be done for the full conversion of TypeScript to - * be successful and as useful as possible. - * TODO: Type the MetaMask state tree and use that type here. - * - * @param state - MetaMask state - * @returns true if there are unconfirmed transactions in state - */ -export function hasUnconfirmedTransactions( - state: Record, -): boolean { - return unconfirmedTransactionsCountSelector(state) > 0; -} - /** * Rounds the given decimal string to 4 significant digits. * diff --git a/ui/pages/confirmation/confirmation.js b/ui/pages/confirmation/confirmation.js index 83a5b1cba604..4666a4cbfb7f 100644 --- a/ui/pages/confirmation/confirmation.js +++ b/ui/pages/confirmation/confirmation.js @@ -11,7 +11,7 @@ import { useHistory } from 'react-router-dom'; import { isEqual } from 'lodash'; import { produce } from 'immer'; -import { MESSAGE_TYPE } from '../../../shared/constants/app'; +import { ApprovalType } from '@metamask/controller-utils'; import Box from '../../components/ui/box'; import MetaMaskTemplateRenderer from '../../components/app/metamask-template-renderer'; import ConfirmationWarningModal from '../../components/app/confirmation-warning-modal'; @@ -198,9 +198,9 @@ export default function ConfirmationPage({ getSnapName(pendingConfirmation?.origin, targetSubjectMetadata); const SNAP_DIALOG_TYPE = [ - MESSAGE_TYPE.SNAP_DIALOG_ALERT, - MESSAGE_TYPE.SNAP_DIALOG_CONFIRMATION, - MESSAGE_TYPE.SNAP_DIALOG_PROMPT, + ApprovalType.SnapDialogAlert, + ApprovalType.SnapDialogConfirmation, + ApprovalType.SnapDialogPrompt, ]; const isSnapDialog = SNAP_DIALOG_TYPE.includes(pendingConfirmation?.type); @@ -208,7 +208,7 @@ export default function ConfirmationPage({ const INPUT_STATE_CONFIRMATIONS = [ ///: BEGIN:ONLY_INCLUDE_IN(snaps) - MESSAGE_TYPE.SNAP_DIALOG_PROMPT, + ApprovalType.SnapDialogPrompt, ///: END:ONLY_INCLUDE_IN ]; @@ -284,7 +284,7 @@ export default function ConfirmationPage({ setShowWarningModal(true); } else { const inputState = hasInputState(pendingConfirmation.type) - ? inputStates[MESSAGE_TYPE.SNAP_DIALOG_PROMPT] + ? inputStates[ApprovalType.SnapDialogPrompt] : null; // submit result is an array of errors or empty on success const submitResult = await templatedValues.onSubmit(inputState); diff --git a/ui/pages/confirmation/templates/index.js b/ui/pages/confirmation/templates/index.js index 2dc7a50c5423..bd2b733a66ef 100644 --- a/ui/pages/confirmation/templates/index.js +++ b/ui/pages/confirmation/templates/index.js @@ -1,5 +1,5 @@ import { omit, pick } from 'lodash'; -import { MESSAGE_TYPE } from '../../../../shared/constants/app'; +import { ApprovalType } from '@metamask/controller-utils'; import { rejectPendingApproval, resolvePendingApproval, @@ -15,16 +15,16 @@ import snapPrompt from './snaps/snap-prompt/snap-prompt'; ///: END:ONLY_INCLUDE_IN const APPROVAL_TEMPLATES = { - [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN]: addEthereumChain, - [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN]: switchEthereumChain, + [ApprovalType.AddEthereumChain]: addEthereumChain, + [ApprovalType.SwitchEthereumChain]: switchEthereumChain, ///: BEGIN:ONLY_INCLUDE_IN(snaps) - [MESSAGE_TYPE.SNAP_DIALOG_ALERT]: snapAlert, - [MESSAGE_TYPE.SNAP_DIALOG_CONFIRMATION]: snapConfirmation, - [MESSAGE_TYPE.SNAP_DIALOG_PROMPT]: snapPrompt, + [ApprovalType.SnapDialogAlert]: snapAlert, + [ApprovalType.SnapDialogConfirmation]: snapConfirmation, + [ApprovalType.SnapDialogPrompt]: snapPrompt, ///: END:ONLY_INCLUDE_IN }; -export const TEMPLATED_CONFIRMATION_MESSAGE_TYPES = +export const TEMPLATED_CONFIRMATION_APPROVAL_TYPES = Object.keys(APPROVAL_TEMPLATES); const ALLOWED_TEMPLATE_KEYS = [ diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index 0bfe5d8ce9e4..8b82060205f2 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -55,9 +55,14 @@ import { CONFIRMATION_V_NEXT_ROUTE, ADD_NFT_ROUTE, ONBOARDING_SECURE_YOUR_WALLET_ROUTE, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + CONFIRM_INSTITUTIONAL_FEATURE_CONNECT, + CONFIRM_ADD_CUSTODIAN_TOKEN, + INTERACTIVE_REPLACEMENT_TOKEN_PAGE, + ///: END:ONLY_INCLUDE_IN } from '../../helpers/constants/routes'; import ZENDESK_URLS from '../../helpers/constants/zendesk-url'; -///: BEGIN:ONLY_INCLUDE_IN(build-main) +///: BEGIN:ONLY_INCLUDE_IN(build-main,build-mmi) import { SUPPORT_LINK } from '../../../shared/lib/ui-utils'; ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(build-beta) @@ -71,12 +76,25 @@ function shouldCloseNotificationPopup({ isNotification, totalUnapprovedCount, isSigningQRHardwareTransaction, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + waitForConfirmDeepLinkDialog, + institutionalConnectRequests, + ///: END:ONLY_INCLUDE_IN }) { - return ( + let shouldCLose = isNotification && totalUnapprovedCount === 0 && - !isSigningQRHardwareTransaction - ); + !isSigningQRHardwareTransaction; + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + shouldCLose &&= + // MMI User must be shown a deeplink + !waitForConfirmDeepLinkDialog && + // MMI User is connecting to custodian or compliance + institutionalConnectRequests.length === 0; + ///: END:ONLY_INCLUDE_IN + + return shouldCLose; } export default class Home extends PureComponent { @@ -89,7 +107,7 @@ export default class Home extends PureComponent { history: PropTypes.object, forgottenPassword: PropTypes.bool, hasWatchAssetPendingApprovals: PropTypes.bool, - unconfirmedTransactionsCount: PropTypes.number, + hasTransactionPendingApprovals: PropTypes.bool.isRequired, shouldShowSeedPhraseReminder: PropTypes.bool.isRequired, isPopup: PropTypes.bool, isNotification: PropTypes.bool.isRequired, @@ -152,6 +170,14 @@ export default class Home extends PureComponent { clearNewNetworkAdded: PropTypes.func, setActiveNetwork: PropTypes.func, onboardedInThisUISession: PropTypes.bool, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + institutionalConnectRequests: PropTypes.arrayOf(PropTypes.object), + mmiPortfolioEnabled: PropTypes.bool, + mmiPortfolioUrl: PropTypes.string, + modalOpen: PropTypes.bool, + setWaitForConfirmDeepLinkDialog: PropTypes.func, + waitForConfirmDeepLinkDialog: PropTypes.bool, + ///: END:ONLY_INCLUDE_IN }; state = { @@ -171,7 +197,7 @@ export default class Home extends PureComponent { showAwaitingSwapScreen, hasWatchAssetPendingApprovals, swapsFetchParams, - unconfirmedTransactionsCount, + hasTransactionPendingApprovals, } = this.props; if (shouldCloseNotificationPopup(props)) { @@ -179,7 +205,7 @@ export default class Home extends PureComponent { closeNotificationPopup(); } else if ( firstPermissionsRequestId || - unconfirmedTransactionsCount > 0 || + hasTransactionPendingApprovals || hasWatchAssetPendingApprovals || (!isNotification && (showAwaitingSwapScreen || haveSwapsQuotes || swapsFetchParams)) @@ -188,18 +214,72 @@ export default class Home extends PureComponent { } } + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + checkInstitutionalConnectRequest() { + const { history, institutionalConnectRequests } = this.props; + if ( + institutionalConnectRequests && + institutionalConnectRequests.length > 0 && + institutionalConnectRequests[0].feature === 'custodian' + ) { + if ( + institutionalConnectRequests[0].method === + 'metamaskinstitutional_reauthenticate' + ) { + history.push(INTERACTIVE_REPLACEMENT_TOKEN_PAGE); + } else if ( + institutionalConnectRequests[0].method === + 'metamaskinstitutional_authenticate' + ) { + history.push(CONFIRM_ADD_CUSTODIAN_TOKEN); + } + } else if ( + institutionalConnectRequests && + institutionalConnectRequests.length > 0 && + institutionalConnectRequests[0].feature !== 'custodian' + ) { + history.push(CONFIRM_INSTITUTIONAL_FEATURE_CONNECT); + } + } + + shouldCloseCurrentWindow() { + const { + isNotification, + modalOpen, + totalUnapprovedCount, + institutionalConnectRequests, + waitForConfirmDeepLinkDialog, + } = this.props; + + if ( + isNotification && + totalUnapprovedCount === 0 && + institutionalConnectRequests.length === 0 && + !waitForConfirmDeepLinkDialog && + !modalOpen + ) { + global.platform.closeCurrentWindow(); + } + } + ///: END:ONLY_INCLUDE_IN + checkStatusAndNavigate() { const { firstPermissionsRequestId, history, isNotification, hasWatchAssetPendingApprovals, - unconfirmedTransactionsCount, + hasTransactionPendingApprovals, haveSwapsQuotes, showAwaitingSwapScreen, swapsFetchParams, pendingConfirmations, } = this.props; + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + this.shouldCloseCurrentWindow(); + ///: END:ONLY_INCLUDE_IN + if (!isNotification && showAwaitingSwapScreen) { history.push(AWAITING_SWAP_ROUTE); } else if (!isNotification && haveSwapsQuotes) { @@ -208,17 +288,29 @@ export default class Home extends PureComponent { history.push(BUILD_QUOTE_ROUTE); } else if (firstPermissionsRequestId) { history.push(`${CONNECT_ROUTE}/${firstPermissionsRequestId}`); - } else if (unconfirmedTransactionsCount > 0) { + } else if (hasTransactionPendingApprovals) { history.push(CONFIRM_TRANSACTION_ROUTE); } else if (hasWatchAssetPendingApprovals) { history.push(CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE); } else if (pendingConfirmations.length > 0) { history.push(CONFIRMATION_V_NEXT_ROUTE); } + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + this.checkInstitutionalConnectRequest(); + ///: END:ONLY_INCLUDE_IN } componentDidMount() { this.checkStatusAndNavigate(); + + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + const { setWaitForConfirmDeepLinkDialog } = this.props; + + window.addEventListener('beforeunload', () => { + // If user closes notification window manually, change waitForConfirmDeepLinkDialog to false + setWaitForConfirmDeepLinkDialog(false); + }); + ///: END:ONLY_INCLUDE_IN } static getDerivedStateFromProps(props) { @@ -625,6 +717,10 @@ export default class Home extends PureComponent { completedOnboarding, onboardedInThisUISession, newNetworkAddedConfigurationId, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + mmiPortfolioEnabled, + mmiPortfolioUrl, + ///: END:ONLY_INCLUDE_IN } = this.props; if (forgottenPassword) { @@ -653,6 +749,9 @@ export default class Home extends PureComponent { exact />
+ { + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + } {showWhatsNew ? : null} {!showWhatsNew && showRecoveryPhraseReminder ? ( {process.env.MULTICHAIN ? null : }
- + { + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + + ///: END:ONLY_INCLUDE_IN + } + { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + + ///: END:ONLY_INCLUDE_IN + }
- - history.push(`${ASSET_ROUTE}/${asset}`) - } - /> - - - { - history.push(ADD_NFT_ROUTE); - }} - /> + {process.env.MULTICHAIN ? ( + + + history.push(`${ASSET_ROUTE}/${asset}`) + } + /> + + ) : ( + + history.push(`${ASSET_ROUTE}/${asset}`) + } + /> + )} + { + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + + { + history.push(ADD_NFT_ROUTE); + }} + /> + + ///: END:ONLY_INCLUDE_IN + }
{ - ///: BEGIN:ONLY_INCLUDE_IN(build-main) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-mmi) t('needHelp', [ { @@ -79,6 +88,9 @@ const mapStateToProps = (state) => { const totalUnapprovedCount = getTotalUnapprovedCount(state); const swapsEnabled = getSwapsFeatureIsLive(state); const pendingConfirmations = getUnapprovedTemplatedConfirmations(state); + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + const institutionalConnectRequests = getInstitutionalConnectRequests(state); + ///: END:ONLY_INCLUDE_IN const envType = getEnvironmentType(); const isPopup = envType === ENVIRONMENT_TYPE_POPUP; @@ -109,7 +121,7 @@ const mapStateToProps = (state) => { hasUnsignedQRHardwareTransaction(state) || hasUnsignedQRHardwareMessage(state); - const hasWatchAssetPendingApprovals = hasPendingApprovalsSelector( + const hasWatchAssetPendingApprovals = hasPendingApprovals( state, ApprovalType.WatchAsset, ); @@ -118,7 +130,7 @@ const mapStateToProps = (state) => { forgottenPassword, hasWatchAssetPendingApprovals, swapsEnabled, - unconfirmedTransactionsCount: unconfirmedTransactionsCountSelector(state), + hasTransactionPendingApprovals: hasTransactionPendingApprovals(state), shouldShowSeedPhraseReminder: getShouldShowSeedPhraseReminder(state), isPopup, isNotification, @@ -155,50 +167,68 @@ const mapStateToProps = (state) => { newTokensImported: getNewTokensImported(state), newNetworkAddedConfigurationId: appState.newNetworkAddedConfigurationId, onboardedInThisUISession: appState.onboardedInThisUISession, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + waitForConfirmDeepLinkDialog: getWaitForConfirmDeepLinkDialog(state), + institutionalConnectRequests, + modalOpen: state.appState.modal.open, + mmiPortfolioUrl: getMmiPortfolioUrl(state), + mmiPortfolioEnabled: getMmiPortfolioEnabled(state), + notificationsToShow: getSortedAnnouncementsToShow(state).length > 0, + ///: END:ONLY_INCLUDE_IN }; }; -const mapDispatchToProps = (dispatch) => ({ - closeNotificationPopup: () => closeNotificationPopup(), - ///: BEGIN:ONLY_INCLUDE_IN(snaps) - removeSnapError: async (id) => await removeSnapError(id), +const mapDispatchToProps = (dispatch) => { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + const mmiActions = mmiActionsFactory(); ///: END:ONLY_INCLUDE_IN - setConnectedStatusPopoverHasBeenShown: () => - dispatch(setConnectedStatusPopoverHasBeenShown()), - onTabClick: (name) => dispatch(setDefaultHomeActiveTabName(name)), - setWeb3ShimUsageAlertDismissed: (origin) => - setWeb3ShimUsageAlertDismissed(origin), - disableWeb3ShimUsageAlert: () => - setAlertEnabledness(AlertTypes.web3ShimUsage, false), - hideWhatsNewPopup: () => dispatch(hideWhatsNewPopup()), - setRecoveryPhraseReminderHasBeenShown: () => - dispatch(setRecoveryPhraseReminderHasBeenShown()), - setRecoveryPhraseReminderLastShown: (lastShown) => - dispatch(setRecoveryPhraseReminderLastShown(lastShown)), - setTermsOfUseLastAgreed: (lastAgreed) => { - dispatch(setTermsOfUseLastAgreed(lastAgreed)); - }, - setOutdatedBrowserWarningLastShown: (lastShown) => { - dispatch(setOutdatedBrowserWarningLastShown(lastShown)); - }, - setNewNftAddedMessage: (message) => { - dispatch(setRemoveNftMessage('')); - dispatch(setNewNftAddedMessage(message)); - }, - setRemoveNftMessage: (message) => { - dispatch(setNewNftAddedMessage('')); - dispatch(setRemoveNftMessage(message)); - }, - setNewTokensImported: (newTokens) => { - dispatch(setNewTokensImported(newTokens)); - }, - clearNewNetworkAdded: () => { - dispatch(setNewNetworkAdded({})); - }, - setActiveNetwork: (networkConfigurationId) => { - dispatch(setActiveNetwork(networkConfigurationId)); - }, -}); + + return { + closeNotificationPopup: () => closeNotificationPopup(), + ///: BEGIN:ONLY_INCLUDE_IN(snaps) + removeSnapError: async (id) => await removeSnapError(id), + ///: END:ONLY_INCLUDE_IN + setConnectedStatusPopoverHasBeenShown: () => + dispatch(setConnectedStatusPopoverHasBeenShown()), + onTabClick: (name) => dispatch(setDefaultHomeActiveTabName(name)), + setWeb3ShimUsageAlertDismissed: (origin) => + setWeb3ShimUsageAlertDismissed(origin), + disableWeb3ShimUsageAlert: () => + setAlertEnabledness(AlertTypes.web3ShimUsage, false), + hideWhatsNewPopup: () => dispatch(hideWhatsNewPopup()), + setRecoveryPhraseReminderHasBeenShown: () => + dispatch(setRecoveryPhraseReminderHasBeenShown()), + setRecoveryPhraseReminderLastShown: (lastShown) => + dispatch(setRecoveryPhraseReminderLastShown(lastShown)), + setTermsOfUseLastAgreed: (lastAgreed) => { + dispatch(setTermsOfUseLastAgreed(lastAgreed)); + }, + setOutdatedBrowserWarningLastShown: (lastShown) => { + dispatch(setOutdatedBrowserWarningLastShown(lastShown)); + }, + setNewNftAddedMessage: (message) => { + dispatch(setRemoveNftMessage('')); + dispatch(setNewNftAddedMessage(message)); + }, + setRemoveNftMessage: (message) => { + dispatch(setNewNftAddedMessage('')); + dispatch(setRemoveNftMessage(message)); + }, + setNewTokensImported: (newTokens) => { + dispatch(setNewTokensImported(newTokens)); + }, + clearNewNetworkAdded: () => { + dispatch(setNewNetworkAdded({})); + }, + setActiveNetwork: (networkConfigurationId) => { + dispatch(setActiveNetwork(networkConfigurationId)); + }, + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + setWaitForConfirmDeepLinkDialog: (wait) => + dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(wait)), + ///: END:ONLY_INCLUDE_IN + }; +}; export default compose( withRouter, diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index 0b562094957f..7ae47b96173b 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -498,6 +498,7 @@ export default class Routes extends Component { isNetworkMenuOpen, toggleNetworkMenu, accountDetailsAddress, + location, } = this.props; const loadMessage = loadingMessage || isNetworkLoading @@ -542,7 +543,7 @@ export default class Routes extends Component { {!this.hideAppHeader() && (process.env.MULTICHAIN ? ( - + ) : ( -
@@ -82,8 +83,9 @@ exports[`SendGasRow Component render should match snapshot 1`] = ` style="display: inline;" tabindex="0" > -
diff --git a/ui/pages/settings/alerts-tab/alerts-tab.js b/ui/pages/settings/alerts-tab/alerts-tab.js index 83dd76e14307..7523c68f6fa1 100644 --- a/ui/pages/settings/alerts-tab/alerts-tab.js +++ b/ui/pages/settings/alerts-tab/alerts-tab.js @@ -9,6 +9,7 @@ import { setAlertEnabledness } from '../../../store/actions'; import { getAlertEnabledness } from '../../../ducks/metamask/metamask'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { handleSettingsRefs } from '../../../helpers/utils/settings-search'; +import { Icon, IconName } from '../../../components/component-library'; const AlertSettingsEntry = ({ alertId, description, title }) => { const t = useI18nContext(); @@ -30,7 +31,10 @@ const AlertSettingsEntry = ({ alertId, description, title }) => { title={description} wrapperClassName="alerts-tab__description" > - + { + return ; +}; + +DefaultAlertsTab.storyName = 'Default'; diff --git a/ui/pages/settings/settings.component.js b/ui/pages/settings/settings.component.js index deab2d573476..788110616bfe 100644 --- a/ui/pages/settings/settings.component.js +++ b/ui/pages/settings/settings.component.js @@ -303,7 +303,7 @@ class SettingsPage extends PureComponent { }, { content: t('about'), - icon: , + icon: , key: ABOUT_US_ROUTE, }, ]; diff --git a/ui/pages/swaps/view-quote/__snapshots__/view-quote-price-difference.test.js.snap b/ui/pages/swaps/view-quote/__snapshots__/view-quote-price-difference.test.js.snap index 41cf8a7fa1db..ce2ad6d17ba3 100644 --- a/ui/pages/swaps/view-quote/__snapshots__/view-quote-price-difference.test.js.snap +++ b/ui/pages/swaps/view-quote/__snapshots__/view-quote-price-difference.test.js.snap @@ -35,8 +35,9 @@ exports[`View Price Quote Difference displays a fiat error when calculationError style="display: inline;" tabindex="0" > - @@ -92,8 +93,9 @@ exports[`View Price Quote Difference displays an error when in high bucket 1`] = style="display: inline;" tabindex="0" > - @@ -149,8 +151,9 @@ exports[`View Price Quote Difference displays an error when in medium bucket 1`] style="display: inline;" tabindex="0" > - @@ -206,8 +209,9 @@ exports[`View Price Quote Difference should match snapshot 1`] = ` style="display: inline;" tabindex="0" > - diff --git a/ui/pages/swaps/view-quote/view-quote-price-difference.js b/ui/pages/swaps/view-quote/view-quote-price-difference.js index 602db1393761..2607243494d4 100644 --- a/ui/pages/swaps/view-quote/view-quote-price-difference.js +++ b/ui/pages/swaps/view-quote/view-quote-price-difference.js @@ -12,6 +12,7 @@ import { DISPLAY, } from '../../../helpers/constants/design-system'; import { GasRecommendations } from '../../../../shared/constants/gas'; +import { Icon, IconName } from '../../../components/component-library'; export default function ViewQuotePriceDifference(props) { const { @@ -74,7 +75,7 @@ export default function ViewQuotePriceDifference(props) { {priceDifferenceTitle} - +
{priceDifferenceMessage} diff --git a/ui/pages/token-details/token-details-page.js b/ui/pages/token-details/token-details-page.js index 4b75b71a87c6..17f058187780 100644 --- a/ui/pages/token-details/token-details-page.js +++ b/ui/pages/token-details/token-details-page.js @@ -14,13 +14,12 @@ import { ASSET_ROUTE, DEFAULT_ROUTE } from '../../helpers/constants/routes'; import Tooltip from '../../components/ui/tooltip'; import Button from '../../components/ui/button'; import Box from '../../components/ui/box'; -import Typography from '../../components/ui/typography'; import { - TypographyVariant, - FONT_WEIGHT, + TextVariant, + FontWeight, DISPLAY, - TEXT_ALIGN, - OVERFLOW_WRAP, + TextAlign, + OverflowWrap, TextColor, IconColor, } from '../../helpers/constants/design-system'; @@ -29,6 +28,7 @@ import { ButtonIcon, ButtonIconSize, IconName, + Text, } from '../../components/component-library'; export default function TokenDetailsPage() { @@ -64,11 +64,12 @@ export default function TokenDetailsPage() { return ( - @@ -78,19 +79,20 @@ export default function TokenDetailsPage() { onClick={() => history.push(`${ASSET_ROUTE}/${token.address}`)} className="token-details__closeButton" /> - + - {tokenBalance || ''} - + - {tokenCurrencyBalance || ''} - - + {t('tokenContractAddress')} - + - {token.address} - + - {t('tokenDecimalTitle')} - - + {token.decimals} - - + {t('network')} - - + + {aggregators && ( <> - {t('tokenList')} - - + {`${aggregators}.`} - + )} diff --git a/ui/selectors/approvals.test.ts b/ui/selectors/approvals.test.ts index 384d4d1be6ab..44923b416cfd 100644 --- a/ui/selectors/approvals.test.ts +++ b/ui/selectors/approvals.test.ts @@ -1,10 +1,10 @@ import { ApprovalType } from '@metamask/controller-utils'; -import { hasPendingApprovalsSelector } from './approvals'; +import { hasPendingApprovals } from './approvals'; describe('approval selectors', () => { const mockedState = { metamask: { - pendingApprovalCount: 2, + pendingApprovalCount: 3, pendingApprovals: { '1': { id: '1', @@ -18,28 +18,30 @@ describe('approval selectors', () => { id: '2', origin: 'origin', time: Date.now(), - type: ApprovalType.EthSignTypedData, + type: ApprovalType.Transaction, requestData: {}, requestState: null, }, }, + unapprovedTxs: { + '2': { + id: '2', + }, + }, }, }; - describe('hasPendingApprovalsSelector', () => { + describe('hasPendingApprovals', () => { it('should return true if there is a pending approval request', () => { - const result = hasPendingApprovalsSelector( - mockedState, - ApprovalType.WatchAsset, - ); + const result = hasPendingApprovals(mockedState, ApprovalType.WatchAsset); expect(result).toBe(true); }); it('should return false if there is no pending approval request', () => { - const result = hasPendingApprovalsSelector( + const result = hasPendingApprovals( mockedState, - ApprovalType.Transaction, + ApprovalType.SnapDialogPrompt, ); expect(result).toBe(false); diff --git a/ui/selectors/approvals.ts b/ui/selectors/approvals.ts index f777185df314..408ed8918071 100644 --- a/ui/selectors/approvals.ts +++ b/ui/selectors/approvals.ts @@ -1,19 +1,35 @@ import { ApprovalControllerState } from '@metamask/approval-controller'; import { ApprovalType } from '@metamask/controller-utils'; +import { TransactionMeta } from '../../shared/constants/transaction'; type ApprovalsMetaMaskState = { metamask: { pendingApprovals: ApprovalControllerState['pendingApprovals']; + unapprovedTxs: { + [transactionId: string]: TransactionMeta; + }; }; }; -export function hasPendingApprovalsSelector( +export const getApprovalRequestsByType = ( state: ApprovalsMetaMaskState, approvalType: ApprovalType, -) { +) => { const pendingApprovalRequests = Object.values( state.metamask.pendingApprovals, ).filter(({ type }) => type === approvalType); + return pendingApprovalRequests; +}; + +export function hasPendingApprovals( + state: ApprovalsMetaMaskState, + approvalType: ApprovalType, +) { + const pendingApprovalRequests = getApprovalRequestsByType( + state, + approvalType, + ); + return pendingApprovalRequests.length > 0; } diff --git a/ui/selectors/confirm-transaction.js b/ui/selectors/confirm-transaction.js index 3b3e7b13705b..349750192606 100644 --- a/ui/selectors/confirm-transaction.js +++ b/ui/selectors/confirm-transaction.js @@ -142,50 +142,6 @@ export const unconfirmedMessagesHashSelector = createSelector( }, ); -const unapprovedMsgCountSelector = (state) => state.metamask.unapprovedMsgCount; -const unapprovedPersonalMsgCountSelector = (state) => - state.metamask.unapprovedPersonalMsgCount; -const unapprovedDecryptMsgCountSelector = (state) => - state.metamask.unapprovedDecryptMsgCount; -const unapprovedEncryptionPublicKeyMsgCountSelector = (state) => - state.metamask.unapprovedEncryptionPublicKeyMsgCount; -const unapprovedTypedMessagesCountSelector = (state) => - state.metamask.unapprovedTypedMessagesCount; - -export const unconfirmedTransactionsCountSelector = createSelector( - unapprovedTxsSelector, - unapprovedMsgCountSelector, - unapprovedPersonalMsgCountSelector, - unapprovedDecryptMsgCountSelector, - unapprovedEncryptionPublicKeyMsgCountSelector, - unapprovedTypedMessagesCountSelector, - deprecatedGetCurrentNetworkId, - getCurrentChainId, - ( - unapprovedTxs = {}, - unapprovedMsgCount = 0, - unapprovedPersonalMsgCount = 0, - unapprovedDecryptMsgCount = 0, - unapprovedEncryptionPublicKeyMsgCount = 0, - unapprovedTypedMessagesCount = 0, - network, - chainId, - ) => { - const filteredUnapprovedTxIds = Object.keys(unapprovedTxs).filter((txId) => - transactionMatchesNetwork(unapprovedTxs[txId], chainId, network), - ); - - return ( - filteredUnapprovedTxIds.length + - unapprovedTypedMessagesCount + - unapprovedMsgCount + - unapprovedPersonalMsgCount + - unapprovedDecryptMsgCount + - unapprovedEncryptionPublicKeyMsgCount - ); - }, -); - export const currentCurrencySelector = (state) => state.metamask.currentCurrency; export const conversionRateSelector = (state) => state.metamask.conversionRate; diff --git a/ui/selectors/confirm-transaction.test.js b/ui/selectors/confirm-transaction.test.js index e0f7c9c6f44e..653301265a6e 100644 --- a/ui/selectors/confirm-transaction.test.js +++ b/ui/selectors/confirm-transaction.test.js @@ -1,7 +1,5 @@ -import { CHAIN_IDS } from '../../shared/constants/network'; import { TransactionType } from '../../shared/constants/transaction'; import { - unconfirmedTransactionsCountSelector, sendTokenTokenAmountAndToAddressSelector, contractExchangeRateSelector, conversionRateSelector, @@ -17,32 +15,6 @@ const getEthersArrayLikeFromObj = (obj) => { }; describe('Confirm Transaction Selector', () => { - describe('unconfirmedTransactionsCountSelector', () => { - const state = { - metamask: { - unapprovedTxs: { - 1: { - metamaskNetworkId: '5', - }, - 2: { - chainId: CHAIN_IDS.MAINNET, - }, - }, - unapprovedMsgCount: 1, - unapprovedPersonalMsgCount: 1, - unapprovedTypedMessagesCount: 1, - networkId: '5', - providerConfig: { - chainId: '0x5', - }, - }, - }; - - it('returns number of txs in unapprovedTxs state with the same network plus unapproved signing method counts', () => { - expect(unconfirmedTransactionsCountSelector(state)).toStrictEqual(4); - }); - }); - describe('sendTokenTokenAmountAndToAddressSelector', () => { const state = { confirmTransaction: { diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index dfc2a83e7b2f..fd7ac5767d14 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -1,7 +1,9 @@ +import { ApprovalType } from '@metamask/controller-utils'; ///: BEGIN:ONLY_INCLUDE_IN(snaps) import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN import { CaveatTypes } from '../../shared/constants/permissions'; +import { getApprovalRequestsByType } from './approvals'; import { getMetaMaskAccountsOrdered, getOriginOfCurrentTab, @@ -341,9 +343,10 @@ export function getFirstSnapInstallOrUpdateRequest(state) { ///: END:ONLY_INCLUDE_IN export function getPermissionsRequests(state) { - return Object.values(state.metamask.pendingApprovals) - .filter(({ type }) => type === 'wallet_requestPermissions') - .map(({ requestData }) => requestData); + return getApprovalRequestsByType( + state, + ApprovalType.WalletRequestPermissions, + ).map(({ requestData }) => requestData); } export function getFirstPermissionRequest(state) { diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index de7a4b8dca65..85cb57be3a56 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -63,7 +63,7 @@ import { ///: END:ONLY_INCLUDE_IN } from '../helpers/utils/util'; -import { TEMPLATED_CONFIRMATION_MESSAGE_TYPES } from '../pages/confirmation/templates'; +import { TEMPLATED_CONFIRMATION_APPROVAL_TYPES } from '../pages/confirmation/templates'; import { STATIC_MAINNET_TOKEN_LIST } from '../../shared/constants/tokens'; import { DAY } from '../../shared/constants/time'; import { TERMS_OF_USE_LAST_UPDATED } from '../../shared/constants/terms'; @@ -551,7 +551,7 @@ export function getUnapprovedConfirmations(state) { export function getUnapprovedTemplatedConfirmations(state) { const unapprovedConfirmations = getUnapprovedConfirmations(state); return unapprovedConfirmations.filter((approval) => - TEMPLATED_CONFIRMATION_MESSAGE_TYPES.includes(approval.type), + TEMPLATED_CONFIRMATION_APPROVAL_TYPES.includes(approval.type), ); } diff --git a/ui/selectors/transactions.js b/ui/selectors/transactions.js index 63e72d8c2b50..1b2a07dc7f37 100644 --- a/ui/selectors/transactions.js +++ b/ui/selectors/transactions.js @@ -1,4 +1,5 @@ import { createSelector } from 'reselect'; +import { ApprovalType } from '@metamask/controller-utils'; import { PRIORITY_STATUS_HASH, PENDING_STATUS_HASH, @@ -17,6 +18,7 @@ import { deprecatedGetCurrentNetworkId, getSelectedAddress, } from './selectors'; +import { hasPendingApprovals, getApprovalRequestsByType } from './approvals'; const INVALID_INITIAL_TRANSACTION_TYPES = [ TransactionType.cancel, @@ -534,3 +536,34 @@ export const submittedPendingTransactionsSelector = createSelector( (transaction) => transaction.status === TransactionStatus.submitted, ), ); + +const hasUnapprovedTransactionsInCurrentNetwork = (state) => { + const { unapprovedTxs } = state.metamask; + const unapprovedTxRequests = getApprovalRequestsByType( + state, + ApprovalType.Transaction, + ); + + const chainId = getCurrentChainId(state); + + const filteredUnapprovedTxInCurrentNetwork = unapprovedTxRequests.filter( + ({ id }) => transactionMatchesNetwork(unapprovedTxs[id], chainId), + ); + + return filteredUnapprovedTxInCurrentNetwork.length > 0; +}; + +const TRANSACTION_APPROVAL_TYPES = [ + ApprovalType.EthDecrypt, + ApprovalType.EthGetEncryptionPublicKey, + ApprovalType.EthSign, + ApprovalType.EthSignTypedData, + ApprovalType.PersonalSign, +]; + +export function hasTransactionPendingApprovals(state) { + return ( + hasUnapprovedTransactionsInCurrentNetwork(state) || + TRANSACTION_APPROVAL_TYPES.some((type) => hasPendingApprovals(state, type)) + ); +} diff --git a/ui/selectors/transactions.test.js b/ui/selectors/transactions.test.js index 02227c410d0f..30d48efcc68b 100644 --- a/ui/selectors/transactions.test.js +++ b/ui/selectors/transactions.test.js @@ -1,3 +1,4 @@ +import { ApprovalType } from '@metamask/controller-utils'; import { CHAIN_IDS } from '../../shared/constants/network'; import { TransactionStatus } from '../../shared/constants/transaction'; import { @@ -7,6 +8,7 @@ import { nonceSortedPendingTransactionsSelector, nonceSortedCompletedTransactionsSelector, submittedPendingTransactionsSelector, + hasTransactionPendingApprovals, } from './transactions'; describe('Transaction Selectors', () => { @@ -329,4 +331,78 @@ describe('Transaction Selectors', () => { ); }); }); + + describe('hasTransactionPendingApprovals', () => { + const mockNetworkId = 'mockNetworkId'; + const mockedState = { + metamask: { + providerConfig: { + chainId: mockNetworkId, + }, + pendingApprovalCount: 2, + pendingApprovals: { + 1: { + id: '1', + origin: 'origin', + time: Date.now(), + type: ApprovalType.WatchAsset, + requestData: {}, + requestState: null, + }, + 2: { + id: '2', + origin: 'origin', + time: Date.now(), + type: ApprovalType.Transaction, + requestData: {}, + requestState: null, + }, + }, + unapprovedTxs: { + 2: { + id: '2', + chainId: mockNetworkId, + }, + }, + }, + }; + + it('should return true if there is a pending transaction on same network', () => { + const result = hasTransactionPendingApprovals(mockedState); + expect(result).toBe(true); + }); + it('should return false if there is a pending transaction on different network', () => { + mockedState.metamask.unapprovedTxs['2'].chainId = 'differentNetworkId'; + const result = hasTransactionPendingApprovals(mockedState); + expect(result).toBe(false); + }); + it.each([ + [ApprovalType.EthDecrypt], + [ApprovalType.EthGetEncryptionPublicKey], + [ApprovalType.EthSign], + [ApprovalType.EthSignTypedData], + [ApprovalType.PersonalSign], + ])( + 'should return true if there is a pending transaction of %s type', + (type) => { + const result = hasTransactionPendingApprovals({ + ...mockedState, + metamask: { + ...mockedState.metamask, + pendingApprovals: { + 2: { + id: '2', + origin: 'origin', + time: Date.now(), + type, + requestData: {}, + requestState: null, + }, + }, + }, + }); + expect(result).toBe(true); + }, + ); + }); }); diff --git a/ui/store/actions.ts b/ui/store/actions.ts index a923bca0f3e1..84554096962a 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -23,12 +23,12 @@ import { POLLING_TOKEN_ENVIRONMENT_TYPES, MESSAGE_TYPE, } from '../../shared/constants/app'; -import { hasUnconfirmedTransactions } from '../helpers/utils/confirm-tx.util'; import { getEnvironmentType, addHexPrefix } from '../../app/scripts/lib/util'; import { getMetaMaskAccounts, getPermittedAccountsForCurrentTab, getSelectedAddress, + hasTransactionPendingApprovals, ///: BEGIN:ONLY_INCLUDE_IN(snaps) getNotifications, ///: END:ONLY_INCLUDE_IN @@ -2698,7 +2698,7 @@ export function closeCurrentNotificationWindow(): ThunkAction< return (_, getState) => { if ( getEnvironmentType() === ENVIRONMENT_TYPE_NOTIFICATION && - !hasUnconfirmedTransactions(getState()) + !hasTransactionPendingApprovals(getState()) ) { closeNotificationPopup(); } diff --git a/yarn.lock b/yarn.lock index 39656d679494..afe2b74632b2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,13 +5,44 @@ __metadata: version: 6 cacheKey: 8 +"@actions/core@npm:^1.10.0": + version: 1.10.0 + resolution: "@actions/core@npm:1.10.0" + dependencies: + "@actions/http-client": ^2.0.1 + uuid: ^8.3.2 + checksum: 0a75621e007ab20d887434cdd165f0b9036f14c22252a2faed33543d8b9d04ec95d823e69ca636a25245574e4585d73e1e9e47a845339553c664f9f2c9614669 + languageName: node + linkType: hard + +"@actions/github@npm:^5.1.1": + version: 5.1.1 + resolution: "@actions/github@npm:5.1.1" + dependencies: + "@actions/http-client": ^2.0.1 + "@octokit/core": ^3.6.0 + "@octokit/plugin-paginate-rest": ^2.17.0 + "@octokit/plugin-rest-endpoint-methods": ^5.13.0 + checksum: 2210bd7f8e1e8b407b7df74a259523dc4c63f4ad3a6bfcc0d7867b6e9c3499bd3e25d7de7a9a1bbd0de3be441a8832d5c0b5c0cff3036cd477378c0ec5502434 + languageName: node + linkType: hard + +"@actions/http-client@npm:^2.0.1": + version: 2.1.0 + resolution: "@actions/http-client@npm:2.1.0" + dependencies: + tunnel: ^0.0.6 + checksum: 25a72a952cc95fb4b3ab086da73a5754dd0957c206637cace69be2e16f018cc1b3d3c40d3bcf89ffd8a5929d5e8445594b498b50db306a50ad7536023f8e3800 + languageName: node + linkType: hard + "@ampproject/remapping@npm:^2.1.0": - version: 2.2.0 - resolution: "@ampproject/remapping@npm:2.2.0" + version: 2.2.1 + resolution: "@ampproject/remapping@npm:2.2.1" dependencies: - "@jridgewell/gen-mapping": ^0.1.0 + "@jridgewell/gen-mapping": ^0.3.0 "@jridgewell/trace-mapping": ^0.3.9 - checksum: d74d170d06468913921d72430259424b7e4c826b5a7d39ff839a29d547efb97dc577caa8ba3fb5cf023624e9af9d09651afc3d4112a45e2050328abc9b3a2292 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 languageName: node linkType: hard @@ -1596,6 +1627,15 @@ __metadata: languageName: node linkType: hard +"@babel/runtime@npm:^7.12.13": + version: 7.21.0 + resolution: "@babel/runtime@npm:7.21.0" + dependencies: + regenerator-runtime: ^0.13.11 + checksum: 7b33e25bfa9e0e1b9e8828bb61b2d32bdd46b41b07ba7cb43319ad08efc6fda8eb89445193e67d6541814627df0ca59122c0ea795e412b99c5183a0540d338ab + languageName: node + linkType: hard + "@babel/runtime@patch:@babel/runtime@npm%3A7.18.9#./.yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch::locator=metamask-crx%40workspace%3A.": version: 7.18.9 resolution: "@babel/runtime@patch:@babel/runtime@npm%3A7.18.9#./.yarn/patches/@babel-runtime-npm-7.18.9-28ca6b5f61.patch::version=7.18.9&hash=918bda&locator=metamask-crx%40workspace%3A." @@ -1746,26 +1786,22 @@ __metadata: languageName: node linkType: hard -"@electron/get@npm:^1.0.1": - version: 1.12.3 - resolution: "@electron/get@npm:1.12.3" +"@electron/get@npm:^2.0.0": + version: 2.0.2 + resolution: "@electron/get@npm:2.0.2" dependencies: debug: ^4.1.1 env-paths: ^2.2.0 - filenamify: ^4.1.0 fs-extra: ^8.1.0 - global-agent: ^2.0.2 - global-tunnel-ng: ^2.7.1 - got: ^9.6.0 + global-agent: ^3.0.0 + got: ^11.8.5 progress: ^2.0.3 semver: ^6.2.0 sumchecker: ^3.0.1 dependenciesMeta: global-agent: optional: true - global-tunnel-ng: - optional: true - checksum: 4aff199a7c38f1824eb8ae215f4c85dc7af61f8599b99d525a7fade850be1deaa5dfbe25fbea47bed23fca60f9291ca01c8c9ad5090b2fc60283a3999b60026e + checksum: 900845cc0b31b54761fc9b0ada2dea1e999e59aacc48999d53903bcb7c9a0a7356b5fe736cf610b2a56c5a21f5a3c0e083b2ed2b7e52c36a4d0f420d4b5ec268 languageName: node linkType: hard @@ -3221,16 +3257,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.1.0": - version: 0.1.1 - resolution: "@jridgewell/gen-mapping@npm:0.1.1" - dependencies: - "@jridgewell/set-array": ^1.0.0 - "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc - languageName: node - linkType: hard - "@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": version: 0.3.2 resolution: "@jridgewell/gen-mapping@npm:0.3.2" @@ -3249,7 +3275,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1": +"@jridgewell/set-array@npm:^1.0.1": version: 1.1.2 resolution: "@jridgewell/set-array@npm:1.1.2" checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e @@ -3593,6 +3619,13 @@ __metadata: languageName: node linkType: hard +"@metamask-institutional/portfolio-dashboard@npm:1.1.2": + version: 1.1.2 + resolution: "@metamask-institutional/portfolio-dashboard@npm:1.1.2" + checksum: f2e1ec83fe0411f4d2e67dfdf2183f89667f34ae862425ece7b5cd0f4099eb7ae091910d67a3f15b7b5982e87bc80e9f668c25072c3bc5a977377fce14357cd3 + languageName: node + linkType: hard + "@metamask/abi-utils@npm:^1.1.0": version: 1.1.1 resolution: "@metamask/abi-utils@npm:1.1.1" @@ -4045,9 +4078,9 @@ __metadata: languageName: node linkType: hard -"@metamask/message-manager@npm:^4.0.0": - version: 4.0.0 - resolution: "@metamask/message-manager@npm:4.0.0" +"@metamask/message-manager@npm:^5.0.0": + version: 5.0.0 + resolution: "@metamask/message-manager@npm:5.0.0" dependencies: "@metamask/base-controller": ^2.0.0 "@metamask/controller-utils": ^3.4.0 @@ -4056,7 +4089,7 @@ __metadata: ethereumjs-util: ^7.0.10 jsonschema: ^1.2.4 uuid: ^8.3.2 - checksum: 9c3295a726eb59c2cc3f764b96010833edf2463e2dd3ee0a4d23ea6bf662615b3bd71110a5c6b60f253eac1de6c8b38af1edc0188ec766770a9d02c0f7401caa + checksum: 078c7eeca03975c3a899dcaa7485ce7aaff6d97b53c2a8e8563ec4e17791b836914fbc0f57a64cbf263be231609e0ffc77eabbe9a98fdcc1240af09a733ba574 languageName: node linkType: hard @@ -4312,18 +4345,18 @@ __metadata: languageName: node linkType: hard -"@metamask/signature-controller@npm:^1.0.0": - version: 1.0.0 - resolution: "@metamask/signature-controller@npm:1.0.0" +"@metamask/signature-controller@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/signature-controller@npm:2.0.0" dependencies: "@metamask/approval-controller": ^2.1.1 "@metamask/base-controller": ^2.0.0 "@metamask/controller-utils": ^3.4.0 - "@metamask/message-manager": ^4.0.0 + "@metamask/message-manager": ^5.0.0 eth-rpc-errors: ^4.0.2 ethereumjs-util: ^7.0.10 immer: ^9.0.6 - checksum: 7efb738646a179db15c45d6e1654e17ce6c7a3e42b03fd27d365e50bb2e4287a1757f26efc0b3e99b3e5d320816f3f9e0c7038491289cf6071b7f886eaa0f27b + checksum: aa7a37079cb108bd9dcb23292f82690b6796b3cde5a2b841db7f636fa9f19a5eaaa8eea7461d757dcfd664d1a6a5da3af8ea25a402c6fe575c3204390ff3964f languageName: node linkType: hard @@ -4692,6 +4725,116 @@ __metadata: languageName: node linkType: hard +"@octokit/auth-token@npm:^2.4.4": + version: 2.5.0 + resolution: "@octokit/auth-token@npm:2.5.0" + dependencies: + "@octokit/types": ^6.0.3 + checksum: 45949296c09abcd6beb4c3f69d45b0c1f265f9581d2a9683cf4d1800c4cf8259c2f58d58e44c16c20bffb85a0282a176c0d51f4af300e428b863f27b910e6297 + languageName: node + linkType: hard + +"@octokit/core@npm:^3.6.0": + version: 3.6.0 + resolution: "@octokit/core@npm:3.6.0" + dependencies: + "@octokit/auth-token": ^2.4.4 + "@octokit/graphql": ^4.5.8 + "@octokit/request": ^5.6.3 + "@octokit/request-error": ^2.0.5 + "@octokit/types": ^6.0.3 + before-after-hook: ^2.2.0 + universal-user-agent: ^6.0.0 + checksum: f81160129037bd8555d47db60cd5381637b7e3602ad70735a7bdf8f3d250c7b7114a666bb12ef7a8746a326a5d72ed30a1b8f8a5a170007f7285c8e217bef1f0 + languageName: node + linkType: hard + +"@octokit/endpoint@npm:^6.0.1": + version: 6.0.12 + resolution: "@octokit/endpoint@npm:6.0.12" + dependencies: + "@octokit/types": ^6.0.3 + is-plain-object: ^5.0.0 + universal-user-agent: ^6.0.0 + checksum: b48b29940af11c4b9bca41cf56809754bb8385d4e3a6122671799d27f0238ba575b3fde86d2d30a84f4dbbc14430940de821e56ecc6a9a92d47fc2b29a31479d + languageName: node + linkType: hard + +"@octokit/graphql@npm:^4.5.8": + version: 4.8.0 + resolution: "@octokit/graphql@npm:4.8.0" + dependencies: + "@octokit/request": ^5.6.0 + "@octokit/types": ^6.0.3 + universal-user-agent: ^6.0.0 + checksum: f68afe53f63900d4a16a0a733f2f500df2695b731f8ed32edb728d50edead7f5011437f71d069c2d2f6d656227703d0c832a3c8af58ecf82bd5dcc051f2d2d74 + languageName: node + linkType: hard + +"@octokit/openapi-types@npm:^12.11.0": + version: 12.11.0 + resolution: "@octokit/openapi-types@npm:12.11.0" + checksum: 8a7d4bd6288cc4085cabe0ca9af2b87c875c303af932cb138aa1b2290eb69d32407759ac23707bb02776466e671244a902e9857896903443a69aff4b6b2b0e3b + languageName: node + linkType: hard + +"@octokit/plugin-paginate-rest@npm:^2.17.0": + version: 2.21.3 + resolution: "@octokit/plugin-paginate-rest@npm:2.21.3" + dependencies: + "@octokit/types": ^6.40.0 + peerDependencies: + "@octokit/core": ">=2" + checksum: acf31de2ba4021bceec7ff49c5b0e25309fc3c009d407f153f928ddf436ab66cd4217344138378d5523f5fb233896e1db58c9c7b3ffd9612a66d760bc5d319ed + languageName: node + linkType: hard + +"@octokit/plugin-rest-endpoint-methods@npm:^5.13.0": + version: 5.16.2 + resolution: "@octokit/plugin-rest-endpoint-methods@npm:5.16.2" + dependencies: + "@octokit/types": ^6.39.0 + deprecation: ^2.3.1 + peerDependencies: + "@octokit/core": ">=3" + checksum: 30fcc50c335d1093f03573d9fa3a4b7d027fc98b215c43e07e82ee8dabfa0af0cf1b963feb542312ae32d897a2f68dc671577206f30850215517bebedc5a2c73 + languageName: node + linkType: hard + +"@octokit/request-error@npm:^2.0.5, @octokit/request-error@npm:^2.1.0": + version: 2.1.0 + resolution: "@octokit/request-error@npm:2.1.0" + dependencies: + "@octokit/types": ^6.0.3 + deprecation: ^2.0.0 + once: ^1.4.0 + checksum: baec2b5700498be01b4d958f9472cb776b3f3b0ea52924323a07e7a88572e24cac2cdf7eb04a0614031ba346043558b47bea2d346e98f0e8385b4261f138ef18 + languageName: node + linkType: hard + +"@octokit/request@npm:^5.6.0, @octokit/request@npm:^5.6.3": + version: 5.6.3 + resolution: "@octokit/request@npm:5.6.3" + dependencies: + "@octokit/endpoint": ^6.0.1 + "@octokit/request-error": ^2.1.0 + "@octokit/types": ^6.16.1 + is-plain-object: ^5.0.0 + node-fetch: ^2.6.7 + universal-user-agent: ^6.0.0 + checksum: c0b4542eb4baaf880d673c758d3e0b5c4a625a4ae30abf40df5548b35f1ff540edaac74625192b1aff42a79ac661e774da4ab7d5505f1cb4ef81239b1e8510c5 + languageName: node + linkType: hard + +"@octokit/types@npm:^6.0.3, @octokit/types@npm:^6.16.1, @octokit/types@npm:^6.39.0, @octokit/types@npm:^6.40.0": + version: 6.41.0 + resolution: "@octokit/types@npm:6.41.0" + dependencies: + "@octokit/openapi-types": ^12.11.0 + checksum: fd6f75e0b19b90d1a3d244d2b0c323ed8f2f05e474a281f60a321986683548ef2e0ec2b3a946aa9405d6092e055344455f69f58957c60f58368c8bdda5b7d2ab + languageName: node + linkType: hard + "@oozcitak/dom@npm:1.15.10": version: 1.15.10 resolution: "@oozcitak/dom@npm:1.15.10" @@ -5054,13 +5197,6 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^0.14.0": - version: 0.14.0 - resolution: "@sindresorhus/is@npm:0.14.0" - checksum: 971e0441dd44ba3909b467219a5e242da0fc584048db5324cfb8048148fa8dcc9d44d71e3948972c4f6121d24e5da402ef191420d1266a95f713bb6d6e59c98a - languageName: node - linkType: hard - "@sindresorhus/is@npm:^4.0.0": version: 4.6.0 resolution: "@sindresorhus/is@npm:4.6.0" @@ -5133,7 +5269,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-a11y@npm:^6.5.13": +"@storybook/addon-a11y@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/addon-a11y@npm:6.5.16" dependencies: @@ -5165,7 +5301,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-actions@npm:6.5.16, @storybook/addon-actions@npm:^6.5.13": +"@storybook/addon-actions@npm:6.5.16, @storybook/addon-actions@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/addon-actions@npm:6.5.16" dependencies: @@ -5304,7 +5440,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-essentials@npm:^6.5.13": +"@storybook/addon-essentials@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/addon-essentials@npm:6.5.16" dependencies: @@ -5496,7 +5632,7 @@ __metadata: languageName: node linkType: hard -"@storybook/addons@npm:6.5.16, @storybook/addons@npm:^6.5.13": +"@storybook/addons@npm:6.5.16, @storybook/addons@npm:^6.5.14, @storybook/addons@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/addons@npm:6.5.16" dependencies: @@ -5518,7 +5654,7 @@ __metadata: languageName: node linkType: hard -"@storybook/api@npm:6.5.16, @storybook/api@npm:^6.5.13": +"@storybook/api@npm:6.5.16, @storybook/api@npm:^6.5.14, @storybook/api@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/api@npm:6.5.16" dependencies: @@ -5607,7 +5743,7 @@ __metadata: languageName: node linkType: hard -"@storybook/builder-webpack5@npm:^6.5.13": +"@storybook/builder-webpack5@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/builder-webpack5@npm:6.5.16" dependencies: @@ -5698,7 +5834,7 @@ __metadata: languageName: node linkType: hard -"@storybook/client-api@npm:6.5.16, @storybook/client-api@npm:^6.5.13": +"@storybook/client-api@npm:6.5.16, @storybook/client-api@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/client-api@npm:6.5.16" dependencies: @@ -5739,7 +5875,7 @@ __metadata: languageName: node linkType: hard -"@storybook/components@npm:6.5.16, @storybook/components@npm:^6.5.13": +"@storybook/components@npm:6.5.16, @storybook/components@npm:^6.5.14, @storybook/components@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/components@npm:6.5.16" dependencies: @@ -5857,7 +5993,7 @@ __metadata: languageName: node linkType: hard -"@storybook/core-events@npm:6.5.16, @storybook/core-events@npm:^6.5.13": +"@storybook/core-events@npm:6.5.16, @storybook/core-events@npm:^6.5.14, @storybook/core-events@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/core-events@npm:6.5.16" dependencies: @@ -5929,7 +6065,7 @@ __metadata: languageName: node linkType: hard -"@storybook/core@npm:6.5.16, @storybook/core@npm:^6.5.13": +"@storybook/core@npm:6.5.16, @storybook/core@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/core@npm:6.5.16" dependencies: @@ -6010,6 +6146,13 @@ __metadata: languageName: node linkType: hard +"@storybook/global@npm:^5.0.0": + version: 5.0.0 + resolution: "@storybook/global@npm:5.0.0" + checksum: ede0ad35ec411fe31c61150dbd118fef344d1d0e72bf5d3502368e35cf68126f6b7ae4a0ab5e2ffe2f0baa3b4286f03ad069ba3e098e1725449ef08b7e154ba8 + languageName: node + linkType: hard + "@storybook/manager-webpack4@npm:6.5.16": version: 6.5.16 resolution: "@storybook/manager-webpack4@npm:6.5.16" @@ -6059,7 +6202,7 @@ __metadata: languageName: node linkType: hard -"@storybook/manager-webpack5@npm:^6.5.13": +"@storybook/manager-webpack5@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/manager-webpack5@npm:6.5.16" dependencies: @@ -6191,7 +6334,7 @@ __metadata: languageName: node linkType: hard -"@storybook/react@npm:^6.5.13": +"@storybook/react@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/react@npm:6.5.16" dependencies: @@ -6367,7 +6510,7 @@ __metadata: languageName: node linkType: hard -"@storybook/test-runner@npm:^0.9.2": +"@storybook/test-runner@npm:^0.9.4": version: 0.9.4 resolution: "@storybook/test-runner@npm:0.9.4" dependencies: @@ -6407,7 +6550,7 @@ __metadata: languageName: node linkType: hard -"@storybook/theming@npm:6.5.16, @storybook/theming@npm:^6.5.13": +"@storybook/theming@npm:6.5.16, @storybook/theming@npm:^6.5.14, @storybook/theming@npm:^6.5.16": version: 6.5.16 resolution: "@storybook/theming@npm:6.5.16" dependencies: @@ -6472,15 +6615,6 @@ __metadata: languageName: node linkType: hard -"@szmarczak/http-timer@npm:^1.1.2": - version: 1.1.2 - resolution: "@szmarczak/http-timer@npm:1.1.2" - dependencies: - defer-to-connect: ^1.0.1 - checksum: 4d9158061c5f397c57b4988cde33a163244e4f02df16364f103971957a32886beb104d6180902cbe8b38cb940e234d9f98a4e486200deca621923f62f50a06fe - languageName: node - linkType: hard - "@szmarczak/http-timer@npm:^4.0.5": version: 4.0.6 resolution: "@szmarczak/http-timer@npm:4.0.6" @@ -7455,24 +7589,17 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^12.0.12": - version: 12.19.15 - resolution: "@types/node@npm:12.19.15" - checksum: 9672f6f33d2461105902e15cd21f9de34bb2c331a95d7baab499b5822e1547e0716051374647bb4e430e3f57b1dae820aca624fe9ef6dc4cc74acbaab8ec1eab - languageName: node - linkType: hard - -"@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0, @types/node@npm:^16.7.10": - version: 16.11.56 - resolution: "@types/node@npm:16.11.56" - checksum: b4efade16eb08a39810921c54a1637e69c8f3184a20d87e8fe74d557d9bda73f0829ac318e2a30a32b1903e4b099812defd1dfe438be70b98dbfbea5b0d99a53 +"@types/node@npm:^14.0.10 || ^16.0.0, @types/node@npm:^14.14.20 || ^16.0.0, @types/node@npm:^16.11.26, @types/node@npm:^16.7.10": + version: 16.18.26 + resolution: "@types/node@npm:16.18.26" + checksum: 2a746b3f9e97e00aa5d1d8cce36c5b75d5504df15e82647ad1fadbc3435ea4491203d044bbaa595edc2ab25a9ab820793f9d38dba753ad150929335fa21e24d4 languageName: node linkType: hard "@types/node@npm:^17.0.21": - version: 17.0.29 - resolution: "@types/node@npm:17.0.29" - checksum: bb9d7bce9d6d3882efd9d63b773b548dce98df4bd57eff8ceaa316aa2f3346e36d3618764cc93da84bbff92005174a35eec3465cde91ee973ef1c351ffa40074 + version: 17.0.45 + resolution: "@types/node@npm:17.0.45" + checksum: aa04366b9103b7d6cfd6b2ef64182e0eaa7d4462c3f817618486ea0422984c51fc69fd0d436eae6c9e696ddfdbec9ccaa27a917f7c2e8c75c5d57827fe3d95e8 languageName: node linkType: hard @@ -7640,6 +7767,13 @@ __metadata: languageName: node linkType: hard +"@types/semver@npm:^7.3.12": + version: 7.3.13 + resolution: "@types/semver@npm:7.3.13" + checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 + languageName: node + linkType: hard + "@types/sinon@npm:^10.0.13": version: 10.0.13 resolution: "@types/sinon@npm:10.0.13" @@ -7901,17 +8035,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/experimental-utils@npm:^5.3.0": - version: 5.34.0 - resolution: "@typescript-eslint/experimental-utils@npm:5.34.0" - dependencies: - "@typescript-eslint/utils": 5.34.0 - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: adbb3c64846a2a75f655f7985798e7d4a54c8ae1510ffddfeefc693908e605440dad27d83dce2d8425b7d304257ac68aa30cb31a99947e484205a126be804d97 - languageName: node - linkType: hard - "@typescript-eslint/parser@npm:^5.30.7": version: 5.30.7 resolution: "@typescript-eslint/parser@npm:5.30.7" @@ -7939,13 +8062,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.34.0": - version: 5.34.0 - resolution: "@typescript-eslint/scope-manager@npm:5.34.0" +"@typescript-eslint/scope-manager@npm:5.59.1": + version: 5.59.1 + resolution: "@typescript-eslint/scope-manager@npm:5.59.1" dependencies: - "@typescript-eslint/types": 5.34.0 - "@typescript-eslint/visitor-keys": 5.34.0 - checksum: 039893fa1b8d349427c642a24932dba7932be823f860ce191691d999cd77ac99c3cc743ecd9dd68ad58ba987626e77c1ec458dad9534623e136766b9f9c5c9bf + "@typescript-eslint/types": 5.59.1 + "@typescript-eslint/visitor-keys": 5.59.1 + checksum: ae7758181d0f18d1ad20abf95164553fa98c20410968d538ac7abd430ec59f69e30d4da16ad968d029feced1ed49abc65daf6685c996eb4529d798e8320204ff languageName: node linkType: hard @@ -7979,10 +8102,10 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:5.34.0": - version: 5.34.0 - resolution: "@typescript-eslint/types@npm:5.34.0" - checksum: 74ad0302ebac160d1b8178ff07183868018a9b558137c638140b24589ba71dbeccfcedf57156f4d6b7443b139e186ede24a01cba66132f0bda6f891d515878fb +"@typescript-eslint/types@npm:5.59.1": + version: 5.59.1 + resolution: "@typescript-eslint/types@npm:5.59.1" + checksum: 40ea7ccf59c4951797d3761e53c866a5979e07fbdabef9dc07d3a3f625a99d4318d5329ae8e628cdfdc0bb9bb6e6d8dfb740f33c7bf318e63fa0a863b9ae85c7 languageName: node linkType: hard @@ -8004,12 +8127,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.34.0": - version: 5.34.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.34.0" +"@typescript-eslint/typescript-estree@npm:5.59.1": + version: 5.59.1 + resolution: "@typescript-eslint/typescript-estree@npm:5.59.1" dependencies: - "@typescript-eslint/types": 5.34.0 - "@typescript-eslint/visitor-keys": 5.34.0 + "@typescript-eslint/types": 5.59.1 + "@typescript-eslint/visitor-keys": 5.59.1 debug: ^4.3.4 globby: ^11.1.0 is-glob: ^4.0.3 @@ -8018,7 +8141,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2b9dac41d6dc544a2f61384ef8ed6559a15bdc19d9e49257829441dd166dd0ca395f4f6b42c97fbb2f006b1a6e7c8907c149add7644267b638ec7f1c0d01de30 + checksum: e33081937225f38e717ac2f9e90c4a8c6b71b701923eea3e03be76d8c466f0d3c6a4ec1d65c9fc1da4f1989416d386305353c5b53aa736d3af9503061001e3eb languageName: node linkType: hard @@ -8056,19 +8179,21 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.34.0, @typescript-eslint/utils@npm:^5.10.0": - version: 5.34.0 - resolution: "@typescript-eslint/utils@npm:5.34.0" +"@typescript-eslint/utils@npm:^5.10.0, @typescript-eslint/utils@npm:^5.45.0": + version: 5.59.1 + resolution: "@typescript-eslint/utils@npm:5.59.1" dependencies: + "@eslint-community/eslint-utils": ^4.2.0 "@types/json-schema": ^7.0.9 - "@typescript-eslint/scope-manager": 5.34.0 - "@typescript-eslint/types": 5.34.0 - "@typescript-eslint/typescript-estree": 5.34.0 + "@types/semver": ^7.3.12 + "@typescript-eslint/scope-manager": 5.59.1 + "@typescript-eslint/types": 5.59.1 + "@typescript-eslint/typescript-estree": 5.59.1 eslint-scope: ^5.1.1 - eslint-utils: ^3.0.0 + semver: ^7.3.7 peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 6b05bb2bf5c492dec19ae8ee29550ede1c76cc46c5aa03c4b83aff4b1205611e3e03e7fbf3839d60acce8c596ee7cbf715117b474fdcfd47c6879d504a4c3401 + checksum: ca32c90efa57e937ebf812221e070c0604ca99f900fbca60578b42d40c923d5a94fd9503cf5918ecd75b687b68a1be562f7c6593a329bc40b880c95036a021c0 languageName: node linkType: hard @@ -8092,13 +8217,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.34.0": - version: 5.34.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.34.0" +"@typescript-eslint/visitor-keys@npm:5.59.1": + version: 5.59.1 + resolution: "@typescript-eslint/visitor-keys@npm:5.59.1" dependencies: - "@typescript-eslint/types": 5.34.0 + "@typescript-eslint/types": 5.59.1 eslint-visitor-keys: ^3.3.0 - checksum: b5574ce8363f905f0a11e14126ec606130bbcc151c326c004d0f510c8e4e884175a70e0299adb0a82ed817db469558d2d385137c09837249118e15cbfa47bff2 + checksum: f98e399147310cad67de718a8a6336f053d46753bade380c89ddac3dd49512555c3f613636b255ce0b5e2b004654d1c167eb5e53fc8085148b637a5afc20cdd8 languageName: node linkType: hard @@ -8508,9 +8633,9 @@ __metadata: languageName: node linkType: hard -"@whitespace/storybook-addon-html@npm:^5.1.1": - version: 5.1.1 - resolution: "@whitespace/storybook-addon-html@npm:5.1.1" +"@whitespace/storybook-addon-html@npm:^5.1.4": + version: 5.1.4 + resolution: "@whitespace/storybook-addon-html@npm:5.1.4" peerDependencies: "@storybook/addons": ^6.5.8 "@storybook/api": ^6.5.8 @@ -8526,7 +8651,7 @@ __metadata: optional: true react-dom: optional: true - checksum: 34bdd5e2ffeffeb7c6fb57e4c913dce4cbf87e118cfd6d26556fce0313e7233f1eaa17eb61da3eef3c8b8c345cf341f774a26e927c4d3a6aa791b8685ed66c92 + checksum: cd2b3da31774bf44f6cda1f91e77d627f601caee4050a01afe2f3c61d0d7e87e27bb6d7a32dd36208b4a0992b77f537c48cc55c683d50b7334212e8131a3ee93 languageName: node linkType: hard @@ -10351,6 +10476,13 @@ __metadata: languageName: node linkType: hard +"before-after-hook@npm:^2.2.0": + version: 2.2.3 + resolution: "before-after-hook@npm:2.2.3" + checksum: a1a2430976d9bdab4cd89cb50d27fa86b19e2b41812bf1315923b0cba03371ebca99449809226425dd3bcef20e010db61abdaff549278e111d6480034bebae87 + languageName: node + linkType: hard + "better-opn@npm:^2.1.1": version: 2.1.1 resolution: "better-opn@npm:2.1.1" @@ -11022,16 +11154,16 @@ __metadata: linkType: hard "browserslist@npm:^4.12.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4": - version: 4.21.4 - resolution: "browserslist@npm:4.21.4" + version: 4.21.5 + resolution: "browserslist@npm:4.21.5" dependencies: - caniuse-lite: ^1.0.30001400 - electron-to-chromium: ^1.4.251 - node-releases: ^2.0.6 - update-browserslist-db: ^1.0.9 + caniuse-lite: ^1.0.30001449 + electron-to-chromium: ^1.4.284 + node-releases: ^2.0.8 + update-browserslist-db: ^1.0.10 bin: browserslist: cli.js - checksum: 4af3793704dbb4615bcd29059ab472344dc7961c8680aa6c4bb84f05340e14038d06a5aead58724eae69455b8fade8b8c69f1638016e87e5578969d74c078b79 + checksum: 9755986b22e73a6a1497fd8797aedd88e04270be33ce66ed5d85a1c8a798292a65e222b0f251bafa1c2522261e237d73b08b58689d4920a607e5a53d56dc4706 languageName: node linkType: hard @@ -11363,21 +11495,6 @@ __metadata: languageName: node linkType: hard -"cacheable-request@npm:^6.0.0": - version: 6.1.0 - resolution: "cacheable-request@npm:6.1.0" - dependencies: - clone-response: ^1.0.2 - get-stream: ^5.1.0 - http-cache-semantics: ^4.0.0 - keyv: ^3.0.0 - lowercase-keys: ^2.0.0 - normalize-url: ^4.1.0 - responselike: ^1.0.2 - checksum: b510b237b18d17e89942e9ee2d2a077cb38db03f12167fd100932dfa8fc963424bfae0bfa1598df4ae16c944a5484e43e03df8f32105b04395ee9495e9e4e9f1 - languageName: node - linkType: hard - "cacheable-request@npm:^7.0.2": version: 7.0.2 resolution: "cacheable-request@npm:7.0.2" @@ -11512,9 +11629,9 @@ __metadata: linkType: hard "caniuse-lite@npm:^1.0.30001109, caniuse-lite@npm:^1.0.30001400, caniuse-lite@npm:^1.0.30001426": - version: 1.0.30001431 - resolution: "caniuse-lite@npm:1.0.30001431" - checksum: bc8ab55cd194e240152946b54bfaff7456180cc018674fc7ed134f4f502192405f6643f422feaa0a5e7cc02b5bac564cfac7771ac6d29f5d129482fcfe335ba1 + version: 1.0.30001482 + resolution: "caniuse-lite@npm:1.0.30001482" + checksum: a5f7681c860a29736f29350ebd81041c40b6aa7b2f94c50ed27284a0507e46dc79536dcfc05432504cfc80a0bf2070e4ad6fa704a9c0f3f32d47bed9059e98c2 languageName: node linkType: hard @@ -12469,7 +12586,7 @@ __metadata: languageName: node linkType: hard -"concat-stream@npm:^1.5.0, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.1, concat-stream@npm:^1.6.2, concat-stream@npm:~1.6.0": +"concat-stream@npm:^1.5.0, concat-stream@npm:^1.6.0, concat-stream@npm:^1.6.1, concat-stream@npm:~1.6.0": version: 1.6.2 resolution: "concat-stream@npm:1.6.2" dependencies: @@ -12511,16 +12628,6 @@ __metadata: languageName: node linkType: hard -"config-chain@npm:^1.1.11": - version: 1.1.12 - resolution: "config-chain@npm:1.1.12" - dependencies: - ini: ^1.3.4 - proto-list: ~1.2.1 - checksum: a16332f87212b4015afcdfc95fe42b40b162e7f10b4f4370ab3239979b6e69a41b4e6fb34d7891aa028a557f2340da236f810df433b18dfa5c408b2eb8489bf7 - languageName: node - linkType: hard - "configstore@npm:^3.0.0": version: 3.1.2 resolution: "configstore@npm:3.1.2" @@ -13455,15 +13562,6 @@ __metadata: languageName: node linkType: hard -"decompress-response@npm:^3.3.0": - version: 3.3.0 - resolution: "decompress-response@npm:3.3.0" - dependencies: - mimic-response: ^1.0.0 - checksum: 952552ac3bd7de2fc18015086b09468645c9638d98a551305e485230ada278c039c91116e946d07894b39ee53c0f0d5b6473f25a224029344354513b412d7380 - languageName: node - linkType: hard - "decompress-response@npm:^6.0.0": version: 6.0.0 resolution: "decompress-response@npm:6.0.0" @@ -13574,13 +13672,6 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^1.0.1": - version: 1.1.3 - resolution: "defer-to-connect@npm:1.1.3" - checksum: 9491b301dcfa04956f989481ba7a43c2231044206269eb4ab64a52d6639ee15b1252262a789eb4239fb46ab63e44d4e408641bae8e0793d640aee55398cb3930 - languageName: node - linkType: hard - "defer-to-connect@npm:^2.0.0": version: 2.0.1 resolution: "defer-to-connect@npm:2.0.1" @@ -13774,6 +13865,13 @@ __metadata: languageName: node linkType: hard +"deprecation@npm:^2.0.0, deprecation@npm:^2.3.1": + version: 2.3.1 + resolution: "deprecation@npm:2.3.1" + checksum: f56a05e182c2c195071385455956b0c4106fe14e36245b00c689ceef8e8ab639235176a96977ba7c74afb173317fac2e0ec6ec7a1c6d1e6eaa401c586c714132 + languageName: node + linkType: hard + "deps-regex@npm:^0.1.4": version: 0.1.4 resolution: "deps-regex@npm:0.1.4" @@ -13858,6 +13956,13 @@ __metadata: languageName: node linkType: hard +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: e46307d7264644975b71c104b9f028ed1d3d34b83a15b8a22373640ce5ea630e5640b1078b8ea15f202b54641da71e4aa7597093bd4b91f113db520a26a37449 + languageName: node + linkType: hard + "detect-node@npm:^2.0.4": version: 2.0.4 resolution: "detect-node@npm:2.0.4" @@ -14431,23 +14536,23 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.251": - version: 1.4.284 - resolution: "electron-to-chromium@npm:1.4.284" - checksum: be496e9dca6509dbdbb54dc32146fc99f8eb716d28a7ee8ccd3eba0066561df36fc51418d8bd7cf5a5891810bf56c0def3418e74248f51ea4a843d423603d10a +"electron-to-chromium@npm:^1.4.284": + version: 1.4.376 + resolution: "electron-to-chromium@npm:1.4.376" + checksum: 881351d25e0e983432c10844540bb664ee4c54f781b81b7247c36d6e617dc85305fd87ffb5de6d9630c6a54f4432afd8e97565a11c62bb77b63051e43cb8a942 languageName: node linkType: hard -"electron@npm:^11.1.0": - version: 11.5.0 - resolution: "electron@npm:11.5.0" +"electron@npm:^23.1.2": + version: 23.3.0 + resolution: "electron@npm:23.3.0" dependencies: - "@electron/get": ^1.0.1 - "@types/node": ^12.0.12 - extract-zip: ^1.0.3 + "@electron/get": ^2.0.0 + "@types/node": ^16.11.26 + extract-zip: ^2.0.1 bin: electron: cli.js - checksum: 9c7cc76bf2d10d3299ed60ca1461573e62f30a0e38520e6447f8544d369a1aa743c4b0c59fed9666b3c9c5ba4638d9d797edea1ea4379adbf21b79eb3949b7a0 + checksum: 3d2959d736f3d448f768d12d5d225b9569837695aa07706a6d5b8d6705f5fabaa643ed4b3319a35cec00234bdf7a15a86cabbe04439baff8c9ad7b9e2425c45d languageName: node linkType: hard @@ -14603,9 +14708,9 @@ __metadata: linkType: hard "env-paths@npm:^2.2.0": - version: 2.2.0 - resolution: "env-paths@npm:2.2.0" - checksum: ba2aea38301aafd69086be1f8cb453b92946e4840cb0de9d1c88a67e6f43a6174dcddb60b218ec36db8720b12de46b0d93c2f97ad9bbec6a267b479ab37debb6 + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e languageName: node linkType: hard @@ -15119,17 +15224,17 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-storybook@npm:^0.6.4": - version: 0.6.4 - resolution: "eslint-plugin-storybook@npm:0.6.4" +"eslint-plugin-storybook@npm:^0.6.10": + version: 0.6.11 + resolution: "eslint-plugin-storybook@npm:0.6.11" dependencies: "@storybook/csf": ^0.0.1 - "@typescript-eslint/experimental-utils": ^5.3.0 + "@typescript-eslint/utils": ^5.45.0 requireindex: ^1.1.0 ts-dedent: ^2.2.0 peerDependencies: eslint: ">=6" - checksum: 9bc1befb50ed741ee27f0492ba5c8c6c3d8d54a8ac53bd6c2054046a2918829d80b0f0ff916abe10c7e01fb45d29ec284ff9d19d0ef35d7812367b4f708756a3 + checksum: efb85688041d4fd02be0cc51f07803acffaa54fdf61c21e9ae9eb18f26e6b8aec50911cfa71855ff4322b377b62cd53e7bf549faf60df4f20b8840171eab0029 languageName: node linkType: hard @@ -16456,20 +16561,6 @@ __metadata: languageName: node linkType: hard -"extract-zip@npm:^1.0.3": - version: 1.7.0 - resolution: "extract-zip@npm:1.7.0" - dependencies: - concat-stream: ^1.6.2 - debug: ^2.6.9 - mkdirp: ^0.5.4 - yauzl: ^2.10.0 - bin: - extract-zip: cli.js - checksum: 011bab660d738614555773d381a6ba4815d98c1cfcdcdf027e154ebcc9fc8c9ef637b3ea5c9b2144013100071ee41722ed041fc9aacc60f6198ef747cac0c073 - languageName: node - linkType: hard - "extract-zip@npm:^2.0.1": version: 2.0.1 resolution: "extract-zip@npm:2.0.1" @@ -16549,7 +16640,7 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.0.0, fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d @@ -16794,7 +16885,7 @@ __metadata: languageName: node linkType: hard -"filenamify@npm:^4.1.0, filenamify@npm:^4.3.0": +"filenamify@npm:^4.3.0": version: 4.3.0 resolution: "filenamify@npm:4.3.0" dependencies: @@ -17126,6 +17217,15 @@ __metadata: languageName: node linkType: hard +"focus-lock@npm:^0.11.6": + version: 0.11.6 + resolution: "focus-lock@npm:0.11.6" + dependencies: + tslib: ^2.0.3 + checksum: 6a407c4c45f05f8258f92565541fc5f8043f576643a7603eb999e1a790173e08712056766ed034ccd31c6d6deed259dea558002712fa5ef2432fc6930b9c7a05 + languageName: node + linkType: hard + "follow-redirects@npm:^1.14.0, follow-redirects@npm:^1.14.9, follow-redirects@npm:^1.15.0": version: 1.15.2 resolution: "follow-redirects@npm:1.15.2" @@ -17722,7 +17822,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^4.0.0, get-stream@npm:^4.1.0": +"get-stream@npm:^4.0.0": version: 4.1.0 resolution: "get-stream@npm:4.1.0" dependencies: @@ -17960,18 +18060,17 @@ __metadata: languageName: node linkType: hard -"global-agent@npm:^2.0.2": - version: 2.1.12 - resolution: "global-agent@npm:2.1.12" +"global-agent@npm:^3.0.0": + version: 3.0.0 + resolution: "global-agent@npm:3.0.0" dependencies: boolean: ^3.0.1 - core-js: ^3.6.5 es6-error: ^4.1.1 matcher: ^3.0.0 roarr: ^2.15.3 semver: ^7.3.2 serialize-error: ^7.0.1 - checksum: 220c30f0ee19bf0a32a286d94b5d23c11b4f1c0a029b68a6ba22c25e0e9409dbe5e9e19e724cb4dd68e7be64f5fc5fd04cb0a897361f8e2fdda571438ecc37ad + checksum: 75074d80733b4bd5386c47f5df028e798018025beac0ab310e9908c72bf5639e408203e7bca0130d5ee01b5f4abc6d34385d96a9f950ea5fe1979bb431c808f7 languageName: node linkType: hard @@ -18050,18 +18149,6 @@ __metadata: languageName: node linkType: hard -"global-tunnel-ng@npm:^2.7.1": - version: 2.7.1 - resolution: "global-tunnel-ng@npm:2.7.1" - dependencies: - encodeurl: ^1.0.2 - lodash: ^4.17.10 - npm-conf: ^1.1.3 - tunnel: ^0.0.6 - checksum: b7e016093eab6058b5fdd8caea31c22dc1a607f0f0b41c001ade5e0227c5d74efe9ce9bae56316d794bc1cedd461a187b8b7e8f0a3eb4d194972cdfb9d860af2 - languageName: node - linkType: hard - "global@npm:^4.4.0": version: 4.4.0 resolution: "global@npm:4.4.0" @@ -18196,6 +18283,25 @@ __metadata: languageName: node linkType: hard +"got@npm:^11.8.5": + version: 11.8.6 + resolution: "got@npm:11.8.6" + dependencies: + "@sindresorhus/is": ^4.0.0 + "@szmarczak/http-timer": ^4.0.5 + "@types/cacheable-request": ^6.0.1 + "@types/responselike": ^1.0.0 + cacheable-lookup: ^5.0.3 + cacheable-request: ^7.0.2 + decompress-response: ^6.0.0 + http2-wrapper: ^1.0.0-beta.5.2 + lowercase-keys: ^2.0.0 + p-cancelable: ^2.0.0 + responselike: ^2.0.0 + checksum: bbc783578a8d5030c8164ef7f57ce41b5ad7db2ed13371e1944bef157eeca5a7475530e07c0aaa71610d7085474d0d96222c9f4268d41db333a17e39b463f45d + languageName: node + linkType: hard + "got@npm:^6.7.1": version: 6.7.1 resolution: "got@npm:6.7.1" @@ -18215,25 +18321,6 @@ __metadata: languageName: node linkType: hard -"got@npm:^9.6.0": - version: 9.6.0 - resolution: "got@npm:9.6.0" - dependencies: - "@sindresorhus/is": ^0.14.0 - "@szmarczak/http-timer": ^1.1.2 - cacheable-request: ^6.0.0 - decompress-response: ^3.3.0 - duplexer3: ^0.1.4 - get-stream: ^4.1.0 - lowercase-keys: ^1.0.1 - mimic-response: ^1.0.1 - p-cancelable: ^1.0.0 - to-readable-stream: ^1.0.0 - url-parse-lax: ^3.0.0 - checksum: 941807bd9704bacf5eb401f0cc1212ffa1f67c6642f2d028fd75900471c221b1da2b8527f4553d2558f3faeda62ea1cf31665f8b002c6137f5de8732f07370b0 - languageName: node - linkType: hard - "graceful-fs@npm:^4.0.0, graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.1.9, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.3, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.10 resolution: "graceful-fs@npm:4.2.10" @@ -22058,13 +22145,6 @@ __metadata: languageName: node linkType: hard -"json-buffer@npm:3.0.0": - version: 3.0.0 - resolution: "json-buffer@npm:3.0.0" - checksum: 0cecacb8025370686a916069a2ff81f7d55167421b6aa7270ee74e244012650dd6bce22b0852202ea7ff8624fce50ff0ec1bdf95914ccb4553426e290d5a63fa - languageName: node - linkType: hard - "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -22491,15 +22571,6 @@ __metadata: languageName: node linkType: hard -"keyv@npm:^3.0.0": - version: 3.1.0 - resolution: "keyv@npm:3.1.0" - dependencies: - json-buffer: 3.0.0 - checksum: bb7e8f3acffdbafbc2dd5b63f377fe6ec4c0e2c44fc82720449ef8ab54f4a7ce3802671ed94c0f475ae0a8549703353a2124561fcf3317010c141b32ca1ce903 - languageName: node - linkType: hard - "kind-of@npm:^2.0.1": version: 2.0.1 resolution: "kind-of@npm:2.0.1" @@ -23224,7 +23295,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.13.1, lodash@npm:^4.16.4, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4": +"lodash@npm:^4.13.1, lodash@npm:^4.16.4, lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -23314,7 +23385,7 @@ __metadata: languageName: node linkType: hard -"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": +"lowercase-keys@npm:^1.0.0": version: 1.0.1 resolution: "lowercase-keys@npm:1.0.1" checksum: 4d045026595936e09953e3867722e309415ff2c80d7701d067546d75ef698dac218a4f53c6d1d0e7368b47e45fd7529df47e6cb56fbb90523ba599f898b3d147 @@ -23951,6 +24022,8 @@ __metadata: version: 0.0.0-use.local resolution: "metamask-crx@workspace:." dependencies: + "@actions/core": ^1.10.0 + "@actions/github": ^5.1.1 "@babel/code-frame": ^7.12.13 "@babel/core": ^7.12.1 "@babel/eslint-parser": ^7.13.14 @@ -23978,6 +24051,7 @@ __metadata: "@lavamoat/lavapack": ^5.0.0 "@lavamoat/snow": ^1.5.0 "@material-ui/core": ^4.11.0 + "@metamask-institutional/portfolio-dashboard": 1.1.2 "@metamask/address-book-controller": ^2.0.0 "@metamask/announcement-controller": ^3.0.0 "@metamask/approval-controller": ^2.1.0 @@ -24006,7 +24080,7 @@ __metadata: "@metamask/jazzicon": ^2.0.0 "@metamask/key-tree": ^7.0.0 "@metamask/logo": ^3.1.1 - "@metamask/message-manager": ^4.0.0 + "@metamask/message-manager": ^5.0.0 "@metamask/metamask-eth-abis": ^3.0.0 "@metamask/notification-controller": ^2.0.0 "@metamask/obs-store": ^8.1.0 @@ -24020,7 +24094,7 @@ __metadata: "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.32.2" "@metamask/safe-event-emitter": ^2.0.0 "@metamask/scure-bip39": ^2.0.3 - "@metamask/signature-controller": ^1.0.0 + "@metamask/signature-controller": ^2.0.0 "@metamask/slip44": ^3.0.0 "@metamask/smart-transactions-controller": ^3.1.0 "@metamask/snaps-controllers": ^0.32.2 @@ -24042,22 +24116,22 @@ __metadata: "@sentry/integrations": ^6.0.0 "@sentry/types": ^6.0.1 "@sentry/utils": ^6.0.1 - "@storybook/addon-a11y": ^6.5.13 - "@storybook/addon-actions": ^6.5.13 - "@storybook/addon-essentials": ^6.5.13 + "@storybook/addon-a11y": ^6.5.16 + "@storybook/addon-actions": ^6.5.16 + "@storybook/addon-essentials": ^6.5.16 "@storybook/addon-knobs": ^6.4.0 - "@storybook/addons": ^6.5.13 - "@storybook/api": ^6.5.13 - "@storybook/builder-webpack5": ^6.5.13 - "@storybook/client-api": ^6.5.13 - "@storybook/components": ^6.5.13 - "@storybook/core": ^6.5.13 - "@storybook/core-events": ^6.5.13 - "@storybook/manager-webpack5": ^6.5.13 - "@storybook/react": ^6.5.13 + "@storybook/addons": ^6.5.16 + "@storybook/api": ^6.5.16 + "@storybook/builder-webpack5": ^6.5.16 + "@storybook/client-api": ^6.5.16 + "@storybook/components": ^6.5.16 + "@storybook/core": ^6.5.16 + "@storybook/core-events": ^6.5.16 + "@storybook/manager-webpack5": ^6.5.16 + "@storybook/react": ^6.5.16 "@storybook/storybook-deployer": ^2.8.16 - "@storybook/test-runner": ^0.9.2 - "@storybook/theming": ^6.5.13 + "@storybook/test-runner": ^0.9.4 + "@storybook/theming": ^6.5.16 "@testing-library/jest-dom": ^5.11.10 "@testing-library/react": ^10.4.8 "@testing-library/react-hooks": ^8.0.1 @@ -24091,7 +24165,7 @@ __metadata: "@types/yargs": ^17.0.8 "@typescript-eslint/eslint-plugin": ^5.30.7 "@typescript-eslint/parser": ^5.30.7 - "@whitespace/storybook-addon-html": ^5.1.1 + "@whitespace/storybook-addon-html": ^5.1.4 "@zxing/browser": ^0.0.10 "@zxing/library": 0.8.0 addons-linter: ^5.2.0 @@ -24138,7 +24212,7 @@ __metadata: eslint-plugin-prettier: ^4.2.1 eslint-plugin-react: ^7.23.1 eslint-plugin-react-hooks: ^4.2.0 - eslint-plugin-storybook: ^0.6.4 + eslint-plugin-storybook: ^0.6.10 eth-block-tracker: ^7.0.0 eth-ens-namehash: ^2.0.8 eth-json-rpc-filters: ^6.0.0 @@ -24233,6 +24307,7 @@ __metadata: react: ^16.12.0 react-devtools: ^4.11.0 react-dom: ^16.12.0 + react-focus-lock: ^2.9.4 react-idle-timer: ^4.2.5 react-inspector: ^2.3.0 react-markdown: ^6.0.3 @@ -24266,7 +24341,7 @@ __metadata: source-map: ^0.7.2 source-map-explorer: ^2.4.2 squirrelly: ^8.0.8 - storybook-dark-mode: ^1.1.0 + storybook-dark-mode: ^2.1.1 stream-browserify: ^3.0.0 string.prototype.matchall: ^4.0.2 style-loader: ^0.21.0 @@ -24446,7 +24521,7 @@ __metadata: languageName: node linkType: hard -"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": +"mimic-response@npm:^1.0.0": version: 1.0.1 resolution: "mimic-response@npm:1.0.1" checksum: 034c78753b0e622bc03c983663b1cdf66d03861050e0c8606563d149bc2b02d63f62ce4d32be4ab50d0553ae0ffe647fc34d1f5281184c6e1e8cf4d85e8d9823 @@ -24706,7 +24781,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.3, mkdirp@npm:^0.5.4, mkdirp@npm:^0.5.5, mkdirp@npm:^0.5.6": +"mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.3, mkdirp@npm:^0.5.5, mkdirp@npm:^0.5.6": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" dependencies: @@ -25443,10 +25518,10 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.6": - version: 2.0.6 - resolution: "node-releases@npm:2.0.6" - checksum: e86a926dc9fbb3b41b4c4a89d998afdf140e20a4e8dbe6c0a807f7b2948b42ea97d7fd3ad4868041487b6e9ee98409829c6e4d84a734a4215dff060a7fbeb4bf +"node-releases@npm:^2.0.8": + version: 2.0.10 + resolution: "node-releases@npm:2.0.10" + checksum: d784ecde25696a15d449c4433077f5cce620ed30a1656c4abf31282bfc691a70d9618bae6868d247a67914d1be5cc4fde22f65a05f4398cdfb92e0fc83cadfbc languageName: node linkType: hard @@ -25553,13 +25628,6 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^4.1.0": - version: 4.5.1 - resolution: "normalize-url@npm:4.5.1" - checksum: 9a9dee01df02ad23e171171893e56e22d752f7cff86fb96aafeae074819b572ea655b60f8302e2d85dbb834dc885c972cc1c573892fea24df46b2765065dd05a - languageName: node - linkType: hard - "normalize-url@npm:^6.0.1": version: 6.1.0 resolution: "normalize-url@npm:6.1.0" @@ -25583,16 +25651,6 @@ __metadata: languageName: node linkType: hard -"npm-conf@npm:^1.1.3": - version: 1.1.3 - resolution: "npm-conf@npm:1.1.3" - dependencies: - config-chain: ^1.1.11 - pify: ^3.0.0 - checksum: 2d4e933b657623d98183ec408d17318547296b1cd17c4d3587e2920c554675f24f829d8f5f7f84db3a020516678fdcd01952ebaaf0e7fa8a17f6c39be4154bef - languageName: node - linkType: hard - "npm-normalize-package-bin@npm:^1.0.0, npm-normalize-package-bin@npm:^1.0.1": version: 1.0.1 resolution: "npm-normalize-package-bin@npm:1.0.1" @@ -26178,13 +26236,6 @@ __metadata: languageName: node linkType: hard -"p-cancelable@npm:^1.0.0": - version: 1.1.0 - resolution: "p-cancelable@npm:1.1.0" - checksum: 2db3814fef6d9025787f30afaee4496a8857a28be3c5706432cbad76c688a6db1874308f48e364a42f5317f5e41e8e7b4f2ff5c8ff2256dbb6264bc361704ece - languageName: node - linkType: hard - "p-cancelable@npm:^2.0.0": version: 2.1.1 resolution: "p-cancelable@npm:2.1.1" @@ -27540,13 +27591,6 @@ __metadata: languageName: node linkType: hard -"prepend-http@npm:^2.0.0": - version: 2.0.0 - resolution: "prepend-http@npm:2.0.0" - checksum: 7694a9525405447662c1ffd352fcb41b6410c705b739b6f4e3a3e21cf5fdede8377890088e8934436b8b17ba55365a615f153960f30877bf0d0392f9e93503ea - languageName: node - linkType: hard - "preserve@npm:^0.2.0": version: 0.2.0 resolution: "preserve@npm:0.2.0" @@ -27823,13 +27867,6 @@ __metadata: languageName: node linkType: hard -"proto-list@npm:~1.2.1": - version: 1.2.4 - resolution: "proto-list@npm:1.2.4" - checksum: 4d4826e1713cbfa0f15124ab0ae494c91b597a3c458670c9714c36e8baddf5a6aad22842776f2f5b137f259c8533e741771445eb8df82e861eea37a6eaba03f7 - languageName: node - linkType: hard - "protobufjs@npm:^6.11.3": version: 6.11.3 resolution: "protobufjs@npm:6.11.3" @@ -28287,6 +28324,17 @@ __metadata: languageName: node linkType: hard +"react-clientside-effect@npm:^1.2.6": + version: 1.2.6 + resolution: "react-clientside-effect@npm:1.2.6" + dependencies: + "@babel/runtime": ^7.12.13 + peerDependencies: + react: ^15.3.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + checksum: 7db6110027a51458b1a46109d2b63dd822825f483c71afef7c0c0a671f3b1aa155049dbd8651c9d536ffac83601f8823b7c3f8916b4f4ee5c3cb7647a85cce4e + languageName: node + linkType: hard + "react-colorful@npm:^5.1.2": version: 5.3.0 resolution: "react-colorful@npm:5.3.0" @@ -28297,29 +28345,29 @@ __metadata: languageName: node linkType: hard -"react-devtools-core@npm:4.16.0": - version: 4.16.0 - resolution: "react-devtools-core@npm:4.16.0" +"react-devtools-core@npm:4.27.6": + version: 4.27.6 + resolution: "react-devtools-core@npm:4.27.6" dependencies: shell-quote: ^1.6.1 ws: ^7 - checksum: 93b9d49b3b9ffc0148dcf24ecf6bbf805eb8f28f0e8c35dc50e93c6566f6130cb74cd472ac770debb48ea863e5182af5d307c6b50554077b245b405010bd34b0 + checksum: c0ec5d798c1bbf8c8861677a5940ad552efbe7aa99f2a4aa04e2841605266bc93b2b5956890b5d6c5136f88c6a0c8d080b929dde89227ac56d4a7fb0e85fe55f languageName: node linkType: hard "react-devtools@npm:^4.11.0": - version: 4.16.0 - resolution: "react-devtools@npm:4.16.0" + version: 4.27.6 + resolution: "react-devtools@npm:4.27.6" dependencies: cross-spawn: ^5.0.1 - electron: ^11.1.0 + electron: ^23.1.2 ip: ^1.1.4 minimist: ^1.2.3 - react-devtools-core: 4.16.0 + react-devtools-core: 4.27.6 update-notifier: ^2.1.0 bin: react-devtools: bin.js - checksum: 65ba2e3a93bfa58b4c2c624de383adf87a91b7a1ebb5c74500ebf0edf30c7d752a78f36909a88ad5abedcd10411fb6dba414fdaea9173dddef56ccc230928449 + checksum: 95db5d2e2907c5b349a3fab70915c95ffc3196c4679b43b77ed78263d56919d5c6ec7ec05e3a2d31f975e5e1f51c7a0903b268207787b095b0cbb318e5070d67 languageName: node linkType: hard @@ -28405,6 +28453,26 @@ __metadata: languageName: node linkType: hard +"react-focus-lock@npm:^2.9.4": + version: 2.9.4 + resolution: "react-focus-lock@npm:2.9.4" + dependencies: + "@babel/runtime": ^7.0.0 + focus-lock: ^0.11.6 + prop-types: ^15.6.2 + react-clientside-effect: ^1.2.6 + use-callback-ref: ^1.3.0 + use-sidecar: ^1.1.2 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: f4c696bdbde5008560388622b994c00502d1faeeabff32b02964770c8c020208872f5f6b914b249a8bf3e97cc12e58bb0d227cd33460093654156b7b7f4c8d76 + languageName: node + linkType: hard + "react-idle-timer@npm:^4.2.5": version: 4.2.5 resolution: "react-idle-timer@npm:4.2.5" @@ -29047,7 +29115,7 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.9": +"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.9": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 @@ -29789,15 +29857,6 @@ __metadata: languageName: node linkType: hard -"responselike@npm:^1.0.2": - version: 1.0.2 - resolution: "responselike@npm:1.0.2" - dependencies: - lowercase-keys: ^1.0.0 - checksum: 2e9e70f1dcca3da621a80ce71f2f9a9cad12c047145c6ece20df22f0743f051cf7c73505e109814915f23f9e34fb0d358e22827723ee3d56b623533cab8eafcd - languageName: node - linkType: hard - "responselike@npm:^2.0.0": version: 2.0.1 resolution: "responselike@npm:2.0.1" @@ -30468,7 +30527,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:7.3.8, semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": +"semver@npm:7.3.8": version: 7.3.8 resolution: "semver@npm:7.3.8" dependencies: @@ -30488,6 +30547,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.0.0, semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": + version: 7.5.0 + resolution: "semver@npm:7.5.0" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b + languageName: node + linkType: hard + "semver@npm:~5.4.1": version: 5.4.1 resolution: "semver@npm:5.4.1" @@ -31437,19 +31507,27 @@ __metadata: languageName: node linkType: hard -"storybook-dark-mode@npm:^1.1.0": - version: 1.1.0 - resolution: "storybook-dark-mode@npm:1.1.0" - dependencies: - fast-deep-equal: ^3.0.0 +"storybook-dark-mode@npm:^2.1.1": + version: 2.1.1 + resolution: "storybook-dark-mode@npm:2.1.1" + dependencies: + "@storybook/addons": ^6.5.14 + "@storybook/api": ^6.5.14 + "@storybook/components": ^6.5.14 + "@storybook/core-events": ^6.5.14 + "@storybook/global": ^5.0.0 + "@storybook/theming": ^6.5.14 + fast-deep-equal: ^3.1.3 memoizerific: ^1.11.3 peerDependencies: - "@storybook/addons": ^6.0.0 - "@storybook/api": ^6.0.0 - "@storybook/components": ^6.0.0 - "@storybook/core-events": ^6.0.0 - "@storybook/theming": ^6.0.0 - checksum: e1d7abbb96d1cdbe9cdba1e20aabffa6878f170e348958cc328de4183027c2052f44f6d78f82a45039f803349c7a4ec19988d42898030b2720dc591192f520e6 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + checksum: 44d6313013a1d63f47c95e2e8e0d11c24d467b3540259e152ceb3236636dbadf7a46c6f7f183946b105ee53173cb13815f1f88ca6da41fc74673c3c11f619863 languageName: node linkType: hard @@ -32748,13 +32826,6 @@ __metadata: languageName: node linkType: hard -"to-readable-stream@npm:^1.0.0": - version: 1.0.0 - resolution: "to-readable-stream@npm:1.0.0" - checksum: 2bd7778490b6214a2c40276065dd88949f4cf7037ce3964c76838b8cb212893aeb9cceaaf4352a4c486e3336214c350270f3263e1ce7a0c38863a715a4d9aeb5 - languageName: node - linkType: hard - "to-regex-range@npm:^2.1.0": version: 2.1.1 resolution: "to-regex-range@npm:2.1.1" @@ -33597,6 +33668,13 @@ __metadata: languageName: node linkType: hard +"universal-user-agent@npm:^6.0.0": + version: 6.0.0 + resolution: "universal-user-agent@npm:6.0.0" + checksum: 5092bbc80dd0d583cef0b62c17df0043193b74f425112ea6c1f69bc5eda21eeec7a08d8c4f793a277eb2202ffe9b44bec852fa3faff971234cd209874d1b79ef + languageName: node + linkType: hard + "universalify@npm:^0.1.0, universalify@npm:^0.1.2": version: 0.1.2 resolution: "universalify@npm:0.1.2" @@ -33658,17 +33736,17 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.9": - version: 1.0.10 - resolution: "update-browserslist-db@npm:1.0.10" +"update-browserslist-db@npm:^1.0.10": + version: 1.0.11 + resolution: "update-browserslist-db@npm:1.0.11" dependencies: escalade: ^3.1.1 picocolors: ^1.0.0 peerDependencies: browserslist: ">= 4.21.0" bin: - browserslist-lint: cli.js - checksum: 12db73b4f63029ac407b153732e7cd69a1ea8206c9100b482b7d12859cd3cd0bc59c602d7ae31e652706189f1acb90d42c53ab24a5ba563ed13aebdddc5561a0 + update-browserslist-db: cli.js + checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 languageName: node linkType: hard @@ -33748,15 +33826,6 @@ __metadata: languageName: node linkType: hard -"url-parse-lax@npm:^3.0.0": - version: 3.0.0 - resolution: "url-parse-lax@npm:3.0.0" - dependencies: - prepend-http: ^2.0.0 - checksum: 1040e357750451173132228036aff1fd04abbd43eac1fb3e4fca7495a078bcb8d33cb765fe71ad7e473d9c94d98fd67adca63bd2716c815a2da066198dd37217 - languageName: node - linkType: hard - "url@npm:^0.11.0, url@npm:~0.11.0": version: 0.11.0 resolution: "url@npm:0.11.0" @@ -33767,6 +33836,37 @@ __metadata: languageName: node linkType: hard +"use-callback-ref@npm:^1.3.0": + version: 1.3.0 + resolution: "use-callback-ref@npm:1.3.0" + dependencies: + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 7913df383a5a6fcb399212eedefaac2e0c6f843555202d4e3010bac3848afe38ecaa3d0d6500ad1d936fbeffd637e6c517e68edb024af5e6beca7f27f3ce7b21 + languageName: node + linkType: hard + +"use-sidecar@npm:^1.1.2": + version: 1.1.2 + resolution: "use-sidecar@npm:1.1.2" + dependencies: + detect-node-es: ^1.1.0 + tslib: ^2.0.0 + peerDependencies: + "@types/react": ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 925d1922f9853e516eaad526b6fed1be38008073067274f0ecc3f56b17bb8ab63480140dd7c271f94150027c996cea4efe83d3e3525e8f3eda22055f6a39220b + languageName: node + linkType: hard + "use@npm:^3.1.0": version: 3.1.0 resolution: "use@npm:3.1.0"