From db4c4317dd32ce46566ff18625dc12b1e5ba54f6 Mon Sep 17 00:00:00 2001 From: "sumit shinde ( Roni )" <110285294+sumitshinde-84@users.noreply.github.com> Date: Mon, 24 Apr 2023 14:48:14 +0530 Subject: [PATCH 01/60] Update knobs to controls in storybook: SelectQuotePopover (#18671) * Update knobs to controls in storybook: SelectQuotePopover * Update select-quote-popover.stories.js * Update select-quote-popover.stories.js * fix eslint * Update ui/pages/swaps/select-quote-popover/select-quote-popover.stories.js Co-authored-by: George Marshall --------- Co-authored-by: George Marshall Co-authored-by: George Marshall --- .../select-quote-popover.stories.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/ui/pages/swaps/select-quote-popover/select-quote-popover.stories.js b/ui/pages/swaps/select-quote-popover/select-quote-popover.stories.js index 0da8e42c3..69bedcce5 100644 --- a/ui/pages/swaps/select-quote-popover/select-quote-popover.stories.js +++ b/ui/pages/swaps/select-quote-popover/select-quote-popover.stories.js @@ -1,6 +1,4 @@ import React, { useState } from 'react'; -import { action } from '@storybook/addon-actions'; -import { object } from '@storybook/addon-knobs'; import Button from '../../../components/ui/button'; import mockQuoteData from './mock-quote-data'; import README from './README.mdx'; @@ -29,11 +27,16 @@ export default { options: ['Agg1', 'Agg2', 'Agg3', 'Agg4', 'Agg5', 'Agg6'], }, quoteDataRows: { - control: 'object', + control: { + type: 'object', + }, }, hideEstimatedGasFee: { control: 'boolean', }, + onSubmit: { + action: 'onSubmit', + }, }, args: { quoteDataRows: mockQuoteData, @@ -43,14 +46,19 @@ export default { export const DefaultStory = (args) => { const [showPopover, setShowPopover] = useState(false); + const handleSubmit = () => { + setShowPopover(false); + args.onSubmit(); + }; + return (
{showPopover && ( setShowPopover(false)} - onSubmit={action('submit SelectQuotePopover')} + onSubmit={handleSubmit} swapToSymbol={args.swapToSymbol || 'DAI'} initialAggId={args.initialAggId || 'Agg4'} hideEstimatedGasFee={args.hideEstimatedGasFee || false} From b53d335b2c03f0cdaf4c21bdb9a30368e6568844 Mon Sep 17 00:00:00 2001 From: Ananyamadhu08 <78725970+Ananyamadhu08@users.noreply.github.com> Date: Mon, 24 Apr 2023 14:49:35 +0530 Subject: [PATCH 02/60] Part of 17670: Replace Typography with Text in detected-token-address.js (#18435) * feat: replaced typography with text comp * fix: changed h7 to h6 --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../detected-token-address.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/components/app/detected-token/detected-token-address/detected-token-address.js b/ui/components/app/detected-token/detected-token-address/detected-token-address.js index 9ae894aaf..2e752bce1 100644 --- a/ui/components/app/detected-token/detected-token-address/detected-token-address.js +++ b/ui/components/app/detected-token/detected-token-address/detected-token-address.js @@ -6,16 +6,16 @@ import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard'; import Box from '../../../ui/box'; import Button from '../../../ui/button'; -import Typography from '../../../ui/typography'; import Tooltip from '../../../ui/tooltip'; import { DISPLAY, TextColor, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import { shortenAddress } from '../../../../helpers/utils/util'; +import { Text } from '../../../component-library'; const DetectedTokenAddress = ({ tokenAddress }) => { const t = useI18nContext(); @@ -23,17 +23,18 @@ const DetectedTokenAddress = ({ tokenAddress }) => { return ( - + {`${t('tokenAddress')}:`} - - + {shortenAddress(tokenAddress)} - + Date: Mon, 24 Apr 2023 14:51:40 +0530 Subject: [PATCH 03/60] Part of #17670: Replace Typography with Text component (#18569) Co-authored-by: Om Raval Co-authored-by: Brad Decker --- .../smart-transaction-status.js | 62 +++++++++---------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js b/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js index 3b5851543..a1fee0351 100644 --- a/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js +++ b/ui/pages/swaps/smart-transaction-status/smart-transaction-status.js @@ -32,12 +32,12 @@ import { DEFAULT_ROUTE, BUILD_QUOTE_ROUTE, } from '../../../helpers/constants/routes'; -import Typography from '../../../components/ui/typography'; +import { Text } from '../../../components/component-library'; import Box from '../../../components/ui/box'; import UrlIcon from '../../../components/ui/url-icon'; import { BLOCK_SIZES, - TypographyVariant, + TextVariant, JustifyContent, DISPLAY, FONT_WEIGHT, @@ -330,21 +330,17 @@ export default function SmartTransactionStatusPage() { justifyContent={JustifyContent.center} alignItems={AlignItems.center} > - + {`${fetchParams?.value && Number(fetchParams.value).toFixed(5)} `} - - + {fetchParamsSourceTokenInfo.symbol ?? latestSmartTransaction?.sourceTokenSymbol} - + {fetchParamsSourceTokenInfo.iconUrl ? ( ) : null} - {`~${destinationValue && Number(destinationValue).toFixed(5)} `} - - + {fetchParamsDestinationTokenInfo.symbol ?? latestSmartTransaction?.destinationTokenSymbol} - + - {`${t('stxSwapCompleteIn')} `} - - + {showRemainingTimeInMinAndSec(timeLeftForPendingStxInSec)} - + )} - {headerText} - + {isSmartTransactionPending && (
)} {description && ( - {description} - + )} {blockExplorerUrl && ( {subDescription && ( - {subDescription} - + )} {showCancelSwapLink && From ff9683687149c2d02a60afcf17f17b16003f63e2 Mon Sep 17 00:00:00 2001 From: David Drazic Date: Mon, 24 Apr 2023 12:21:37 +0200 Subject: [PATCH 04/60] [FLASK] Add updated version of the Snaps settings UI (#18438) * Add updated version of the Snaps list UI Add more changes to match the designs of snaps list Add next design iteration for snaps list Update icons, sizes and pointer behaviour Add redesign for snap settings page Refactor and improve designs Fix unit tests and refactor code Fix e2e test Fix lint Update margin values Add CSS override for connected sites list and update margins Update paddings as requested Fix vertical alignment of links Fix tooltip position on the enable button Add usage of getSnapName function for displaying snap names Fix e2e tests and update date format for snap install date Improve unit test for snap-settings-card Change installation info logic Update mocked state for snap Add tests for ViewSnap component, refactor and update mocked state Add check for version info Change Snaps icon in Settings Refactor Snaps list to use selector Add handling in case of missing version history * Fix icon ref * Remove console logs * Remove onClick from selector * Add code fencing for imports in selectors.js --- app/_locales/de/messages.json | 31 -- app/_locales/el/messages.json | 31 -- app/_locales/en/messages.json | 41 +-- app/_locales/es/messages.json | 31 -- app/_locales/es_419/messages.json | 12 - app/_locales/fr/messages.json | 31 -- app/_locales/hi/messages.json | 31 -- app/_locales/id/messages.json | 31 -- app/_locales/it/messages.json | 4 - app/_locales/ja/messages.json | 31 -- app/_locales/ko/messages.json | 31 -- app/_locales/pt/messages.json | 31 -- app/_locales/pt_BR/messages.json | 12 - app/_locales/ru/messages.json | 31 -- app/_locales/tl/messages.json | 31 -- app/_locales/tr/messages.json | 31 -- app/_locales/vi/messages.json | 31 -- app/_locales/zh_CN/messages.json | 31 -- test/data/mock-state.json | 38 ++- test/e2e/snaps/test-snap-management.spec.js | 13 +- .../app/flask/snap-avatar/snap-avatar.js | 2 +- .../app/flask/snap-settings-card/index.scss | 56 +--- .../snap-settings-card/snap-settings-card.js | 262 +++------------- .../snap-settings-card.test.js | 90 ++---- ui/components/app/tab-bar/tab-bar.stories.js | 2 +- .../settings/flask/snaps-list-tab/index.scss | 9 +- .../flask/snaps-list-tab/snap-list-tab.js | 34 +- ui/pages/settings/flask/view-snap/index.scss | 147 +++------ .../settings/flask/view-snap/view-snap.js | 296 ++++++++++-------- .../flask/view-snap/view-snap.test.js | 81 +++++ ui/pages/settings/settings.component.js | 2 +- ui/selectors/selectors.js | 26 ++ 32 files changed, 454 insertions(+), 1107 deletions(-) create mode 100644 ui/pages/settings/flask/view-snap/view-snap.test.js diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 88153ba68..d56c2fe06 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -695,10 +695,6 @@ "message": "$1 ist mit keiner Site verbunden.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1-Snap ist mit diesen Sites verbunden. Sie haben Zugriff auf die oben aufgeführten Berechtigungen.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Verbinden..." }, @@ -1355,18 +1351,6 @@ "message": "Dateiimport fehlgeschlagen? Bitte hier klicken!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Details ansehen", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Hinzugefügt am", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "von", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "Sie sollten diese Erweiterung deinstallieren", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Keine passenden Ergebnisse gefunden." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Zeigen" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Intelligente Transaktionen" }, - "snapAccess": { - "message": "$1-Snap hat Zugriff auf:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Am $1 von $2 hinzugefügt", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Diese Inhalte stammen von $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Verwalten Sie Ihre Snaps" }, - "snapsStatus": { - "message": "Snap-Status ist von der Aktivität abhängig." - }, "snapsToggle": { "message": "Ein Snap wird nur ausgeführt, wenn er aktiviert ist" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index c3aa83b1f..11a5bdf85 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -695,10 +695,6 @@ "message": "$1 δεν είναι συνδεδεμένο με καμία τοποθεσία.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Το snap $1 συνδέεται με αυτούς τους ιστότοπους. Έχουν πρόσβαση στις παραπάνω άδειες.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Σύνδεση..." }, @@ -1355,18 +1351,6 @@ "message": "Η εισαγωγή αρχείων δεν λειτουργεί; Κάντε κλικ εδώ!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Προβολή λεπτομερειών", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Προστέθηκε στις", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "από", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "θα πρέπει να καταργήσετε την εγκατάσταση αυτής της επέκτασης", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Δε βρέθηκαν αποτελέσματα που να ταιριάζουν." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Εμφάνιση" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Έξυπνη Συναλλαγή" }, - "snapAccess": { - "message": "Το snap $1 έχει πρόσβαση σε:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Προστέθηκε στις $1 από $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Αυτό το περιεχόμενο προέρχεται από το $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Διαχειριστείτε τα Snaps σας" }, - "snapsStatus": { - "message": "Η κατάσταση του Snap εξαρτάται από τη δραστηριότητα." - }, "snapsToggle": { "message": "Ένα snap θα εκτελεστεί μόνο εάν είναι ενεργοποιημένο" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 451ea68a7..df8a1d895 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -771,10 +771,6 @@ "message": "$1 is not connected to any sites.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 snap is connected to these sites. They have access to the permissions listed above.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Connecting..." }, @@ -1328,6 +1324,12 @@ "enableSmartTransactions": { "message": "Enable smart transactions" }, + "enableSnap": { + "message": "Enable snap" + }, + "enableSnapDescription": { + "message": "Your installed snap will only have access to its permissions and run if it’s enabled." + }, "enableToken": { "message": "enable $1", "description": "$1 is a token symbol, e.g. ETH" @@ -1478,18 +1480,6 @@ "fileTooBig": { "message": "The dropped file is too big." }, - "flaskSnapSettingsCardButtonCta": { - "message": "See details", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Added on", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "from", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "you should uninstall this extension", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3574,10 +3564,6 @@ "settingsSearchMatchingNotFound": { "message": "No matching results found." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Show" }, @@ -3654,14 +3640,6 @@ "smartTransaction": { "message": "Smart transaction" }, - "snapAccess": { - "message": "$1 snap has access to:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Added on $1 from $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "This content is coming from $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3733,9 +3711,6 @@ "snapsSettingsDescription": { "message": "Manage your Snaps" }, - "snapsStatus": { - "message": "Snap status is dependent on activity." - }, "snapsToggle": { "message": "A snap will only run if it is enabled" }, @@ -4883,6 +4858,10 @@ "message": "You've added all the popular networks. You can discover more networks $1 Or you can $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" }, + "youInstalled": { + "message": "You installed", + "description": "Part of version description for installed snap" + }, "youNeedToAllowCameraAccess": { "message": "You need to allow camera access to use this feature." }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 05ea8c314..6d0036fa4 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -695,10 +695,6 @@ "message": "$1 no está conectado a ningún sitio.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "El complemento de $1 está conectado a estos sitios. Tienen acceso a los permisos enumerados anteriormente.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Estableciendo conexión…" }, @@ -1355,18 +1351,6 @@ "message": "¿No funciona la importación del archivo? Haga clic aquí.", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Ver detalles", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Añadido el", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "de", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "le recomendamos que desinstale esta extensión", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "No se encontraron resultados coincidentes." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Mostrar" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Transacción inteligente" }, - "snapAccess": { - "message": "El complemento de $1 tiene acceso a:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Se agregó en $1 de $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Este contenido proviene de $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Administre sus complementos" }, - "snapsStatus": { - "message": "El estado del complemento depende de la actividad." - }, "snapsToggle": { "message": "Un complemento solo se ejecutará si está habilitado" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index e46218f14..98254c6fc 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -882,18 +882,6 @@ "message": "¿No funciona la importación del archivo? ¡Haga clic aquí!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Ver detalles", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Añadido el", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "de", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "le recomendamos que desinstale esta extensión", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 23da974ab..42b38286c 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -695,10 +695,6 @@ "message": "$1 n’est connecté à aucun site.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Le snap $1 est connecté à ces sites. Ils ont accès aux autorisations énumérées ci-dessus.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Connexion…" }, @@ -1355,18 +1351,6 @@ "message": "L’importation de fichier ne fonctionne pas ? Cliquez ici !", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Voir les détails", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Ajouté le", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "de", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "vous devriez désinstaller cette extension", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Aucun résultat correspondant trouvé." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Afficher" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Transaction intelligente" }, - "snapAccess": { - "message": "Le snap $1 peut accéder à :", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Ajouté le $1 à partir de $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Ce contenu provient de $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Gérez vos Snaps" }, - "snapsStatus": { - "message": "L’état du Snap dépend de l’activité." - }, "snapsToggle": { "message": "Un snap ne s’exécute que s’il est activé" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 2299802ba..a868af14d 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -695,10 +695,6 @@ "message": "$1 किसी भी साइट से कनेक्ट नहीं है।", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 स्नैप इन साइटों से जुड़ा है। वे ऊपर सूचीबद्ध अनुमतियों को एक्सेस कर सकती हैं।", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "कनेक्ट किया जा रहा है..." }, @@ -1355,18 +1351,6 @@ "message": "फाइल आयात काम नहीं कर रहा है? यहां क्लिक करें!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "विवरण देखें", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "जोड़ा गया", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "से", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "आपको इस एक्सटेन्शन को अनइंस्टाल करना चाहिए", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "कोई मेल खाने वाला परिणाम नहीं मिला।" }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "दिखाएं" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "स्मार्ट लेनदेन" }, - "snapAccess": { - "message": "$1 स्नैप को एक्सेस है:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "$2 से $1 जोड़ा गया", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "यह सामग्री $1 से आ रही है", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "अपने स्नैप्स प्रबंधित करें" }, - "snapsStatus": { - "message": "स्नैप स्टेटस एक्टिविटी पर निर्भर करता है।" - }, "snapsToggle": { "message": "कोई स्नैप तभी चलेगा जब उसे सक्षम किया गया हो" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 7fe302c56..81e8d6d71 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -695,10 +695,6 @@ "message": "$1 tidak terhubung ke situs mana pun.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Snap $1 terhubung ke situs-situs ini. Token ini memiliki akses ke izin yang tercantum di atas. \t", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Menghubungkan..." }, @@ -1355,18 +1351,6 @@ "message": "Impor file tidak bekerja? Klik di sini!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Lihat detailnya", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Ditambahkan di", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "dari", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "Anda harus menghapus ekstensi ini", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Tidak menemukan hasil yang cocok." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Tampil" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Transaksi pintar" }, - "snapAccess": { - "message": "Snap $1 memiliki akses ke:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Ditambahkan pada $1 dari $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Konten ini berasal dari $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Kelola Snap Anda" }, - "snapsStatus": { - "message": "Status snap tergantung pada aktivitas." - }, "snapsToggle": { "message": "Snap hanya akan beroperasi jika diaktifkan" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 6ed51025d..fc9e9a4d1 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -538,10 +538,6 @@ "message": "$1 non è connesso ad alcun sito.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 snap è collegato a questi siti. Hanno accesso alle autorizzazioni sopra elencate.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Connessione..." }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 30667b7df..632b32d10 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -695,10 +695,6 @@ "message": "$1はどのサイトとも接続されていません。", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 スナップはこれらのサイトに接続されており、上記のパーミッションにアクセスできます。", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "接続中..." }, @@ -1355,18 +1351,6 @@ "message": "ファイルのインポートが機能していない場合ここをクリックしてください!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "詳細を表示", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "追加日", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "元", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "この拡張機能はアンインストールしてください", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "一致する結果が見つかりませんでした。" }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "表示" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "スマートトランザクション" }, - "snapAccess": { - "message": "$1 スナップは次にアクセス可能です:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "$1 に $2 から追加", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "このコンテンツは $1 からのものです", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "スナップの管理" }, - "snapsStatus": { - "message": "スナップのステータスはアクティビティによります。" - }, "snapsToggle": { "message": "スナップは有効になっている場合にのみ実行されます" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 65c96401b..76a8f0b22 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -695,10 +695,6 @@ "message": "$1 계정은 어떤 사이트에도 연결되어 있지 않습니다.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 스냅이 이 사이트에 연결되어 있습니다. 이 사이트는 위에 나열된 접근 권한이 있습니다.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "연결 중..." }, @@ -1355,18 +1351,6 @@ "message": "파일 가져오기가 작동하지 않나요? 여기를 클릭하세요.", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "세부 정보 보기", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "추가하기", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "발신", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "이 확장 프로그램을 삭제해야 합니다", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "검색 결과가 없습니다." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "보기" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "스마트 트랜잭션" }, - "snapAccess": { - "message": "$1 스냅이 접근할 수 있는 대상:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "$1에 $2에서 추가됨", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "콘텐츠 출처: $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "스냅 관리" }, - "snapsStatus": { - "message": "스냅 상태는 활동에 따라 달라집니다." - }, "snapsToggle": { "message": "스냅은 활성화된 상태에서만 작동합니다." }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 7db95bf79..0d06c5bcb 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -695,10 +695,6 @@ "message": "$1 não está conectada a nenhum site.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "O snap $1 está conectado a estes sites. Eles têm acesso às permissões listadas acima.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Conectando..." }, @@ -1355,18 +1351,6 @@ "message": "A importação de ficheiro não está a funcionar? Carregue aqui!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Ver detalhes", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Adicionado em", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "de", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "você deve desinstalar essa extensão", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Nenhum resultado correspondente encontrado." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Exibir" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Transação inteligente" }, - "snapAccess": { - "message": "Snap $1 tem acesso a:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Adicionado em $1 a partir de $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Esse conteúdo vem de $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Gerencie seus snaps" }, - "snapsStatus": { - "message": "O status do snap depende da atividade." - }, "snapsToggle": { "message": "O snap só será executado se estiver ativado" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index 73ec8f5c3..6c949ccfc 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -882,18 +882,6 @@ "message": "A importação de arquivo não está funcionando? Clique aqui!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Ver detalhes", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Adicionado em", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "de", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "você deve desinstalar essa extensão", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 026e36730..04fe18e52 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -695,10 +695,6 @@ "message": "$1 не подключен ни к каким сайтам.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Снап $1 подключен к этим сайтам. У них есть доступ к перечисленным выше разрешениям.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Подключение..." }, @@ -1355,18 +1351,6 @@ "message": "Импорт файлов не работает? Нажмите здесь!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "См. подробности", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Добавлена", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "от", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "вам нужно должны удалить это расширение", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Совпадений не найдено." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Показать" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Смарт-транзакция" }, - "snapAccess": { - "message": "У снапа $1 есть доступ к:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Добавлено на $1 из $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Этот контент поступает от $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Управление вашим снапами" }, - "snapsStatus": { - "message": "Статус снапа зависит от активности." - }, "snapsToggle": { "message": "Снап будет работать только в том случае, если он включен" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 4d2957f89..847e1d3eb 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -695,10 +695,6 @@ "message": "Ang $1 ay hindi nakakonekta sa anumang site.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Ang $1 snap ay konektado sa mga site na ito. May access sila sa mga pahintulot na nakalista sa itaas.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Kumokonekta..." }, @@ -1355,18 +1351,6 @@ "message": "Hindi gumagana ang pag-import ng file? Mag-click dito!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Tingnan ang mga detalye", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Dinagdag sa", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "mula sa", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "dapat mong i-uninstall ang extension na ito", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Walang nakitang katugmang resulta." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Ipakita" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Smart Transaction" }, - "snapAccess": { - "message": "Ang $1 snap ay may access sa:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Idinagdag noong $1 mula sa $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Ang nilalamang ito ay nagmumula sa $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Pamahalaan ang iyong mga Snap" }, - "snapsStatus": { - "message": "Ang lagay ng Snap ay nakadepende sa aktibidad." - }, "snapsToggle": { "message": "Tatakbo lamang ang snap kapag pinagana ito" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index f4d61422f..b6be9fdce 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -695,10 +695,6 @@ "message": "$1 herhangi bir siteye bağlanmamış.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1 snap bu sitelere bağlı. Yukarıda listelenen izinlere erişimleri vardır.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Bağlanıyor..." }, @@ -1355,18 +1351,6 @@ "message": "Dosya içe aktarma çalışmıyor mu? Buraya tıklayın!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Ayrıntıları gör", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Şu tarihte eklendi:", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "şurada:", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "bu uzantıyı kaldırmalısın", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Eşleşen sonuç bulunamadı." }, - "shorthandVersion": { - "message": "s$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Göster" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Akıllı işlem" }, - "snapAccess": { - "message": "$1 snap'in şunlara erişimi vardır:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "$1 tarihinde $2 alanından eklendi", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Bu içerik $1 kaynaklıdır", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Snap'lerini yönet" }, - "snapsStatus": { - "message": "Snap durumu etkinliğe bağlıdır." - }, "snapsToggle": { "message": "Bir snap yalnızca etkinleştirilmişse çalışır" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 7bb1339a6..226fbed51 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -695,10 +695,6 @@ "message": "$1 chưa được kết nối với bất kỳ trang web nào.", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "Snap $1 được kết nối với các trang web này. Các trang web này được phép sử dụng những quyền được liệt kê ở trên.", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "Đang kết nối..." }, @@ -1355,18 +1351,6 @@ "message": "Tính năng nhập tập tin không hoạt động? Nhấn vào đây!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "Xem chi tiết", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "Đã thêm vào", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "từ", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "bạn nên gỡ cài đặt tiện ích mở rộng này", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "Không tìm thấy kết quả trùng khớp." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "Hiển thị" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "Giao dịch thông minh" }, - "snapAccess": { - "message": "Snap $1 có quyền truy cập vào:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "Đã thêm vào $1 từ $2", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "Nội dung này đến từ $1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "Quản lý Snap" }, - "snapsStatus": { - "message": "Trạng thái Snap tùy thuộc vào hoạt động." - }, "snapsToggle": { "message": "Snap chỉ hoạt động khi đã bật" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index dc186ebf1..ce0020821 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -695,10 +695,6 @@ "message": "$1 还没连接到任何网站。", "description": "$1 is the account name" }, - "connectedSnapSites": { - "message": "$1的snap已连接到这些站点。它们有上述的访问权限。", - "description": "$1 represents the name of the snap" - }, "connecting": { "message": "连接中……" }, @@ -1355,18 +1351,6 @@ "message": "文件导入失败?点击这里!", "description": "Helps user import their account from a JSON file" }, - "flaskSnapSettingsCardButtonCta": { - "message": "查看详细信息", - "description": "Call to action a user can take to see more information about the snap that is installed" - }, - "flaskSnapSettingsCardDateAddedOn": { - "message": "添加于", - "description": "Start of the sentence describing when and where snap was added" - }, - "flaskSnapSettingsCardFrom": { - "message": "自", - "description": "Part of the sentence describing when and where snap was added" - }, "flaskWelcomeUninstall": { "message": "您应该卸载此扩展程序", "description": "This request is shown on the Flask Welcome screen. It is intended for non-developers, and will be bolded." @@ -3230,10 +3214,6 @@ "settingsSearchMatchingNotFound": { "message": "没有找到匹配的结果." }, - "shorthandVersion": { - "message": "v$1", - "description": "$1 is replaced by a version string (e.g. 1.2.3)" - }, "show": { "message": "显示" }, @@ -3307,14 +3287,6 @@ "smartTransaction": { "message": "智能交易" }, - "snapAccess": { - "message": "$1的snap可以访问:", - "description": "$1 represents the name of the snap" - }, - "snapAdded": { - "message": "从 $2 添加到 $1", - "description": "$1 represents the date the snap was installed, $2 represents which origin installed the snap." - }, "snapContent": { "message": "此内容来自$1", "description": "This is shown when a snap shows transaction insight information in the confirmation UI. $1 is a link to the snap's settings page with the link text being the name of the snap." @@ -3351,9 +3323,6 @@ "snapsSettingsDescription": { "message": "管理您的Snap" }, - "snapsStatus": { - "message": "Snap状态取决于活动。" - }, "snapsToggle": { "message": "Snap仅在启用后才会运行" }, diff --git a/test/data/mock-state.json b/test/data/mock-state.json index b7a08d5c5..23f79951e 100644 --- a/test/data/mock-state.json +++ b/test/data/mock-state.json @@ -57,7 +57,43 @@ "priorityFeeTrend": "down", "networkCongestion": 0.90625 }, - "snaps": [{}], + "snaps": { + "npm:@metamask/test-snap-bip44": { + "id": "npm:@metamask/test-snap-bip44", + "origin": "npm:@metamask/test-snap-bip44", + "version": "5.1.2", + "iconUrl": null, + "initialPermissions": { + "endowment:ethereum-provider": {} + }, + "manifest": { + "description": "An example Snap that signs messages using BLS.", + "proposedName": "BIP-44 Test Snap", + "repository": { + "type": "git", + "url": "https://github.com/MetaMask/test-snaps.git" + }, + "source": { + "location": { + "npm": { + "filePath": "dist/bundle.js", + "packageName": "@metamask/test-snap-bip44", + "registry": "https://registry.npmjs.org" + } + }, + "shasum": "L1k+dT9Q+y3KfIqzaH09MpDZVPS9ZowEh9w01ZMTWMU=" + }, + "version": "5.1.2" + }, + "versionHistory": [ + { + "date": 1680686075921, + "origin": "https://metamask.github.io", + "version": "5.1.2" + } + ] + } + }, "preferences": { "hideZeroBalanceTokens": false, "showFiatInTestnets": false, diff --git a/test/e2e/snaps/test-snap-management.spec.js b/test/e2e/snaps/test-snap-management.spec.js index cb44e7d57..98503cadc 100644 --- a/test/e2e/snaps/test-snap-management.spec.js +++ b/test/e2e/snaps/test-snap-management.spec.js @@ -92,6 +92,10 @@ describe('Test Snap Management', function () { await driver.delay(1000); // try to disable the snap + await driver.clickElement({ + text: 'Notification Test Snap', + tag: 'p', + }); await driver.clickElement('.toggle-button > div'); // switch back to test-snaps window @@ -130,12 +134,11 @@ describe('Test Snap Management', function () { ); assert.equal(await notificationResult.getText(), '1'); - // click on see details - await driver.clickElement({ text: 'See details', tag: 'button' }); - await driver.delay(1000); - // try to remove snap - await driver.clickElement({ text: 'Remove snap', tag: 'button' }); + await driver.clickElement({ + text: 'Remove Notification Test Snap', + tag: 'p', + }); await driver.delay(1000); // try to click remove on popover diff --git a/ui/components/app/flask/snap-avatar/snap-avatar.js b/ui/components/app/flask/snap-avatar/snap-avatar.js index 4e16b8a2a..cdf85e117 100644 --- a/ui/components/app/flask/snap-avatar/snap-avatar.js +++ b/ui/components/app/flask/snap-avatar/snap-avatar.js @@ -50,7 +50,7 @@ const SnapAvatar = ({ snapId, className }) => { position={BadgeWrapperPosition.bottomRight} > {iconUrl ? ( - + ) : ( { - const t = useI18nContext(); - +const SnapSettingsCard = ({ name, packageName, onClick, snapId }) => { return ( - - {(icon || name) && ( - - - - - - )} - - {name} - - - - - + + - - - {description} - - - - + - - - - - - - - } - label={status} - labelProps={{ - color: Color.textAlternative, - margin: [0, 1], - }} - backgroundColor={BackgroundColor.backgroundAlternative} - className="snap-settings-card__chip" - {...chipProps} - /> - - - - - {(dateAdded || version) && ( - <> - - {`${ - dateAdded && t('flaskSnapSettingsCardDateAddedOn') - } ${dateAdded} ${url && t('flaskSnapSettingsCardFrom')} ${url}`} - - - {t('shorthandVersion', [version])} - - - )} + {name} + + + {packageName} + - + + + + ); }; @@ -198,61 +70,17 @@ SnapSettingsCard.propTypes = { */ name: PropTypes.string, /** - * Description of the snap. Truncates after 4 lines + * Name of a snap package */ - description: PropTypes.string, - /** - * Image source of the snap icon for the IconWithFallback component - */ - icon: PropTypes.string, - /** - * Date the snap was added. Date will need formatting - */ - dateAdded: PropTypes.string, - /** - * The version of the snap in semver. Will truncate after 4 numbers e.g. 10.5.1... - */ - version: PropTypes.string, - /** - * Url of the snap website - */ - url: PropTypes.string, - /** - * The onChange function for the ToggleButton component - */ - onToggle: PropTypes.func, - /** - * Whether the snap is enabled. `value` prop of the ToggleButton - */ - isEnabled: PropTypes.bool, + packageName: PropTypes.string, /** * onClick function of the "See Details" Button */ onClick: PropTypes.func, /** - * Status of the snap must be one + * ID of a snap. */ - status: PropTypes.oneOf(Object.values(STATUSES)).isRequired, - /** - * Additional className added to the root div of the SnapSettingsCard component - */ - className: PropTypes.string, - /** - * Optional additional props passed to the Card component - */ - cardProps: PropTypes.shape(Card.propTypes), - /** - * Optional additional props passed to the ToggleButton component - */ - toggleButtonProps: PropTypes.shape(ToggleButton.propTypes), - /** - * Optional additional props passed to the Button component - */ - buttonProps: PropTypes.shape(Button.propTypes), - /** - * Optional additional props passed to the Chip component - */ - chipProps: PropTypes.shape(Chip.propTypes), + snapId: PropTypes.string.isRequired, }; export default SnapSettingsCard; diff --git a/ui/components/app/flask/snap-settings-card/snap-settings-card.test.js b/ui/components/app/flask/snap-settings-card/snap-settings-card.test.js index 9a09e4da9..cbdfe9892 100644 --- a/ui/components/app/flask/snap-settings-card/snap-settings-card.test.js +++ b/ui/components/app/flask/snap-settings-card/snap-settings-card.test.js @@ -1,76 +1,46 @@ import * as React from 'react'; -import { render, fireEvent } from '@testing-library/react'; +import { screen } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; import SnapSettingsCard from '.'; describe('SnapSettingsCard', () => { const args = { name: 'Snap name', - description: - 'This snap provides developers everywhere access to an entirely new data storage paradigm, even letting your programs store data autonomously.', - dateAdded: new Date().toDateString(), - version: '10.5.1234', - url: 'https://metamask.io', - status: 'stopped', - icon: './AST.png', + packageName: '@metamask/test-snap-bip44', + snapId: 'npm:@metamask/test-snap-bip44', + onClick: () => null, }; + const mockStore = configureMockStore([thunk])(mockState); + it('should render the SnapsSettingCard without crashing', () => { - const { getByText } = render(); + const { getByText } = renderWithProvider( + , + mockStore, + ); expect(getByText('Snap name')).toBeDefined(); }); - it('should render the pill as installing when given a status of installing', () => { - args.status = 'installing'; - const { getByText } = render(); - expect(getByText('installing')).toBeDefined(); - }); - - it('should render the pill as running when given a status of running', () => { - args.status = 'running'; - const { getByText } = render(); - expect(getByText('running')).toBeDefined(); - }); - - it('should render the pill as installing when given a status of stopped', () => { - args.status = 'stopped'; - const { getByText } = render(); - expect(getByText('stopped')).toBeDefined(); - }); - - it('should render the pill as crashed when given a status of crashed', () => { - args.status = 'crashed'; - const { getByText } = render(); - expect(getByText('crashed')).toBeDefined(); - }); - - it('should call onToggle prop when toggle button is clicked', () => { - const onToggle = jest.fn(); - args.onToggle = onToggle; - const { container } = render(); - const toggleBtn = container.querySelector('.toggle-button').firstChild; - fireEvent.click(toggleBtn); - expect(onToggle).toHaveBeenCalled(); - }); - - it('should call onClick prop when See Details button is clicked', () => { - const onClick = jest.fn(); - args.onClick = onClick; - const { container } = render(); - const seeDetailsBtn = container.querySelector( - '.snap-settings-card__button', + it('should render the icon fallback using the first letter of the name', async () => { + const { getByText } = renderWithProvider( + , + mockStore, ); - fireEvent.click(seeDetailsBtn); - expect(onClick).toHaveBeenCalled(); + + const avatar = await screen.findAllByText(/B/u); + avatar.forEach((avatarBaseElement) => { + expect(avatarBaseElement).toHaveClass('mm-avatar-base'); + }); + expect(getByText('B')).toBeDefined(); }); - it('should render an icon image', () => { - const { getByAltText } = render(); - const image = getByAltText(args.name); - expect(image).toBeDefined(); - expect(image).toHaveAttribute('src', args.icon); - }); - - it('should render the icon fallback using the first letter of the name', () => { - const { getByText } = render(); - expect(getByText('S')).toBeDefined(); + it('should render the package name', () => { + const { getByText } = renderWithProvider( + , + mockStore, + ); + expect(getByText('@metamask/test-snap-bip44')).toBeDefined(); }); }); diff --git a/ui/components/app/tab-bar/tab-bar.stories.js b/ui/components/app/tab-bar/tab-bar.stories.js index a9677eb19..2861437a3 100644 --- a/ui/components/app/tab-bar/tab-bar.stories.js +++ b/ui/components/app/tab-bar/tab-bar.stories.js @@ -29,7 +29,7 @@ export default { key: 'contacts', }, { - icon: , + icon: , content: 'Snaps', key: 'snaps', }, diff --git a/ui/pages/settings/flask/snaps-list-tab/index.scss b/ui/pages/settings/flask/snaps-list-tab/index.scss index abf10efd2..4153a1e6c 100644 --- a/ui/pages/settings/flask/snaps-list-tab/index.scss +++ b/ui/pages/settings/flask/snaps-list-tab/index.scss @@ -3,22 +3,15 @@ height: 100%; &__wrapper { - width: auto; + max-width: 475px; } &__body { - padding: 12px 18px; - @include screen-sm-min { padding: 12px; } } - .snap-settings-card { - margin: 8px 0; - max-width: 344px; - } - .snap-list-tab__container--no-snaps_inner { max-width: 164px; } diff --git a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js b/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js index f1dc90708..f745b3ff0 100644 --- a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js +++ b/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js @@ -1,5 +1,5 @@ import React, { useRef, useEffect } from 'react'; -import { useDispatch, useSelector } from 'react-redux'; +import { useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; import SnapSettingsCard from '../../../../components/app/flask/snap-settings-card'; import { useI18nContext } from '../../../../hooks/useI18nContext'; @@ -13,8 +13,7 @@ import { } from '../../../../helpers/constants/design-system'; import Box from '../../../../components/ui/box'; import { SNAPS_VIEW_ROUTE } from '../../../../helpers/constants/routes'; -import { disableSnap, enableSnap } from '../../../../store/actions'; -import { getSnaps } from '../../../../selectors'; +import { getSnapsList } from '../../../../selectors'; import { handleSettingsRefs } from '../../../../helpers/utils/settings-search'; import { Icon, @@ -31,46 +30,33 @@ import { const SnapListTab = () => { const t = useI18nContext(); const history = useHistory(); - const dispatch = useDispatch(); - const snaps = useSelector(getSnaps); const settingsRef = useRef(); const onClick = (snap) => { history.push(`${SNAPS_VIEW_ROUTE}/${encodeURIComponent(snap.id)}`); }; - const onToggle = (snap) => { - if (snap.enabled) { - dispatch(disableSnap(snap.id)); - } else { - dispatch(enableSnap(snap.id)); - } - }; useEffect(() => { handleSettingsRefs(t, t('snaps'), settingsRef); }, [settingsRef, t]); + const snapsList = useSelector((state) => getSnapsList(state)); + return (
- {Object.entries(snaps).length ? ( + {snapsList.length ? (
- {Object.entries(snaps).map(([key, snap]) => { + {snapsList.map((snap) => { return ( { - onToggle(snap); - }} - description={snap.manifest.description} - url={snap.id} - name={snap.manifest.proposedName} - status={snap.status} - version={snap.version} + key={snap.key} + packageName={snap.packageName} + name={snap.name} onClick={() => { onClick(snap); }} + snapId={snap.id} /> ); })} diff --git a/ui/pages/settings/flask/view-snap/index.scss b/ui/pages/settings/flask/view-snap/index.scss index 25b584dda..6d6395cf6 100644 --- a/ui/pages/settings/flask/view-snap/index.scss +++ b/ui/pages/settings/flask/view-snap/index.scss @@ -1,131 +1,58 @@ .view-snap { - padding: 12px 18px; + max-width: 475px; - @include screen-sm-min { - padding: 12px; - } + &__version_info { + &__version-number { + font-weight: bold; + } - &__subheader { - padding: 16px 4px; - border-bottom: 1px solid var(--color-border-muted); - margin-inline-end: 24px; - height: 72px; - align-items: center; - display: flex; - flex-flow: row nowrap; - - @include screen-sm-max { - margin-inline-end: 0; - padding: 0 0 16px; - flex-direction: column; - align-items: center; - gap: 8px; - height: max-content; + &__link { + vertical-align: top; } } - &__install-details { - border-bottom: 1px solid var(--color-border-muted); - margin-inline-end: 24px; - - @include screen-sm-max { - margin-inline-end: 0; + &__enable { + &__tooltip_wrapper { + max-width: 52px; } } - &__version { - font-family: monospace; - } - - &__title { - @include screen-sm-max { - padding-bottom: 16px; - } - } - - &__pill-toggle-container { - align-items: center; - display: flex; - flex-grow: 1; - - @include screen-sm-max { - width: 100%; - justify-content: space-between; - } - } - - &__pill-container { - @include screen-sm-max { - padding-left: 0; - display: inline-block; - } - } - - &__toggle-container { - margin-left: auto; - - @include screen-sm-max { - padding-left: 0; - display: inline-block; - } - } - - &__toggle-button { - margin-right: -12px; - } - - &__content-container { - @include screen-sm-max { - width: 100%; - } - } - - &__section { - flex: 1; - min-width: 0; - display: flex; - flex-direction: column; - border-bottom: 1px solid var(--color-border-muted); - padding-bottom: 16px; - margin-bottom: 16px; - - @include screen-sm-max { - height: initial; - padding: 5px 0 16px; - } - - .connected-sites-list__content-row { + .connected-sites-list { + &__content-row { border-top: none; - border-bottom: 1px solid var(--color-border-muted); + padding: 0; - &:last-child { - border-bottom: none; + & &-link-button { + padding: 0; + padding-inline-start: 0; + color: var(--color-error-default); + font-size: 14px; + } + + a { + font-size: 14px; + color: var(--color-error-default); + } + + a:hover { + color: var(--color-error-alternative); } } - &:last-child { - margin-bottom: 0; - border-bottom: none; - } - } - - &__permission-list { - padding-bottom: 0; - - .permission { - padding-top: 16px; - - &:last-child { - border-bottom: none; + &__subject-info { + a.btn-link { + font-size: 14px; + color: var(--color-error-default); } } - } - &__remove-button { - max-width: 175px; + &__subject-icon { + flex-shrink: 0; + } - @include screen-sm-max { - align-self: center; + &__subject-name { + font-size: 14px; + color: var(--color-primary-default); } } } diff --git a/ui/pages/settings/flask/view-snap/view-snap.js b/ui/pages/settings/flask/view-snap/view-snap.js index a9ab3a096..a002ad7b5 100644 --- a/ui/pages/settings/flask/view-snap/view-snap.js +++ b/ui/pages/settings/flask/view-snap/view-snap.js @@ -5,15 +5,13 @@ import { SnapCaveatType, WALLET_SNAP_PERMISSION_KEY, } from '@metamask/rpc-methods'; +import { getSnapPrefix } from '@metamask/snaps-utils'; import Button from '../../../../components/ui/button'; -import Typography from '../../../../components/ui/typography'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { - TypographyVariant, - TEXT_ALIGN, - FRACTIONS, + Size, TextColor, - BLOCK_SIZES, + TextVariant, } from '../../../../helpers/constants/design-system'; import SnapAuthorship from '../../../../components/app/flask/snap-authorship'; import Box from '../../../../components/ui/box'; @@ -36,7 +34,12 @@ import { getPermissionSubjects, getTargetSubjectMetadata, } from '../../../../selectors'; -import { formatDate } from '../../../../helpers/utils/util'; +import { + formatDate, + getSnapName, + removeSnapIdPrefix, +} from '../../../../helpers/utils/util'; +import { ButtonLink, Text } from '../../../../components/component-library'; import SnapPermissionsList from '../../../../components/app/flask/snap-permissions-list'; function ViewSnap() { @@ -108,140 +111,165 @@ function ViewSnap() { } const versionHistory = snap.versionHistory ?? []; - const [firstInstall] = versionHistory; + const installInfo = versionHistory.length + ? versionHistory[versionHistory.length - 1] + : undefined; + const packageName = snap.id && removeSnapIdPrefix(snap.id); + const snapPrefix = snap.id && getSnapPrefix(snap.id); + const isNPM = snapPrefix === 'npm:'; + const url = isNPM + ? `https://www.npmjs.com/package/${packageName}` + : packageName; + const snapName = getSnapName(snap.id, targetSubjectMetadata); return ( -
-
-
- + + + + + + {snap.manifest.description} + + + + + {`${t('youInstalled')} `} + + v{snap.version} + + {` ${t('ofTextNofM')} `} + - {snap.manifest.proposedName} - - - - - - - - - - - -
- - {firstInstall && ( - - {t('snapAdded', [ - formatDate(firstInstall.date, 'MMMM d, y'), - firstInstall.origin, - ])} - + {packageName} + + {installInfo && ` ${t('from').toLowerCase()} `} + {installInfo && ( + + {installInfo.origin} + )} - - {t('shorthandVersion', [snap.version])} - - - + + + {t('enableSnap')} + -
- - {snap.manifest.description} - -
-
- - {t('permissions')} - - - {t('snapAccess', [snap.manifest.proposedName])} - - - - -
-
- - - {t('connectedSites')} - - - {t('connectedSnapSites', [snap.manifest.proposedName])} - - { - onDisconnect(origin, snap.id); - }} - /> - -
-
- - {t('removeSnap')} - - - {t('removeSnapDescription')} - - - {isShowingRemoveWarning && ( - setIsShowingRemoveWarning(false)} - onSubmit={async () => { - await dispatch(removeSnap(snap.id)); - }} - snapName={snap.manifest.proposedName} - /> - )} -
+ {t('enableSnapDescription')} +
+ + + + -
-
+ + + + {t('permissions')} + + + + + + {t('connectedSites')} + + { + onDisconnect(origin, snap.id); + }} + /> + + + + {t('removeSnap')} + + + {t('removeSnapDescription')} + + + + {isShowingRemoveWarning && ( + setIsShowingRemoveWarning(false)} + onSubmit={async () => { + await dispatch(removeSnap(snap.id)); + }} + snapName={snapName} + /> + )} + + + ); } -export default React.memo(ViewSnap); +export default ViewSnap; diff --git a/ui/pages/settings/flask/view-snap/view-snap.test.js b/ui/pages/settings/flask/view-snap/view-snap.test.js new file mode 100644 index 000000000..320077cf6 --- /dev/null +++ b/ui/pages/settings/flask/view-snap/view-snap.test.js @@ -0,0 +1,81 @@ +import * as React from 'react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; +import ViewSnap from './view-snap'; + +jest.mock('../../../../store/actions.ts', () => { + return { + disableSnap: jest.fn(), + enableSnap: jest.fn(), + removeSnap: jest.fn(), + removePermissionsFor: jest.fn(), + updateCaveat: jest.fn(), + }; +}); + +jest.mock('react-router-dom', () => { + const original = jest.requireActual('react-router-dom'); + return { + ...original, + useLocation: jest.fn(() => ({ + pathname: `/settings/snaps-view/${encodeURIComponent( + 'npm:@metamask/test-snap-bip44', + )}`, + })), + }; +}); + +const mockStore = configureMockStore([thunk])(mockState); + +describe('ViewSnap', () => { + it('should properly display Snap View elements', async () => { + const { getByText, container, getByRole } = renderWithProvider( + , + mockStore, + ); + + // Snap name & Snap authorship component + expect(getByText('BIP-44 Test Snap')).toBeDefined(); + expect(container.getElementsByClassName('snaps-authorship')?.length).toBe( + 1, + ); + // Snap description + expect( + getByText('An example Snap that signs messages using BLS.'), + ).toBeDefined(); + // Snap version info + expect(getByText('v5.1.2')).toBeDefined(); + // Enable Snap + expect(getByText('Enable snap')).toBeDefined(); + expect( + getByText( + 'Your installed snap will only have access to its permissions and run if it’s enabled.', + ), + ).toBeDefined(); + expect(container.getElementsByClassName('toggle-button')?.length).toBe(1); + // Permissions + expect(getByText('Permissions')).toBeDefined(); + expect( + container.getElementsByClassName('snap-permissions-list')?.length, + ).toBe(1); + // Connected sites + expect(getByText('Connected sites')).toBeDefined(); + expect( + container.getElementsByClassName('connected-sites-list__content-rows') + ?.length, + ).toBe(1); + // Remove snap + expect(getByText('Remove snap')).toBeDefined(); + expect( + getByText( + 'This action will delete the snap, its data and revoke your given permissions.', + ), + ).toBeDefined(); + expect(getByText('Remove BIP-44 Test Snap')).toBeDefined(); + expect(getByRole('button')).toHaveClass( + 'button btn--rounded btn-danger view-snap__remove-button', + ); + }); +}); diff --git a/ui/pages/settings/settings.component.js b/ui/pages/settings/settings.component.js index b9e007e86..57ba8833d 100644 --- a/ui/pages/settings/settings.component.js +++ b/ui/pages/settings/settings.component.js @@ -280,7 +280,7 @@ class SettingsPage extends PureComponent { { content: t('snaps'), icon: ( - + ), key: SNAPS_LIST_ROUTE, }, diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 6be08b883..e5266293a 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -55,6 +55,10 @@ import { shortenAddress, getAccountByAddress, getURLHostName, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + removeSnapIdPrefix, + getSnapName, + ///: END:ONLY_INCLUDE_IN } from '../helpers/utils/util'; import { TEMPLATED_CONFIRMATION_MESSAGE_TYPES } from '../pages/confirmation/templates'; @@ -1459,3 +1463,25 @@ export function getIsDesktopEnabled(state) { return state.metamask.desktopEnabled; } ///: END:ONLY_INCLUDE_IN + +///: BEGIN:ONLY_INCLUDE_IN(flask) +/** + * To get all installed snaps with proper metadata + * + * @param {*} state + * @returns Boolean + */ +export function getSnapsList(state) { + const snaps = getSnaps(state); + return Object.entries(snaps).map(([key, snap]) => { + const targetSubjectMetadata = getTargetSubjectMetadata(state, snap?.id); + + return { + key, + id: snap.id, + packageName: removeSnapIdPrefix(snap.id), + name: getSnapName(snap.id, targetSubjectMetadata), + }; + }); +} +///: END:ONLY_INCLUDE_IN From 05dcff85a605b28d3a5886914c91663a378789d0 Mon Sep 17 00:00:00 2001 From: David Drazic Date: Mon, 24 Apr 2023 12:56:44 +0200 Subject: [PATCH 05/60] [FLASK] Fix text selection bug in snap ui (#18719) * Fix text selection bug in snap ui * Fix template mapping calls in other places * Fix template mapping calls in snap-prompt --- .../snap-ui-renderer/snap-ui-renderer.js | 21 +++++++++++-------- .../templates/flask/snap-alert/snap-alert.js | 3 ++- .../snap-confirmation/snap-confirmation.js | 3 ++- .../flask/snap-prompt/snap-prompt.js | 3 ++- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js b/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js index 20197923f..4a30ff8fa 100644 --- a/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js +++ b/ui/components/app/flask/snap-ui-renderer/snap-ui-renderer.js @@ -1,6 +1,5 @@ import React from 'react'; import PropTypes from 'prop-types'; -import nanoid from 'nanoid'; import { isComponent } from '@metamask/snaps-ui'; import { useSelector } from 'react-redux'; import MetaMaskTemplateRenderer from '../../metamask-template-renderer/metamask-template-renderer'; @@ -22,10 +21,12 @@ import { Copyable } from '../copyable'; import { DelineatorType } from '../../../../helpers/constants/flask'; export const UI_MAPPING = { - panel: (props) => ({ + panel: (props, elementKey) => ({ element: 'Box', - // eslint-disable-next-line no-use-before-define - children: props.children.map(mapToTemplate), + children: props.children.map((element) => + // eslint-disable-next-line no-use-before-define + mapToTemplate(element, elementKey), + ), props: { display: DISPLAY.FLEX, flexDirection: FLEX_DIRECTION.COLUMN, @@ -66,11 +67,12 @@ export const UI_MAPPING = { }; // TODO: Stop exporting this when we remove the mapToTemplate hack in confirmation templates. -export const mapToTemplate = (data) => { +export const mapToTemplate = (data, elementKeyIndex) => { const { type } = data; - const mapped = UI_MAPPING[type](data); - // TODO: We may want to have deterministic keys at some point - return { ...mapped, key: nanoid() }; + elementKeyIndex.value += 1; + const indexKey = `snap_ui_element_${type}__${elementKeyIndex.value}`; + const mapped = UI_MAPPING[type](data, elementKeyIndex); + return { ...mapped, key: indexKey }; }; // Component that maps Snaps UI JSON format to MetaMask Template Renderer format @@ -97,7 +99,8 @@ export const SnapUIRenderer = ({ ); } - const sections = mapToTemplate(data); + const elementKeyIndex = { value: 0 }; + const sections = mapToTemplate(data, elementKeyIndex); return ( diff --git a/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js b/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js index f4b39dbc0..a3595c343 100644 --- a/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js +++ b/ui/pages/confirmation/templates/flask/snap-alert/snap-alert.js @@ -6,6 +6,7 @@ function getValues(pendingApproval, t, actions) { snapName, requestData: { content }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -24,7 +25,7 @@ function getValues(pendingApproval, t, actions) { snapName, }, // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - children: mapToTemplate(content), + children: mapToTemplate(content, elementKeyIndex), }, }, ], diff --git a/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js b/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js index 6b7d71b2a..bf50923d2 100644 --- a/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js +++ b/ui/pages/confirmation/templates/flask/snap-confirmation/snap-confirmation.js @@ -6,6 +6,7 @@ function getValues(pendingApproval, t, actions) { snapName, requestData: { content }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -24,7 +25,7 @@ function getValues(pendingApproval, t, actions) { snapName, }, // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - children: mapToTemplate(content), + children: mapToTemplate(content, elementKeyIndex), }, }, ], diff --git a/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js b/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js index b54db0e03..ef9d5de48 100644 --- a/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js +++ b/ui/pages/confirmation/templates/flask/snap-prompt/snap-prompt.js @@ -7,6 +7,7 @@ function getValues(pendingApproval, t, actions, _history, setInputState) { snapName, requestData: { content, placeholder }, } = pendingApproval; + const elementKeyIndex = { value: 0 }; return { content: [ @@ -26,7 +27,7 @@ function getValues(pendingApproval, t, actions, _history, setInputState) { }, children: [ // TODO: Replace with SnapUIRenderer when we don't need to inject the input manually. - mapToTemplate(content), + mapToTemplate(content, elementKeyIndex), { element: 'div', key: 'snap-prompt-container', From eaa004c14745b4b4a572d5dcf9d4f88c5702beaa Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 24 Apr 2023 15:43:43 +0200 Subject: [PATCH 06/60] Bump `@metamask/slip44` to `3.0.0` (#18773) --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 65284867d..fdcb71b9c 100644 --- a/package.json +++ b/package.json @@ -255,7 +255,7 @@ "@metamask/rpc-methods": "^0.32.2", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", - "@metamask/slip44": "^2.1.0", + "@metamask/slip44": "^3.0.0", "@metamask/smart-transactions-controller": "^3.1.0", "@metamask/snaps-controllers": "^0.32.2", "@metamask/snaps-ui": "^0.32.2", diff --git a/yarn.lock b/yarn.lock index c98964a2f..8502aa634 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4291,10 +4291,10 @@ __metadata: languageName: node linkType: hard -"@metamask/slip44@npm:^2.1.0": - version: 2.1.0 - resolution: "@metamask/slip44@npm:2.1.0" - checksum: fa2b020af4e0505c8b03ed412289a35f839c0a5fe187a88fe4c5135dac5fee2ca70ba3016b61ddb907345578485fb9e5879342397a377c9945292244a58aa468 +"@metamask/slip44@npm:^3.0.0": + version: 3.0.0 + resolution: "@metamask/slip44@npm:3.0.0" + checksum: 86d0b6c0e156f0f7a5489464b6438c79b6336e4bbb00329b4482c3922acbedd498f65d289a11ba21eded4108cf84dfcd38a167c8a6c2bb87696bd0ca4d8009ff languageName: node linkType: hard @@ -24206,7 +24206,7 @@ __metadata: "@metamask/rpc-methods": ^0.32.2 "@metamask/safe-event-emitter": ^2.0.0 "@metamask/scure-bip39": ^2.0.3 - "@metamask/slip44": ^2.1.0 + "@metamask/slip44": ^3.0.0 "@metamask/smart-transactions-controller": ^3.1.0 "@metamask/snaps-controllers": ^0.32.2 "@metamask/snaps-ui": ^0.32.2 From ff8b41042e333e8cecc6b908b94825f67c39235f Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Mon, 24 Apr 2023 13:44:24 +0000 Subject: [PATCH 07/60] deps: bump serve-handler@6.1.3->6.1.5; minimatch@3.0.4->3.1.2 (#18734) - CVE-2022-3517 / GHSA-f8q6-p94x-37v3 --- yarn.lock | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8502aa634..b5582b8de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7540,7 +7540,14 @@ __metadata: languageName: node linkType: hard -"@types/minimatch@npm:*, @types/minimatch@npm:^3.0.3": +"@types/minimatch@npm:*": + version: 5.1.2 + resolution: "@types/minimatch@npm:5.1.2" + checksum: 0391a282860c7cb6fe262c12b99564732401bdaa5e395bee9ca323c312c1a0f45efbf34dce974682036e857db59a5c9b1da522f3d6055aeead7097264c8705a8 + languageName: node + linkType: hard + +"@types/minimatch@npm:^3.0.3": version: 3.0.5 resolution: "@types/minimatch@npm:3.0.5" checksum: c41d136f67231c3131cf1d4ca0b06687f4a322918a3a5adddc87ce90ed9dbd175a3610adee36b106ae68c0b92c637c35e02b58c8a56c424f71d30993ea220b92 @@ -24684,12 +24691,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.0.4": - version: 3.0.4 - resolution: "minimatch@npm:3.0.4" +"minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" dependencies: brace-expansion: ^1.1.7 - checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078 + checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a languageName: node linkType: hard @@ -24702,15 +24709,6 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a - languageName: node - linkType: hard - "minimatch@npm:^5.0.1": version: 5.0.1 resolution: "minimatch@npm:5.0.1" @@ -30765,18 +30763,18 @@ __metadata: linkType: hard "serve-handler@npm:^6.1.2, serve-handler@npm:^6.1.3": - version: 6.1.3 - resolution: "serve-handler@npm:6.1.3" + version: 6.1.5 + resolution: "serve-handler@npm:6.1.5" dependencies: bytes: 3.0.0 content-disposition: 0.5.2 fast-url-parser: 1.1.3 mime-types: 2.1.18 - minimatch: 3.0.4 + minimatch: 3.1.2 path-is-inside: 1.0.2 path-to-regexp: 2.2.1 range-parser: 1.2.0 - checksum: 384c1bc10add07a554207f918acaa75af47fcfd8fb89e070faa3468ab45ec5bbc9f976e62d659b6b63404edcf5c54efb7e0a48f3f55946eec83b62b283b9837e + checksum: 7a98ca9cbf8692583b6cde4deb3941cff900fa38bf16adbfccccd8430209bab781e21d9a1f61c9c03e226f9f67689893bbce25941368f3ddaf985fc3858b49dc languageName: node linkType: hard From b704a3d60f407eac99a7dc3f8a65529eff812203 Mon Sep 17 00:00:00 2001 From: HowardBraham Date: Mon, 24 Apr 2023 07:18:58 -0700 Subject: [PATCH 08/60] Shallow git clone (#18491) Co-authored-by: Mark Stacey Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Co-authored-by: legobt <6wbvkn0j@anonaddy.me> --- .circleci/config.yml | 104 +++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 68a1c199a..d50ac8747 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,6 +24,24 @@ rc_branch_only: &rc_branch_only only: - /^Version-v(\d+)[.](\d+)[.](\d+)/ +aliases: + # Shallow Git Clone + - &shallow-git-clone + name: Shallow Git Clone + command: | + #!/bin/bash + set -e + set -u + set -o pipefail + + # Set up SSH access + # This SSH key is the current github.com SSH key as of April 2023, but it will need to be changed whenever github changes their key (probably every few years) + GITHUB_SSH_KEY="AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" + mkdir -p ~/.ssh + echo github.com ssh-ed25519 $GITHUB_SSH_KEY >> ~/.ssh/known_hosts + + git clone --depth 1 "$CIRCLE_REPOSITORY_URL" --branch "$CIRCLE_BRANCH" . + workflows: test_and_release: jobs: @@ -234,7 +252,7 @@ jobs: trigger-beta-build: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - when: @@ -263,7 +281,7 @@ jobs: create_release_pull_request: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -282,7 +300,7 @@ jobs: prep-deps: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - restore_cache: keys: # First try to get the specific cache for the checksum of the yarn.lock file. @@ -332,7 +350,7 @@ jobs: validate-lavamoat-config: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -347,7 +365,7 @@ jobs: prep-build: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - when: @@ -381,7 +399,7 @@ jobs: prep-build-desktop: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -405,7 +423,7 @@ jobs: prep-build-flask: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - when: @@ -445,7 +463,7 @@ jobs: prep-build-test-flask: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -466,7 +484,7 @@ jobs: prep-build-test-mv3: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -487,7 +505,7 @@ jobs: prep-build-test: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -508,7 +526,7 @@ jobs: prep-build-storybook: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -522,7 +540,7 @@ jobs: prep-build-ts-migration-dashboard: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -536,7 +554,7 @@ jobs: test-yarn-dedupe: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -546,7 +564,7 @@ jobs: test-lint: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -559,7 +577,7 @@ jobs: test-storybook: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -581,7 +599,7 @@ jobs: test-lint-lockfile: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -591,7 +609,7 @@ jobs: test-lint-changelog: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - when: @@ -617,7 +635,7 @@ jobs: test-deps-audit: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -627,7 +645,7 @@ jobs: test-deps-depcheck: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -638,7 +656,7 @@ jobs: executor: node-browsers parallelism: 8 steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -675,7 +693,7 @@ jobs: executor: node-browsers parallelism: 8 steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -703,7 +721,7 @@ jobs: executor: node-browsers parallelism: 4 steps: - - checkout + - run: *shallow-git-clone - run: name: Install Firefox command: ./.circleci/scripts/firefox-install.sh @@ -740,7 +758,7 @@ jobs: executor: node-browsers parallelism: 4 steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -777,7 +795,7 @@ jobs: executor: node-browsers-medium-plus parallelism: 8 steps: - - checkout + - run: *shallow-git-clone - run: name: Install Firefox command: ./.circleci/scripts/firefox-install.sh @@ -813,7 +831,7 @@ jobs: benchmark: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -839,7 +857,7 @@ jobs: user-actions-benchmark: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -865,7 +883,7 @@ jobs: stats-module-load-init: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -962,7 +980,7 @@ jobs: job-publish-release: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -982,7 +1000,7 @@ jobs: - add_ssh_keys: fingerprints: - '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8' - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -997,7 +1015,7 @@ jobs: - add_ssh_keys: fingerprints: - '8b:21:e3:20:7c:c9:db:82:74:2d:86:d6:11:a7:2f:49' - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1011,7 +1029,7 @@ jobs: test-unit-mocha: executor: node-browsers-medium-plus steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1026,7 +1044,7 @@ jobs: test-unit-jest-development: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1043,7 +1061,7 @@ jobs: executor: node-browsers-medium-plus parallelism: 12 steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1059,7 +1077,7 @@ jobs: upload-and-validate-coverage: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - codecov/upload @@ -1074,7 +1092,7 @@ jobs: test-unit-global: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1084,7 +1102,7 @@ jobs: validate-source-maps: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1094,7 +1112,7 @@ jobs: validate-source-maps-beta: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1105,7 +1123,7 @@ jobs: validate-source-maps-desktop: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1121,7 +1139,7 @@ jobs: validate-source-maps-flask: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1137,7 +1155,7 @@ jobs: test-mozilla-lint: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1147,7 +1165,7 @@ jobs: test-mozilla-lint-beta: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1158,7 +1176,7 @@ jobs: test-mozilla-lint-desktop: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: @@ -1174,7 +1192,7 @@ jobs: test-mozilla-lint-flask: executor: node-browsers steps: - - checkout + - run: *shallow-git-clone - attach_workspace: at: . - run: From 3e520214c9d386f9db35a15a48c2c58a26962c32 Mon Sep 17 00:00:00 2001 From: Garrett Bear Date: Mon, 24 Apr 2023 07:19:19 -0700 Subject: [PATCH 09/60] update icons to ts enum version (#18698) Co-authored-by: Nidhi Kumari Co-authored-by: George Marshall Co-authored-by: Brad Decker Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../custom-spending-cap-tooltip.js | 2 +- ui/pages/add-nft/add-nft.js | 12 ++++----- ui/pages/asset/components/asset-breadcrumb.js | 10 +++---- ui/pages/asset/components/asset-options.js | 13 +++++----- .../confirm-approve-content.component.js | 12 ++++----- .../confirm-decrypt-message.component.js | 7 ++--- ui/pages/confirmation/confirmation.js | 9 +++---- ui/pages/home/home.component.js | 26 +++++++++---------- .../compliance-feature-page.js | 14 +++++----- ui/pages/notifications/notifications.js | 12 ++++----- .../create-password/create-password.js | 7 ++--- .../metametrics/metametrics.js | 22 ++++++++-------- .../recovery-phrase/review-recovery-phrase.js | 7 ++--- .../skip-srp-backup-popover.js | 10 +++---- .../permissions-connect.component.js | 10 +++---- .../permissions-redirect.component.js | 10 +++---- .../add-recipient/add-recipient.component.js | 7 ++--- .../add-recipient/domain-input.component.js | 20 +++++++------- .../contact-list-tab.component.js | 14 +++++----- .../view-contact/view-contact.component.js | 14 +++++----- .../flask/snaps-list-tab/snap-list-tab.js | 15 +++++------ .../custom-content-search.js | 10 ++----- .../networks-list-item/networks-list-item.js | 14 +++++----- .../settings-search-list.js | 7 ++--- .../settings-search/settings-search.js | 7 ++--- ui/pages/settings/settings.component.js | 14 ++++------ ui/pages/token-allowance/token-allowance.js | 7 ++--- ui/pages/token-details/token-details-page.js | 12 ++++----- 28 files changed, 141 insertions(+), 183 deletions(-) diff --git a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js index 49aebd8e4..ad5033a97 100644 --- a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js +++ b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js @@ -33,7 +33,7 @@ export const CustomSpendingCapTooltip = ({ ) : ( diff --git a/ui/pages/add-nft/add-nft.js b/ui/pages/add-nft/add-nft.js index 1463896b0..c4c40895e 100644 --- a/ui/pages/add-nft/add-nft.js +++ b/ui/pages/add-nft/add-nft.js @@ -37,10 +37,10 @@ import { MetaMetricsTokenEventSource, } from '../../../shared/constants/metametrics'; import { - ICON_NAMES, - ICON_SIZES, -} from '../../components/component-library/icon/deprecated'; -import { ButtonIcon } from '../../components/component-library/button-icon/deprecated'; + ButtonIcon, + IconName, + ButtonIconSize, +} from '../../components/component-library'; export default function AddNft() { const t = useI18nContext(); @@ -163,8 +163,8 @@ export default function AddNft() { setNftAddFailed(false)} diff --git a/ui/pages/asset/components/asset-breadcrumb.js b/ui/pages/asset/components/asset-breadcrumb.js index 2f8517ac8..42218ef43 100644 --- a/ui/pages/asset/components/asset-breadcrumb.js +++ b/ui/pages/asset/components/asset-breadcrumb.js @@ -2,18 +2,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; + IconName, + IconSize, +} from '../../../components/component-library'; const AssetBreadcrumb = ({ accountName, assetName, onBack }) => { return (
diff --git a/ui/pages/confirmation/confirmation.js b/ui/pages/confirmation/confirmation.js index b2a045f26..89c932631 100644 --- a/ui/pages/confirmation/confirmation.js +++ b/ui/pages/confirmation/confirmation.js @@ -34,10 +34,7 @@ import { import NetworkDisplay from '../../components/app/network-display/network-display'; import Callout from '../../components/ui/callout'; import SiteOrigin from '../../components/ui/site-origin'; -import { - Icon, - ICON_NAMES, -} from '../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../components/component-library'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import SnapAuthorship from '../../components/app/flask/snap-authorship/snap-authorship'; import { getSnapName } from '../../helpers/utils/util'; @@ -312,7 +309,7 @@ export default function ConfirmationPage({ setCurrentPendingConfirmation(currentPendingConfirmation - 1) } > - + )}
)} diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index 335baaf3e..4001d0ca1 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -35,11 +35,11 @@ import { } from '../../helpers/constants/design-system'; import { SECOND } from '../../../shared/constants/time'; import { - ICON_NAMES, - ICON_SIZES, -} from '../../components/component-library/icon/deprecated'; -import { ButtonIcon } from '../../components/component-library/button-icon/deprecated'; -import { Text } from '../../components/component-library'; + ButtonIcon, + ButtonIconSize, + IconName, + Text, +} from '../../components/component-library'; import { ASSET_ROUTE, @@ -354,8 +354,8 @@ export default class Home extends PureComponent { {t('newNftAddedMessage')} @@ -377,8 +377,8 @@ export default class Home extends PureComponent { {t('removeNftMessage')} @@ -397,8 +397,8 @@ export default class Home extends PureComponent { {t('newNetworkAdded', [newNetworkAddedName])} clearNewNetworkAdded()} className="home__new-network-notification-close" @@ -432,8 +432,8 @@ export default class Home extends PureComponent { setNewTokensImported('')} className="home__new-tokens-imported-notification-close" diff --git a/ui/pages/institutional/compliance-feature-page/compliance-feature-page.js b/ui/pages/institutional/compliance-feature-page/compliance-feature-page.js index acc8e63f4..9820ff691 100644 --- a/ui/pages/institutional/compliance-feature-page/compliance-feature-page.js +++ b/ui/pages/institutional/compliance-feature-page/compliance-feature-page.js @@ -13,12 +13,12 @@ import { Color, FLEX_DIRECTION, } from '../../../helpers/constants/design-system'; -import { ButtonIcon } from '../../../components/component-library/button-icon/deprecated'; -import { Text } from '../../../components/component-library'; import { - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; + ButtonIcon, + ButtonIconSize, + IconName, + Text, +} from '../../../components/component-library'; import Box from '../../../components/ui/box'; import ComplianceSettings from '../../../components/institutional/compliance-settings'; @@ -44,8 +44,8 @@ const ComplianceFeaturePage = () => { > history.push(DEFAULT_ROUTE)} diff --git a/ui/pages/notifications/notifications.js b/ui/pages/notifications/notifications.js index 5e37225e1..013f51d94 100644 --- a/ui/pages/notifications/notifications.js +++ b/ui/pages/notifications/notifications.js @@ -17,10 +17,10 @@ import { import Button from '../../components/ui/button'; import { useI18nContext } from '../../hooks/useI18nContext'; import { - ICON_SIZES, - ICON_NAMES, -} from '../../components/component-library/icon/deprecated'; -import { ButtonIcon } from '../../components/component-library/button-icon/deprecated'; + ButtonIcon, + ButtonIconSize, + IconName, +} from '../../components/component-library'; import { Color } from '../../helpers/constants/design-system'; export function NotificationItem({ notification, snaps, onItemClick }) { @@ -91,8 +91,8 @@ export default function Notifications() {
history.push(DEFAULT_ROUTE)} /> diff --git a/ui/pages/onboarding-flow/create-password/create-password.js b/ui/pages/onboarding-flow/create-password/create-password.js index b67b5dd3b..83dcc54a3 100644 --- a/ui/pages/onboarding-flow/create-password/create-password.js +++ b/ui/pages/onboarding-flow/create-password/create-password.js @@ -35,10 +35,7 @@ import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; -import { - Icon, - ICON_NAMES, -} from '../../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../../components/component-library'; export default function CreatePassword({ createNewAccount, @@ -236,7 +233,7 @@ export default function CreatePassword({ titleDetail={ isValid && (
- +
) } diff --git a/ui/pages/onboarding-flow/metametrics/metametrics.js b/ui/pages/onboarding-flow/metametrics/metametrics.js index c6caadf56..dc35855ec 100644 --- a/ui/pages/onboarding-flow/metametrics/metametrics.js +++ b/ui/pages/onboarding-flow/metametrics/metametrics.js @@ -26,9 +26,9 @@ import { import { MetaMetricsContext } from '../../../contexts/metametrics'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; + IconName, + IconSize, +} from '../../../components/component-library'; import Box from '../../../components/ui/box/box'; @@ -99,7 +99,7 @@ export default function OnboardingMetametrics() {
  • @@ -107,7 +107,7 @@ export default function OnboardingMetametrics() {
  • @@ -117,8 +117,8 @@ export default function OnboardingMetametrics() { {t('onboardingMetametricsNeverCollect', [ @@ -137,8 +137,8 @@ export default function OnboardingMetametrics() { {t('onboardingMetametricsNeverCollectIP', [ @@ -156,8 +156,8 @@ export default function OnboardingMetametrics() { {t('onboardingMetametricsNeverSellData', [ diff --git a/ui/pages/onboarding-flow/recovery-phrase/review-recovery-phrase.js b/ui/pages/onboarding-flow/recovery-phrase/review-recovery-phrase.js index 6a2e732b5..c3e049c12 100644 --- a/ui/pages/onboarding-flow/recovery-phrase/review-recovery-phrase.js +++ b/ui/pages/onboarding-flow/recovery-phrase/review-recovery-phrase.js @@ -23,10 +23,7 @@ import { MetaMetricsEventName, } from '../../../../shared/constants/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics'; -import { - Icon, - ICON_NAMES, -} from '../../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../../components/component-library'; import RecoveryPhraseChips from './recovery-phrase-chips'; export default function RecoveryPhrase({ secretRecoveryPhrase }) { @@ -126,7 +123,7 @@ export default function RecoveryPhrase({ secretRecoveryPhrase }) { }} icon={ } diff --git a/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js b/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js index deb482023..e3017cc86 100644 --- a/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js +++ b/ui/pages/onboarding-flow/secure-your-wallet/skip-srp-backup-popover.js @@ -25,9 +25,9 @@ import { import { MetaMetricsContext } from '../../../contexts/metametrics'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; + IconName, + IconSize, +} from '../../../components/component-library'; export default function SkipSRPBackup({ handleClose }) { const [checked, setChecked] = useState(false); @@ -86,8 +86,8 @@ export default function SkipSRPBackup({ handleClose }) { margin={4} > diff --git a/ui/pages/permissions-connect/permissions-connect.component.js b/ui/pages/permissions-connect/permissions-connect.component.js index 4eaf97c6c..62d04a903 100644 --- a/ui/pages/permissions-connect/permissions-connect.component.js +++ b/ui/pages/permissions-connect/permissions-connect.component.js @@ -9,11 +9,7 @@ import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../shared/constants/app'; import { MILLISECOND } from '../../../shared/constants/time'; import { DEFAULT_ROUTE } from '../../helpers/constants/routes'; import PermissionPageContainer from '../../components/app/permission-page-container'; -import { - Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../components/component-library/icon/deprecated'; +import { Icon, IconName, IconSize } from '../../components/component-library'; import ChooseAccount from './choose-account'; import PermissionsRedirect from './redirect'; ///: BEGIN:ONLY_INCLUDE_IN(flask) @@ -283,9 +279,9 @@ export default class PermissionConnect extends Component { onClick={() => this.goBack()} > {t('back')}
diff --git a/ui/pages/permissions-connect/redirect/permissions-redirect.component.js b/ui/pages/permissions-connect/redirect/permissions-redirect.component.js index 5df81a7cd..308e71925 100644 --- a/ui/pages/permissions-connect/redirect/permissions-redirect.component.js +++ b/ui/pages/permissions-connect/redirect/permissions-redirect.component.js @@ -12,9 +12,9 @@ import { import { I18nContext } from '../../../contexts/i18n'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; + IconName, + IconSize, +} from '../../../components/component-library'; export default function PermissionsRedirect({ subjectMetadata }) { const t = useContext(I18nContext); @@ -42,8 +42,8 @@ export default function PermissionsRedirect({ subjectMetadata }) { justifyContent={JustifyContent.center} >
diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/pages/send/send-content/add-recipient/add-recipient.component.js index f1e5da55b..7190c6dc8 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.component.js @@ -8,10 +8,7 @@ import RecipientGroup from '../../../../components/app/contact-list/recipient-gr import { ellipsify } from '../../send.utils'; import Button from '../../../../components/ui/button'; import Confusable from '../../../../components/ui/confusable'; -import { - Icon, - ICON_NAMES, -} from '../../../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../../../components/component-library'; export default class AddRecipient extends Component { static propTypes = { @@ -184,7 +181,7 @@ export default class AddRecipient extends Component { className="send__select-recipient-wrapper__list__link" onClick={useContactListForRecipientSearch} > - + {t('backToAll')} ) : ( @@ -130,11 +130,11 @@ export default class DomainInput extends Component { )}
) : ( @@ -160,9 +160,7 @@ export default class DomainInput extends Component { this.props.scanQrCode(); } }} - iconName={ - userInput ? ICON_NAMES.CLOSE : ICON_NAMES.SCAN_BARCODE - } + iconName={userInput ? IconName.Close : IconName.ScanBarcode} ariaLabel={t(userInput ? 'close' : 'scanQrCode')} color={ userInput ? IconColor.iconDefault : IconColor.primaryDefault diff --git a/ui/pages/settings/contact-list-tab/contact-list-tab.component.js b/ui/pages/settings/contact-list-tab/contact-list-tab.component.js index 46d3155bc..02cce6a37 100644 --- a/ui/pages/settings/contact-list-tab/contact-list-tab.component.js +++ b/ui/pages/settings/contact-list-tab/contact-list-tab.component.js @@ -13,10 +13,10 @@ import { } from '../../../helpers/utils/settings-search'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../components/component-library/icon/deprecated'; -import { Color } from '../../../helpers/constants/design-system'; + IconName, + IconSize, +} from '../../../components/component-library'; +import { IconColor } from '../../../helpers/constants/design-system'; import EditContact from './edit-contact'; import AddContact from './add-contact'; import ViewContact from './view-contact'; @@ -79,10 +79,10 @@ export default class ContactListTab extends Component {

{t('buildContactList')}

diff --git a/ui/pages/settings/contact-list-tab/view-contact/view-contact.component.js b/ui/pages/settings/contact-list-tab/view-contact/view-contact.component.js index 8a28efe00..5045b9565 100644 --- a/ui/pages/settings/contact-list-tab/view-contact/view-contact.component.js +++ b/ui/pages/settings/contact-list-tab/view-contact/view-contact.component.js @@ -4,12 +4,12 @@ import { Redirect } from 'react-router-dom'; import Identicon from '../../../../components/ui/identicon'; import Button from '../../../../components/ui/button/button.component'; -import { - ICON_NAMES, - ICON_SIZES, -} from '../../../../components/component-library/icon/deprecated'; -import { ButtonIcon } from '../../../../components/component-library/button-icon/deprecated'; +import { + ButtonIcon, + ButtonIconSize, + IconName, +} from '../../../../components/component-library'; import Tooltip from '../../../../components/ui/tooltip'; import { useI18nContext } from '../../../../hooks/useI18nContext'; @@ -74,8 +74,8 @@ function ViewContact({ onClick={() => { handleCopy(checkSummedAddress); }} - iconName={copied ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY} - size={ICON_SIZES.LG} + iconName={copied ? IconName.CopySuccess : IconName.Copy} + size={ButtonIconSize.Lg} color={IconColor.primaryDefault} /> diff --git a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js b/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js index f745b3ff0..6fcfbab2f 100644 --- a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js +++ b/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js @@ -6,6 +6,7 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; import { JustifyContent, AlignItems, + IconColor, Color, TEXT_ALIGN, FLEX_DIRECTION, @@ -15,15 +16,13 @@ import Box from '../../../../components/ui/box'; import { SNAPS_VIEW_ROUTE } from '../../../../helpers/constants/routes'; import { getSnapsList } from '../../../../selectors'; import { handleSettingsRefs } from '../../../../helpers/utils/settings-search'; -import { - Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../../components/component-library/icon/deprecated'; import { BannerTip, BannerTipLogoType, ButtonLink, + Icon, + IconName, + IconSize, Text, } from '../../../../components/component-library'; @@ -79,10 +78,10 @@ const SnapListTab = () => { alignItems={AlignItems.center} > handleSearch('')} > - + )} diff --git a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js index 00c615a18..cd8ef4b12 100644 --- a/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js +++ b/ui/pages/settings/networks-tab/networks-list-item/networks-list-item.js @@ -18,9 +18,9 @@ import UrlIcon from '../../../../components/ui/url-icon'; import { handleSettingsRefs } from '../../../../helpers/utils/settings-search'; import { Icon, - ICON_NAMES, - ICON_SIZES, -} from '../../../../components/component-library/icon/deprecated'; + IconName, + IconSize, +} from '../../../../components/component-library'; import { IconColor } from '../../../../helpers/constants/design-system'; const NetworksListItem = ({ @@ -79,9 +79,9 @@ const NetworksListItem = ({ }} > {isCurrentRpcTarget ? ( - + ) : ( - + )} {network.chainId in CHAIN_ID_TO_NETWORK_IMAGE_URL_MAP ? ( )} diff --git a/ui/pages/settings/settings-search-list/settings-search-list.js b/ui/pages/settings/settings-search-list/settings-search-list.js index 696b969cc..fc659c794 100644 --- a/ui/pages/settings/settings-search-list/settings-search-list.js +++ b/ui/pages/settings/settings-search-list/settings-search-list.js @@ -3,10 +3,7 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { highlightSearchedText } from '../../../helpers/utils/settings-search'; import { I18nContext } from '../../../contexts/i18n'; -import { - Icon, - ICON_NAMES, -} from '../../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../../components/component-library'; import { Size } from '../../../helpers/constants/design-system'; export default function SettingsSearchList({ results, onClickSetting }) { @@ -48,7 +45,7 @@ export default function SettingsSearchList({ results, onClickSetting }) { {tabMessage(t)} diff --git a/ui/pages/settings/settings-search/settings-search.js b/ui/pages/settings/settings-search/settings-search.js index 28e0314a0..b3f3eb77c 100644 --- a/ui/pages/settings/settings-search/settings-search.js +++ b/ui/pages/settings/settings-search/settings-search.js @@ -9,10 +9,7 @@ import TextField from '../../../components/ui/text-field'; import { I18nContext } from '../../../contexts/i18n'; import SearchIcon from '../../../components/ui/icon/search-icon'; import { isEqualCaseInsensitive } from '../../../../shared/modules/string-utils'; -import { - Icon, - ICON_NAMES, -} from '../../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../../components/component-library'; import { IconColor } from '../../../helpers/constants/design-system'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { getSnapsRouteObjects } from '../../../selectors'; @@ -88,7 +85,7 @@ export default function SettingsSearch({ onClick={() => handleSearch('')} style={{ cursor: 'pointer' }} > - + )} diff --git a/ui/pages/settings/settings.component.js b/ui/pages/settings/settings.component.js index 57ba8833d..25a8d9dd1 100644 --- a/ui/pages/settings/settings.component.js +++ b/ui/pages/settings/settings.component.js @@ -27,11 +27,7 @@ import { import { getSettingsRoutes } from '../../helpers/utils/settings-search'; import AddNetwork from '../../components/app/add-network/add-network'; -import { ButtonIcon } from '../../components/component-library/button-icon/deprecated'; -import { - Icon, - ICON_NAMES, -} from '../../components/component-library/icon/deprecated'; +import { ButtonIcon, Icon, IconName } from '../../components/component-library'; import { Color, DISPLAY } from '../../helpers/constants/design-system'; import SettingsTab from './settings-tab'; import AlertsTab from './alerts-tab'; @@ -125,7 +121,7 @@ class SettingsPage extends PureComponent { {currentPath !== SETTINGS_ROUTE && ( history.push(backRoute)} @@ -263,7 +259,7 @@ class SettingsPage extends PureComponent { const tabs = [ { content: t('general'), - icon: , + icon: , key: GENERAL_ROUTE, }, { @@ -273,7 +269,7 @@ class SettingsPage extends PureComponent { }, { content: t('contacts'), - icon: , + icon: , key: CONTACT_LIST_ROUTE, }, ///: BEGIN:ONLY_INCLUDE_IN(flask) @@ -292,7 +288,7 @@ class SettingsPage extends PureComponent { }, { content: t('alerts'), - icon: , + icon: , key: ALERTS_ROUTE, }, { diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js index 10cc6ced0..9fe4244ef 100644 --- a/ui/pages/token-allowance/token-allowance.js +++ b/ui/pages/token-allowance/token-allowance.js @@ -61,10 +61,7 @@ import { import { ConfirmPageContainerNavigation } from '../../components/app/confirm-page-container'; import { useSimulationFailureWarning } from '../../hooks/useSimulationFailureWarning'; import SimulationErrorMessage from '../../components/ui/simulation-error-message'; -import { - Icon, - ICON_NAMES, -} from '../../components/component-library/icon/deprecated'; +import { Icon, IconName } from '../../components/component-library'; import LedgerInstructionField from '../../components/app/ledger-instruction-field/ledger-instruction-field'; import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../../components/app/security-provider-banner-message/security-provider-banner-message.constants'; import SecurityProviderBannerMessage from '../../components/app/security-provider-banner-message/security-provider-banner-message'; @@ -448,7 +445,7 @@ export default function TokenAllowance({ )} } + symbol={} title={t('transactionFee')} showEdit showAdvanceGasFeeOptions diff --git a/ui/pages/token-details/token-details-page.js b/ui/pages/token-details/token-details-page.js index 91a088b3d..a6628017a 100644 --- a/ui/pages/token-details/token-details-page.js +++ b/ui/pages/token-details/token-details-page.js @@ -26,10 +26,10 @@ import { } from '../../helpers/constants/design-system'; import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils'; import { - ICON_SIZES, - ICON_NAMES, -} from '../../components/component-library/icon/deprecated'; -import { ButtonIcon } from '../../components/component-library/button-icon/deprecated'; + ButtonIcon, + ButtonIconSize, + IconName, +} from '../../components/component-library'; export default function TokenDetailsPage() { const dispatch = useDispatch(); @@ -139,11 +139,11 @@ export default function TokenDetailsPage() { > handleCopy(token.address)} color={IconColor.primaryDefault} - size={ICON_SIZES.SM} + size={ButtonIconSize.Sm} /> From 632ae0b7c3c4beb64bb518398a706cc6036ce764 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Mon, 24 Apr 2023 15:44:42 +0100 Subject: [PATCH 10/60] Prevent new JS files in shared folder (#17737) * Prevent new JS files in shared folder * migrate to typescript * fix types * cleanup --- .github/workflows/fitness-functions.yml | 2 +- .../fitness-functions/check-mocha-syntax.js | 44 ------- .../common/constants.test.ts | 105 +++++++++++++++ .../fitness-functions/common/constants.ts | 15 +++ .../fitness-functions/common/get-diff.ts | 54 ++++++++ .../{shared.test.js => common/shared.test.ts} | 120 ++++++------------ .../{shared.js => common/shared.ts} | 42 ++++-- .../fitness-functions/common/test-data.ts | 40 ++++++ development/fitness-functions/index.js | 53 -------- development/fitness-functions/index.ts | 11 ++ development/fitness-functions/rules/index.ts | 42 ++++++ .../rules/javascript-additions.test.ts | 51 ++++++++ .../rules/javascript-additions.ts | 18 +++ .../rules/sinon-assert-syntax.test.ts | 29 +++++ .../rules/sinon-assert-syntax.ts | 30 +++++ package.json | 2 +- 16 files changed, 467 insertions(+), 191 deletions(-) delete mode 100644 development/fitness-functions/check-mocha-syntax.js create mode 100644 development/fitness-functions/common/constants.test.ts create mode 100644 development/fitness-functions/common/constants.ts create mode 100644 development/fitness-functions/common/get-diff.ts rename development/fitness-functions/{shared.test.js => common/shared.test.ts} (59%) rename development/fitness-functions/{shared.js => common/shared.ts} (60%) create mode 100644 development/fitness-functions/common/test-data.ts delete mode 100644 development/fitness-functions/index.js create mode 100644 development/fitness-functions/index.ts create mode 100644 development/fitness-functions/rules/index.ts create mode 100644 development/fitness-functions/rules/javascript-additions.test.ts create mode 100644 development/fitness-functions/rules/javascript-additions.ts create mode 100644 development/fitness-functions/rules/sinon-assert-syntax.test.ts create mode 100644 development/fitness-functions/rules/sinon-assert-syntax.ts diff --git a/.github/workflows/fitness-functions.yml b/.github/workflows/fitness-functions.yml index 7549be6b4..1b55fb461 100644 --- a/.github/workflows/fitness-functions.yml +++ b/.github/workflows/fitness-functions.yml @@ -24,5 +24,5 @@ jobs: run: | # git fetch origin $HEAD_REF # git fetch origin $BASE_REF - # git diff origin/$BASE_REF origin/$HEAD_REF -- . ':(exclude)development/fitness-functions/*' > diff + # git diff origin/$BASE_REF origin/$HEAD_REF -- . > diff # npm run fitness-functions -- "ci" "./diff" diff --git a/development/fitness-functions/check-mocha-syntax.js b/development/fitness-functions/check-mocha-syntax.js deleted file mode 100644 index 2e4cea384..000000000 --- a/development/fitness-functions/check-mocha-syntax.js +++ /dev/null @@ -1,44 +0,0 @@ -const { - EXCLUDE_E2E_TESTS_REGEX, - filterDiffAdditions, - filterDiffByFilePath, - hasNumberOfCodeBlocksIncreased, -} = require('./shared'); - -function checkMochaSyntax(diff) { - const ruleHeading = 'favor-jest-instead-of-mocha'; - const codeBlocks = [ - "import { strict as assert } from 'assert';", - 'assert.deepEqual', - 'assert.equal', - 'assert.rejects', - 'assert.strictEqual', - 'sinon.', - ]; - - console.log(`\nChecking ${ruleHeading}...`); - - const diffByFilePath = filterDiffByFilePath(diff, EXCLUDE_E2E_TESTS_REGEX); - const diffAdditions = filterDiffAdditions(diffByFilePath); - const hashmap = hasNumberOfCodeBlocksIncreased(diffAdditions, codeBlocks); - - Object.keys(hashmap).forEach((key) => { - if (hashmap[key]) { - console.error(`Number of occurences of "${key}" have increased.`); - } - }); - - if (Object.values(hashmap).includes(true)) { - console.error( - `...changes have not been accepted by the fitness function.\nFor more info, see: https://github.com/MetaMask/metamask-extension/blob/develop/docs/testing.md#${ruleHeading}`, - ); - process.exit(1); - } else { - console.log( - `...number of occurences has not increased for any code block.`, - ); - process.exit(0); - } -} - -module.exports = { checkMochaSyntax }; diff --git a/development/fitness-functions/common/constants.test.ts b/development/fitness-functions/common/constants.test.ts new file mode 100644 index 000000000..21912d5fa --- /dev/null +++ b/development/fitness-functions/common/constants.test.ts @@ -0,0 +1,105 @@ +import { EXCLUDE_E2E_TESTS_REGEX, SHARED_FOLDER_JS_REGEX } from './constants'; + +describe('Regular Expressions used in Fitness Functions', (): void => { + describe(`EXCLUDE_E2E_TESTS_REGEX "${EXCLUDE_E2E_TESTS_REGEX}"`, (): void => { + const PATHS_IT_SHOULD_MATCH = [ + 'file.js', + 'path/file.js', + 'much/longer/path/file.js', + 'file.ts', + 'path/file.ts', + 'much/longer/path/file.ts', + 'file.jsx', + 'path/file.jsx', + 'much/longer/path/file.jsx', + ]; + + const PATHS_IT_SHOULD_NOT_MATCH = [ + // any without JS, TS, JSX or TSX extension + 'file', + 'file.extension', + 'path/file.extension', + 'much/longer/path/file.extension', + // any in the test/e2e directory + 'test/e2e/file', + 'test/e2e/file.extension', + 'test/e2e/path/file.extension', + 'test/e2e/much/longer/path/file.extension', + 'test/e2e/file.js', + 'test/e2e/path/file.ts', + 'test/e2e/much/longer/path/file.jsx', + 'test/e2e/much/longer/path/file.tsx', + // any in the development/fitness-functions directory + 'development/fitness-functions/file', + 'development/fitness-functions/file.extension', + 'development/fitness-functions/path/file.extension', + 'development/fitness-functions/much/longer/path/file.extension', + 'development/fitness-functions/file.js', + 'development/fitness-functions/path/file.ts', + 'development/fitness-functions/much/longer/path/file.jsx', + 'development/fitness-functions/much/longer/path/file.tsx', + ]; + + describe('included paths', (): void => { + PATHS_IT_SHOULD_MATCH.forEach((path: string): void => { + it(`should match "${path}"`, (): void => { + const result = new RegExp(EXCLUDE_E2E_TESTS_REGEX, 'u').test(path); + + expect(result).toStrictEqual(true); + }); + }); + }); + + describe('excluded paths', (): void => { + PATHS_IT_SHOULD_NOT_MATCH.forEach((path: string): void => { + it(`should not match "${path}"`, (): void => { + const result = new RegExp(EXCLUDE_E2E_TESTS_REGEX, 'u').test(path); + + expect(result).toStrictEqual(false); + }); + }); + }); + }); + + describe(`SHARED_FOLDER_JS_REGEX "${SHARED_FOLDER_JS_REGEX}"`, (): void => { + const PATHS_IT_SHOULD_MATCH = [ + 'shared/file.js', + 'shared/path/file.js', + 'shared/much/longer/path/file.js', + 'shared/file.jsx', + 'shared/path/file.jsx', + 'shared/much/longer/path/file.jsx', + ]; + + const PATHS_IT_SHOULD_NOT_MATCH = [ + // any without JS or JSX extension + 'file', + 'file.extension', + 'path/file.extension', + 'much/longer/path/file.extension', + 'file.ts', + 'path/file.ts', + 'much/longer/path/file.tsx', + ]; + + describe('included paths', (): void => { + PATHS_IT_SHOULD_MATCH.forEach((path: string): void => { + it(`should match "${path}"`, (): void => { + const result = new RegExp(SHARED_FOLDER_JS_REGEX, 'u').test(path); + + expect(result).toStrictEqual(true); + }); + }); + }); + + describe('excluded paths', (): void => { + PATHS_IT_SHOULD_NOT_MATCH.forEach((path: string): void => { + it(`should not match "${path}"`, (): void => { + const result = new RegExp(SHARED_FOLDER_JS_REGEX, 'u').test(path); + + expect(result).toStrictEqual(false); + }); + }); + }); + }); +}); diff --git a/development/fitness-functions/common/constants.ts b/development/fitness-functions/common/constants.ts new file mode 100644 index 000000000..0514c6ed9 --- /dev/null +++ b/development/fitness-functions/common/constants.ts @@ -0,0 +1,15 @@ +// include JS, TS, JSX, TSX files only excluding files in the e2e tests and +// fitness functions directories +const EXCLUDE_E2E_TESTS_REGEX = + '^(?!test/e2e)(?!development/fitness).*.(js|ts|jsx|tsx)$'; + +// include JS and JSX files in the shared directory only +const SHARED_FOLDER_JS_REGEX = '^(shared).*.(js|jsx)$'; + +enum AUTOMATION_TYPE { + CI = 'ci', + PRE_COMMIT_HOOK = 'pre-commit-hook', + PRE_PUSH_HOOK = 'pre-push-hook', +} + +export { EXCLUDE_E2E_TESTS_REGEX, SHARED_FOLDER_JS_REGEX, AUTOMATION_TYPE }; diff --git a/development/fitness-functions/common/get-diff.ts b/development/fitness-functions/common/get-diff.ts new file mode 100644 index 000000000..620d53b63 --- /dev/null +++ b/development/fitness-functions/common/get-diff.ts @@ -0,0 +1,54 @@ +import { execSync } from 'child_process'; +import fs from 'fs'; +import { AUTOMATION_TYPE } from './constants'; + +function getDiffByAutomationType( + automationType: AUTOMATION_TYPE, +): string | undefined { + if (!Object.values(AUTOMATION_TYPE).includes(automationType)) { + console.error('Invalid automation type.'); + process.exit(1); + } + + let diff; + if (automationType === AUTOMATION_TYPE.CI) { + const optionalArguments = process.argv.slice(3); + if (optionalArguments.length !== 1) { + console.error('Invalid number of arguments.'); + process.exit(1); + } + + diff = getCIDiff(optionalArguments[0]); + } else if (automationType === AUTOMATION_TYPE.PRE_COMMIT_HOOK) { + diff = getPreCommitHookDiff(); + } else if (automationType === AUTOMATION_TYPE.PRE_PUSH_HOOK) { + diff = getPrePushHookDiff(); + } + + return diff; +} + +function getCIDiff(path: string): string { + return fs.readFileSync(path, { + encoding: 'utf8', + flag: 'r', + }); +} + +function getPreCommitHookDiff(): string { + return execSync(`git diff --cached HEAD`).toString().trim(); +} + +function getPrePushHookDiff(): string { + const currentBranch = execSync(`git rev-parse --abbrev-ref HEAD`) + .toString() + .trim(); + + return execSync( + `git diff ${currentBranch} origin/${currentBranch} -- . ':(exclude)development/fitness-functions/'`, + ) + .toString() + .trim(); +} + +export { getDiffByAutomationType }; diff --git a/development/fitness-functions/shared.test.js b/development/fitness-functions/common/shared.test.ts similarity index 59% rename from development/fitness-functions/shared.test.js rename to development/fitness-functions/common/shared.test.ts index 6b464aafd..92306b9d4 100644 --- a/development/fitness-functions/shared.test.js +++ b/development/fitness-functions/common/shared.test.ts @@ -1,46 +1,48 @@ -const { - EXCLUDE_E2E_TESTS_REGEX, - filterDiffAdditions, +import { + filterDiffLineAdditions, hasNumberOfCodeBlocksIncreased, filterDiffByFilePath, -} = require('./shared'); + filterDiffFileCreations, +} from './shared'; +import { generateCreateFileDiff, generateModifyFilesDiff } from './test-data'; -const generateCreateFileDiff = (filePath, content) => ` -diff --git a/${filePath} b/${filePath} -new file mode 100644 -index 000000000..30d74d258 ---- /dev/null -+++ b/${filePath} -@@ -0,0 +1 @@ -+${content} -`; - -const generateModifyFilesDiff = (filePath, addition, removal) => ` -diff --git a/${filePath} b/${filePath} -index 57d5de75c..808d8ba37 100644 ---- a/${filePath} -+++ b/${filePath} -@@ -1,3 +1,8 @@ -+${addition} -@@ -34,33 +39,4 @@ --${removal} -`; - -describe('filterDiffAdditions()', () => { - it('should return code additions in the diff', () => { +describe('filterDiffLineAdditions()', (): void => { + it('should return code additions in the diff', (): void => { const testFilePath = 'new-file.js'; const testAddition = 'foo'; const testFileDiff = generateCreateFileDiff(testFilePath, testAddition); - const actualResult = filterDiffAdditions(testFileDiff); + const actualResult = filterDiffLineAdditions(testFileDiff); const expectedResult = `+${testAddition}`; expect(actualResult).toStrictEqual(expectedResult); }); }); -describe('hasNumberOfCodeBlocksIncreased()', () => { - it('should show which code blocks have increased', () => { +describe('filterDiffFileCreations()', (): void => { + it('should return code additions in the diff', (): void => { + const testFileDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateCreateFileDiff('old-file.js', 'ping'), + generateModifyFilesDiff('old-file.jsx', 'yin', 'yang'), + ].join(''); + + const actualResult = filterDiffFileCreations(testFileDiff); + + expect(actualResult).toMatchInlineSnapshot(` + "diff --git a/old-file.js b/old-file.js + new file mode 100644 + index 000000000..30d74d258 + --- /dev/null + +++ b/old-file.js + @@ -0,0 +1 @@ + +ping" + `); + }); +}); + +describe('hasNumberOfCodeBlocksIncreased()', (): void => { + it('should show which code blocks have increased', (): void => { const testDiffFragment = ` +foo +bar @@ -57,14 +59,14 @@ describe('hasNumberOfCodeBlocksIncreased()', () => { }); }); -describe('filterDiffByFilePath()', () => { +describe('filterDiffByFilePath()', (): void => { const testFileDiff = [ generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), generateModifyFilesDiff('old-file.js', 'ping', 'pong'), generateModifyFilesDiff('old-file.jsx', 'yin', 'yang'), ].join(''); - it('should return the right diff for a generic matcher', () => { + it('should return the right diff for a generic matcher', (): void => { const actualResult = filterDiffByFilePath( testFileDiff, '.*/.*.(js|ts)$|.*.(js|ts)$', @@ -90,7 +92,7 @@ describe('filterDiffByFilePath()', () => { `); }); - it('should return the right diff for a specific file in any dir matcher', () => { + it('should return the right diff for a specific file in any dir matcher', (): void => { const actualResult = filterDiffByFilePath(testFileDiff, '.*old-file.js$'); expect(actualResult).toMatchInlineSnapshot(` @@ -105,7 +107,7 @@ describe('filterDiffByFilePath()', () => { `); }); - it('should return the right diff for a multiple file extension (OR) matcher', () => { + it('should return the right diff for a multiple file extension (OR) matcher', (): void => { const actualResult = filterDiffByFilePath( testFileDiff, '^(./)*old-file.(js|ts|jsx)$', @@ -131,7 +133,7 @@ describe('filterDiffByFilePath()', () => { `); }); - it('should return the right diff for a file name negation matcher', () => { + it('should return the right diff for a file name negation matcher', (): void => { const actualResult = filterDiffByFilePath( testFileDiff, '^(?!.*old-file.js$).*.[a-zA-Z]+$', @@ -157,51 +159,3 @@ describe('filterDiffByFilePath()', () => { `); }); }); - -describe(`EXCLUDE_E2E_TESTS_REGEX "${EXCLUDE_E2E_TESTS_REGEX}"`, () => { - const PATHS_IT_SHOULD_MATCH = [ - 'file.js', - 'path/file.js', - 'much/longer/path/file.js', - 'file.ts', - 'path/file.ts', - 'much/longer/path/file.ts', - 'file.jsx', - 'path/file.jsx', - 'much/longer/path/file.jsx', - ]; - - const PATHS_IT_SHOULD_NOT_MATCH = [ - 'test/e2e/file', - 'test/e2e/file.extension', - 'test/e2e/path/file.extension', - 'test/e2e/much/longer/path/file.extension', - 'test/e2e/file.js', - 'test/e2e/path/file.ts', - 'test/e2e/much/longer/path/file.jsx', - 'file', - 'file.extension', - 'path/file.extension', - 'much/longer/path/file.extension', - ]; - - describe('included paths', () => { - PATHS_IT_SHOULD_MATCH.forEach((path) => { - it(`should match "${path}"`, () => { - const result = new RegExp(EXCLUDE_E2E_TESTS_REGEX, 'u').test(path); - - expect(result).toStrictEqual(true); - }); - }); - }); - - describe('excluded paths', () => { - PATHS_IT_SHOULD_NOT_MATCH.forEach((path) => { - it(`should not match "${path}"`, () => { - const result = new RegExp(EXCLUDE_E2E_TESTS_REGEX, 'u').test(path); - - expect(result).toStrictEqual(false); - }); - }); - }); -}); diff --git a/development/fitness-functions/shared.js b/development/fitness-functions/common/shared.ts similarity index 60% rename from development/fitness-functions/shared.js rename to development/fitness-functions/common/shared.ts index 791837a6d..e24c8cf01 100644 --- a/development/fitness-functions/shared.js +++ b/development/fitness-functions/common/shared.ts @@ -1,6 +1,4 @@ -const EXCLUDE_E2E_TESTS_REGEX = '^(?!test/e2e/).*.(js|ts|jsx)$'; - -function filterDiffByFilePath(diff, regex) { +function filterDiffByFilePath(diff: string, regex: string): string { // split by `diff --git` and remove the first element which is empty const diffBlocks = diff.split(`diff --git`).slice(1); @@ -34,7 +32,7 @@ function filterDiffByFilePath(diff, regex) { return filteredDiff; } -function filterDiffAdditions(diff) { +function filterDiffLineAdditions(diff: string): string { const diffLines = diff.split('\n'); const diffAdditionLines = diffLines.filter((line) => { @@ -46,10 +44,36 @@ function filterDiffAdditions(diff) { return diffAdditionLines.join('/n'); } -function hasNumberOfCodeBlocksIncreased(diffFragment, codeBlocks) { +function filterDiffFileCreations(diff: string): string { + // split by `diff --git` and remove the first element which is empty + const diffBlocks = diff.split(`diff --git`).slice(1); + + const filteredDiff = diffBlocks + .map((block) => block.trim()) + .filter((block) => { + const isFileCreationLine = + block + // get the second line of the block which has the file mode + .split('\n')[1] + .trim() + .substring(0, 13) === 'new file mode'; + + return isFileCreationLine; + }) + // prepend `git --diff` to each block + .map((block) => `diff --git ${block}`) + .join('\n'); + + return filteredDiff; +} + +function hasNumberOfCodeBlocksIncreased( + diffFragment: string, + codeBlocks: string[], +): { [codeBlock: string]: boolean } { const diffLines = diffFragment.split('\n'); - const codeBlockFound = {}; + const codeBlockFound: { [codeBlock: string]: boolean } = {}; for (const codeBlock of codeBlocks) { codeBlockFound[codeBlock] = false; @@ -65,9 +89,9 @@ function hasNumberOfCodeBlocksIncreased(diffFragment, codeBlocks) { return codeBlockFound; } -module.exports = { - EXCLUDE_E2E_TESTS_REGEX, +export { filterDiffByFilePath, - filterDiffAdditions, + filterDiffLineAdditions, + filterDiffFileCreations, hasNumberOfCodeBlocksIncreased, }; diff --git a/development/fitness-functions/common/test-data.ts b/development/fitness-functions/common/test-data.ts new file mode 100644 index 000000000..7dac4dee1 --- /dev/null +++ b/development/fitness-functions/common/test-data.ts @@ -0,0 +1,40 @@ +const generateCreateFileDiff = ( + filePath = 'file.txt', + content = 'Lorem ipsum', +): string => ` +diff --git a/${filePath} b/${filePath} +new file mode 100644 +index 000000000..30d74d258 +--- /dev/null ++++ b/${filePath} +@@ -0,0 +1 @@ ++${content} +`; + +const generateModifyFilesDiff = ( + filePath = 'file.txt', + addition = 'Lorem ipsum', + removal = '', +): string => { + const additionBlock = addition + ? ` +@@ -1,3 +1,8 @@ ++${addition}`.trim() + : ''; + + const removalBlock = removal + ? ` +@@ -34,33 +39,4 @@ +-${removal}`.trim() + : ''; + + return ` +diff --git a/${filePath} b/${filePath} +index 57d5de75c..808d8ba37 100644 +--- a/${filePath} ++++ b/${filePath} +${additionBlock} +${removalBlock}`; +}; + +export { generateCreateFileDiff, generateModifyFilesDiff }; diff --git a/development/fitness-functions/index.js b/development/fitness-functions/index.js deleted file mode 100644 index 37b61819d..000000000 --- a/development/fitness-functions/index.js +++ /dev/null @@ -1,53 +0,0 @@ -const fs = require('fs'); -const { execSync } = require('child_process'); -const { checkMochaSyntax } = require('./check-mocha-syntax'); - -const AUTOMATION_TYPE = Object.freeze({ - CI: 'ci', - PRE_COMMIT_HOOK: 'pre-commit-hook', - PRE_PUSH_HOOK: 'pre-push-hook', -}); - -const automationType = process.argv[2]; - -if (automationType === AUTOMATION_TYPE.CI) { - const optionalArguments = process.argv.slice(3); - if (optionalArguments.length !== 1) { - console.error('Invalid number of arguments.'); - process.exit(1); - } - - const diff = fs.readFileSync(optionalArguments[0], { - encoding: 'utf8', - flag: 'r', - }); - - checkMochaSyntax(diff); -} else if (automationType === AUTOMATION_TYPE.PRE_COMMIT_HOOK) { - const diff = getPreCommitHookDiff(); - - checkMochaSyntax(diff); -} else if (automationType === AUTOMATION_TYPE.PRE_PUSH_HOOK) { - const diff = getPrePushHookDiff(); - - checkMochaSyntax(diff); -} else { - console.error('Invalid automation type.'); - process.exit(1); -} - -function getPreCommitHookDiff() { - return execSync(`git diff --cached HEAD`).toString().trim(); -} - -function getPrePushHookDiff() { - const currentBranch = execSync(`git rev-parse --abbrev-ref HEAD`) - .toString() - .trim(); - - return execSync( - `git diff ${currentBranch} origin/${currentBranch} -- . ':(exclude)development/fitness-functions/'`, - ) - .toString() - .trim(); -} diff --git a/development/fitness-functions/index.ts b/development/fitness-functions/index.ts new file mode 100644 index 000000000..2cb720d4f --- /dev/null +++ b/development/fitness-functions/index.ts @@ -0,0 +1,11 @@ +import { AUTOMATION_TYPE } from './common/constants'; +import { getDiffByAutomationType } from './common/get-diff'; +import { IRule, RULES, runFitnessFunctionRule } from './rules'; + +const automationType: AUTOMATION_TYPE = process.argv[2] as AUTOMATION_TYPE; + +const diff = getDiffByAutomationType(automationType); + +if (typeof diff === 'string') { + RULES.forEach((rule: IRule): void => runFitnessFunctionRule(rule, diff)); +} diff --git a/development/fitness-functions/rules/index.ts b/development/fitness-functions/rules/index.ts new file mode 100644 index 000000000..30844652c --- /dev/null +++ b/development/fitness-functions/rules/index.ts @@ -0,0 +1,42 @@ +import { preventSinonAssertSyntax } from './sinon-assert-syntax'; +import { preventJavaScriptFileAdditions } from './javascript-additions'; + +const RULES: IRule[] = [ + { + name: "Don't use `sinon` or `assert` in unit tests", + fn: preventSinonAssertSyntax, + docURL: + 'https://github.com/MetaMask/metamask-extension/blob/develop/docs/testing.md#favor-jest-instead-of-mocha', + }, + { + name: "Don't add JS or JSX files to the `shared` directory", + fn: preventJavaScriptFileAdditions, + }, +]; + +interface IRule { + name: string; + fn: (diff: string) => boolean; + docURL?: string; +} + +function runFitnessFunctionRule(rule: IRule, diff: string): void { + const { name, fn, docURL } = rule; + console.log(`Checking rule "${name}"...`); + + const hasRulePassed: boolean = fn(diff) as boolean; + if (hasRulePassed === true) { + console.log(`...OK`); + } else { + console.log(`...FAILED. Changes not accepted by the fitness function.`); + + if (docURL) { + console.log(`For more info: ${docURL}.`); + } + + process.exit(1); + } +} + +export { RULES, runFitnessFunctionRule }; +export type { IRule }; diff --git a/development/fitness-functions/rules/javascript-additions.test.ts b/development/fitness-functions/rules/javascript-additions.test.ts new file mode 100644 index 000000000..db1803c1d --- /dev/null +++ b/development/fitness-functions/rules/javascript-additions.test.ts @@ -0,0 +1,51 @@ +import { + generateModifyFilesDiff, + generateCreateFileDiff, +} from '../common/test-data'; +import { preventJavaScriptFileAdditions } from './javascript-additions'; + +describe('preventJavaScriptFileAdditions()', (): void => { + it('should pass when receiving an empty diff', (): void => { + const testDiff = ''; + + const hasRulePassed = preventJavaScriptFileAdditions(testDiff); + + expect(hasRulePassed).toBe(true); + }); + + it('should pass when receiving a diff with a new TS file on the shared folder', (): void => { + const testDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateModifyFilesDiff('old-file.js', undefined, 'pong'), + generateCreateFileDiff('shared/test.ts', 'yada yada yada yada'), + ].join(''); + + const hasRulePassed = preventJavaScriptFileAdditions(testDiff); + + expect(hasRulePassed).toBe(true); + }); + + it('should not pass when receiving a diff with a new JS file on the shared folder', (): void => { + const testDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateModifyFilesDiff('old-file.js', undefined, 'pong'), + generateCreateFileDiff('shared/test.js', 'yada yada yada yada'), + ].join(''); + + const hasRulePassed = preventJavaScriptFileAdditions(testDiff); + + expect(hasRulePassed).toBe(false); + }); + + it('should not pass when receiving a diff with a new JSX file on the shared folder', (): void => { + const testDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateModifyFilesDiff('old-file.js', undefined, 'pong'), + generateCreateFileDiff('shared/test.jsx', 'yada yada yada yada'), + ].join(''); + + const hasRulePassed = preventJavaScriptFileAdditions(testDiff); + + expect(hasRulePassed).toBe(false); + }); +}); diff --git a/development/fitness-functions/rules/javascript-additions.ts b/development/fitness-functions/rules/javascript-additions.ts new file mode 100644 index 000000000..3e3705ea3 --- /dev/null +++ b/development/fitness-functions/rules/javascript-additions.ts @@ -0,0 +1,18 @@ +import { SHARED_FOLDER_JS_REGEX } from '../common/constants'; +import { + filterDiffByFilePath, + filterDiffFileCreations, +} from '../common/shared'; + +function preventJavaScriptFileAdditions(diff: string): boolean { + const sharedFolderDiff = filterDiffByFilePath(diff, SHARED_FOLDER_JS_REGEX); + const sharedFolderCreationDiff = filterDiffFileCreations(sharedFolderDiff); + + const hasCreatedAtLeastOneJSFileInShared = sharedFolderCreationDiff !== ''; + if (hasCreatedAtLeastOneJSFileInShared) { + return false; + } + return true; +} + +export { preventJavaScriptFileAdditions }; diff --git a/development/fitness-functions/rules/sinon-assert-syntax.test.ts b/development/fitness-functions/rules/sinon-assert-syntax.test.ts new file mode 100644 index 000000000..ea403d4a0 --- /dev/null +++ b/development/fitness-functions/rules/sinon-assert-syntax.test.ts @@ -0,0 +1,29 @@ +import { generateModifyFilesDiff } from '../common/test-data'; +import { preventSinonAssertSyntax } from './sinon-assert-syntax'; + +describe('preventSinonAssertSyntax()', (): void => { + it('should pass when receiving an empty diff', (): void => { + const testDiff = ''; + + const hasRulePassed = preventSinonAssertSyntax(testDiff); + + expect(hasRulePassed).toBe(true); + }); + + it('should not pass when receiving a diff with one of the blocked expressions', (): void => { + const infringingExpression = 'assert.equal'; + const testDiff = [ + generateModifyFilesDiff('new-file.ts', 'foo', 'bar'), + generateModifyFilesDiff('old-file.js', undefined, 'pong'), + generateModifyFilesDiff( + 'test.js', + `yada yada ${infringingExpression} yada yada`, + undefined, + ), + ].join(''); + + const hasRulePassed = preventSinonAssertSyntax(testDiff); + + expect(hasRulePassed).toBe(false); + }); +}); diff --git a/development/fitness-functions/rules/sinon-assert-syntax.ts b/development/fitness-functions/rules/sinon-assert-syntax.ts new file mode 100644 index 000000000..57551f929 --- /dev/null +++ b/development/fitness-functions/rules/sinon-assert-syntax.ts @@ -0,0 +1,30 @@ +import { EXCLUDE_E2E_TESTS_REGEX } from '../common/constants'; +import { + filterDiffLineAdditions, + filterDiffByFilePath, + hasNumberOfCodeBlocksIncreased, +} from '../common/shared'; + +const codeBlocks = [ + "import { strict as assert } from 'assert';", + 'assert.deepEqual', + 'assert.equal', + 'assert.rejects', + 'assert.strictEqual', + 'sinon.', +]; + +function preventSinonAssertSyntax(diff: string): boolean { + const diffByFilePath = filterDiffByFilePath(diff, EXCLUDE_E2E_TESTS_REGEX); + const diffAdditions = filterDiffLineAdditions(diffByFilePath); + const hashmap = hasNumberOfCodeBlocksIncreased(diffAdditions, codeBlocks); + + const haveOccurencesOfAtLeastOneCodeBlockIncreased = + Object.values(hashmap).includes(true); + if (haveOccurencesOfAtLeastOneCodeBlockIncreased) { + return false; + } + return true; +} + +export { preventSinonAssertSyntax }; diff --git a/package.json b/package.json index fdcb71b9c..4ae6f6aac 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "test-storybook": "test-storybook -c .storybook", "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": "node development/fitness-functions/index.js", + "fitness-functions": "ts-node development/fitness-functions/index.ts", "generate-beta-commit": "node ./development/generate-beta-commit.js" }, "resolutions": { From 9ddbd9b4e7f08879859de4328f2b8cc01ca438c9 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Mon, 24 Apr 2023 10:47:32 -0500 Subject: [PATCH 11/60] Fix ICON_NAMES error for snaps settings (#18784) --- ui/pages/settings/settings.component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/pages/settings/settings.component.js b/ui/pages/settings/settings.component.js index 25a8d9dd1..b49dc5ff4 100644 --- a/ui/pages/settings/settings.component.js +++ b/ui/pages/settings/settings.component.js @@ -276,7 +276,7 @@ class SettingsPage extends PureComponent { { content: t('snaps'), icon: ( - + ), key: SNAPS_LIST_ROUTE, }, From 9fcbc554b0ae0cfc1454626a03b775f7b3c9f502 Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:22:57 +0530 Subject: [PATCH 12/60] Some linting issues in the file custom spending cap tooltip.js (#18687) Co-authored-by: George Marshall --- .../custom-spending-cap-tooltip.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js index ad5033a97..1c68eb297 100644 --- a/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js +++ b/ui/components/app/custom-spending-cap/custom-spending-cap-tooltip.js @@ -1,14 +1,14 @@ import React from 'react'; import PropTypes from 'prop-types'; import Box from '../../ui/box'; -import Typography from '../../ui/typography'; import Tooltip from '../../ui/tooltip'; import { TextColor, DISPLAY, - TypographyVariant, + TextVariant, } from '../../../helpers/constants/design-system'; -import { Icon, IconName, IconSize } from '../../component-library'; + +import { Icon, IconName, IconSize, Text } from '../../component-library'; export const CustomSpendingCapTooltip = ({ tooltipContentText, @@ -19,14 +19,15 @@ export const CustomSpendingCapTooltip = ({ interactive position="top" html={ - {tooltipContentText} - + } > {tooltipIcon ? ( From cd7cd45ec58c222fc1720797ed0e237c5f98bc95 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Mon, 24 Apr 2023 18:02:27 +0200 Subject: [PATCH 13/60] Only build LavaMoat runtime once (#18768) --- development/build/index.js | 110 +++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 53 deletions(-) diff --git a/development/build/index.js b/development/build/index.js index a82d9bbd3..6c667bc9d 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -73,61 +73,65 @@ async function defineAndRunBuildTasks() { version, } = await parseArgv(); - // scuttle on production/tests environment only - const shouldScuttle = ['dist', 'prod', 'test'].includes(entryTask); + const isRootTask = ['dist', 'prod', 'test', 'dev'].includes(entryTask); - console.log( - `Building lavamoat runtime file`, - `(scuttling is ${shouldScuttle ? 'on' : 'off'})`, - ); + if (isRootTask) { + // scuttle on production/tests environment only + const shouldScuttle = ['dist', 'prod', 'test'].includes(entryTask); - // build lavamoat runtime file - await lavapack.buildRuntime({ - scuttleGlobalThis: applyLavaMoat && shouldScuttle, - scuttleGlobalThisExceptions: [ - // globals used by different mm deps outside of lm compartment - 'toString', - 'getComputedStyle', - 'addEventListener', - 'removeEventListener', - 'ShadowRoot', - 'HTMLElement', - 'Element', - 'pageXOffset', - 'pageYOffset', - 'visualViewport', - 'Reflect', - 'Set', - 'Object', - 'navigator', - 'harden', - 'console', - 'Image', // Used by browser to generate notifications - // globals chrome driver needs to function (test env) - /cdc_[a-zA-Z0-9]+_[a-zA-Z]+/iu, - 'performance', - 'parseFloat', - 'innerWidth', - 'innerHeight', - 'Symbol', - 'Math', - 'DOMRect', - 'Number', - 'Array', - 'crypto', - 'Function', - 'Uint8Array', - 'String', - 'Promise', - // globals sentry needs to function - '__SENTRY__', - 'appState', - 'extra', - 'stateHooks', - 'sentryHooks', - 'sentry', - ], - }); + console.log( + `Building lavamoat runtime file`, + `(scuttling is ${shouldScuttle ? 'on' : 'off'})`, + ); + + // build lavamoat runtime file + await lavapack.buildRuntime({ + scuttleGlobalThis: applyLavaMoat && shouldScuttle, + scuttleGlobalThisExceptions: [ + // globals used by different mm deps outside of lm compartment + 'toString', + 'getComputedStyle', + 'addEventListener', + 'removeEventListener', + 'ShadowRoot', + 'HTMLElement', + 'Element', + 'pageXOffset', + 'pageYOffset', + 'visualViewport', + 'Reflect', + 'Set', + 'Object', + 'navigator', + 'harden', + 'console', + 'Image', // Used by browser to generate notifications + // globals chrome driver needs to function (test env) + /cdc_[a-zA-Z0-9]+_[a-zA-Z]+/iu, + 'performance', + 'parseFloat', + 'innerWidth', + 'innerHeight', + 'Symbol', + 'Math', + 'DOMRect', + 'Number', + 'Array', + 'crypto', + 'Function', + 'Uint8Array', + 'String', + 'Promise', + // globals sentry needs to function + '__SENTRY__', + 'appState', + 'extra', + 'stateHooks', + 'sentryHooks', + 'sentry', + ], + }); + } const browserPlatforms = ['firefox', 'chrome']; From 6f2a5faaea3ee8ffecdc8132e36c934c1ef13767 Mon Sep 17 00:00:00 2001 From: David Drazic Date: Mon, 24 Apr 2023 18:37:12 +0200 Subject: [PATCH 14/60] Fix missing icon for webassembly endowment (#18781) --- ui/helpers/utils/permission.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index 7289dedb0..d102b1966 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -312,7 +312,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ [EndowmentPermissions['endowment:webassembly']]: ({ t }) => ({ label: t('permission_webAssembly'), description: t('permission_webAssemblyDescription'), - leftIcon: 'fas fa-microchip', + leftIcon: ICON_NAMES.DOCUMENT_CODE, rightIcon: null, weight: 2, }), From e65b955b19d95b9752b5b9b911f2466c728c43e0 Mon Sep 17 00:00:00 2001 From: Thomas Huang Date: Mon, 24 Apr 2023 09:55:32 -0700 Subject: [PATCH 15/60] Unit tests for various modals (#18115) * Unit tests for Hide Token Confirmation modal * Unit test for Export Private Key modal * Unit test for Customize Nonce modal * Bump coverage targets --------- Co-authored-by: Brad Decker --- .../customize-nonce.test.js.snap | 119 ++++++++++++++++ .../customize-nonce.component.js | 2 + .../customize-nonce/customize-nonce.test.js | 132 ++++++++++++++++++ .../export-private-key-modal.test.js.snap | 120 ++++++++++++++++ .../export-private-key-modal.component.js | 1 + .../export-private-key-modal.test.js | 81 +++++++++++ ...hide-token-confirmation-modal.test.js.snap | 93 ++++++++++++ .../hide-token-confirmation-modal.test.js | 84 +++++++++++ 8 files changed, 632 insertions(+) create mode 100644 ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap create mode 100644 ui/components/app/modals/customize-nonce/customize-nonce.test.js create mode 100644 ui/components/app/modals/export-private-key-modal/__snapshots__/export-private-key-modal.test.js.snap create mode 100644 ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js create mode 100644 ui/components/app/modals/hide-token-confirmation-modal/__snapshots__/hide-token-confirmation-modal.test.js.snap create mode 100644 ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.test.js diff --git a/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap new file mode 100644 index 000000000..753646819 --- /dev/null +++ b/ui/components/app/modals/customize-nonce/__snapshots__/customize-nonce.test.js.snap @@ -0,0 +1,119 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Customize Nonce should match snapshot 1`] = ` +

+ +
+`; diff --git a/ui/components/app/modals/customize-nonce/customize-nonce.component.js b/ui/components/app/modals/customize-nonce/customize-nonce.component.js index 58d3ab79a..8653cc0ab 100644 --- a/ui/components/app/modals/customize-nonce/customize-nonce.component.js +++ b/ui/components/app/modals/customize-nonce/customize-nonce.component.js @@ -99,6 +99,7 @@ const CustomizeNonce = ({ + +
+
+
+
+`; diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js index 81e0dfc4c..b50c3de85 100644 --- a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js @@ -98,6 +98,7 @@ export default class ExportPrivateKeyModal extends Component { this.setState({ password: event.target.value })} /> ); diff --git a/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js new file mode 100644 index 000000000..bc5e38df2 --- /dev/null +++ b/ui/components/app/modals/export-private-key-modal/export-private-key-modal.test.js @@ -0,0 +1,81 @@ +import React from 'react'; +import { fireEvent } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; +import * as actions from '../../../../store/actions'; +import ExportPrivateKeyModal from '.'; + +jest.mock('../../../../store/actions.ts', () => ({ + ...jest.requireActual('../../../../store/actions.ts'), + exportAccount: jest.fn().mockReturnValue(jest.fn().mockResolvedValueOnce()), + hideWarning: () => jest.fn(), + showModal: () => jest.fn(), + hideModal: () => jest.fn(), + clearAccountDetails: () => jest.fn(), +})); + +describe('Export PrivateKey Modal', () => { + const password = 'a-password'; + + const privKeyModalState = { + ...mockState, + appState: { + ...mockState.appState, + accountDetail: { + privateKey: '0xPrivKey', + }, + }, + }; + const mockStore = configureMockStore([thunk])(privKeyModalState); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + mockStore, + ); + expect(container).toMatchSnapshot(); + }); + + it('should disable confirm button by default', () => { + const { queryByText } = renderWithProvider( + , + mockStore, + ); + + const confirmButton = queryByText('Confirm'); + + expect(confirmButton).toBeDisabled(); + }); + + it('should call export account with password and selected address', () => { + const { queryByTestId, queryByText } = renderWithProvider( + , + mockStore, + ); + + const passwordInput = queryByTestId('password-input'); + + const passwordInputEvent = { + target: { + value: password, + }, + }; + + fireEvent.change(passwordInput, passwordInputEvent); + + const confirmButton = queryByText('Confirm'); + + fireEvent.click(confirmButton); + + expect(actions.exportAccount).toHaveBeenCalledWith( + password, + mockState.metamask.selectedAddress, + ); + }); +}); diff --git a/ui/components/app/modals/hide-token-confirmation-modal/__snapshots__/hide-token-confirmation-modal.test.js.snap b/ui/components/app/modals/hide-token-confirmation-modal/__snapshots__/hide-token-confirmation-modal.test.js.snap new file mode 100644 index 000000000..e12bbb688 --- /dev/null +++ b/ui/components/app/modals/hide-token-confirmation-modal/__snapshots__/hide-token-confirmation-modal.test.js.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Hide Token Confirmation Modal should match snapshot 1`] = ` +
+
+
+
+ Hide token? +
+
+
+
+ + + + + +
+
+
+
+ TKN +
+
+ You can add this token back in the future by going to “Import token” in your accounts options menu. +
+
+ + +
+
+
+
+`; diff --git a/ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.test.js b/ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.test.js new file mode 100644 index 000000000..6a53c80a3 --- /dev/null +++ b/ui/components/app/modals/hide-token-confirmation-modal/hide-token-confirmation-modal.test.js @@ -0,0 +1,84 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import { fireEvent } from '@testing-library/react'; +import thunk from 'redux-thunk'; +import * as actions from '../../../../store/actions'; +import { renderWithProvider } from '../../../../../test/lib/render-helpers'; +import mockState from '../../../../../test/data/mock-state.json'; +import HideTokenConfirmationModal from '.'; + +const mockHistoryPush = jest.fn(); +const mockHideModal = jest.fn(); +const mockHideToken = jest.fn().mockResolvedValue(); + +jest.mock('../../../../store/actions.ts', () => ({ + ...jest.requireActual('../../../../store/actions.ts'), + hideModal: () => mockHideModal, + hideToken: () => mockHideToken, + ignoreTokens: jest.fn().mockReturnValue(jest.fn().mockResolvedValue()), +})); + +describe('Hide Token Confirmation Modal', () => { + const tokenState = { + address: '0xTokenAddress', + symbol: 'TKN', + image: '', + }; + + const tokenModalState = { + ...mockState, + appState: { + ...mockState.appState, + modal: { + modalState: { + props: { + history: { + push: mockHistoryPush, + }, + token: tokenState, + }, + }, + }, + }, + }; + + const mockStore = configureMockStore([thunk])(tokenModalState); + + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + mockStore, + ); + + expect(container).toMatchSnapshot(); + }); + + it('should hide modal', () => { + const { queryByTestId } = renderWithProvider( + , + mockStore, + ); + + const cancelButton = queryByTestId('hide-token-confirmation__cancel'); + + fireEvent.click(cancelButton); + + expect(mockHideModal).toHaveBeenCalled(); + }); + + it('should hide token with token address from state', () => { + const { queryByTestId } = renderWithProvider( + , + mockStore, + ); + + const hideButton = queryByTestId('hide-token-confirmation__hide'); + + fireEvent.click(hideButton); + + expect(mockHideModal).toHaveBeenCalled(); + expect(actions.ignoreTokens).toHaveBeenCalledWith({ + tokensToIgnore: tokenState.address, + }); + }); +}); From 85bc0460e3f55d040a32f726dc42cf4827fc32b6 Mon Sep 17 00:00:00 2001 From: Brad Decker Date: Mon, 24 Apr 2023 17:03:37 -0500 Subject: [PATCH 16/60] Revert "Shallow git clone (#18491)" (#18788) This reverts commit b704a3d60f407eac99a7dc3f8a65529eff812203. --- .circleci/config.yml | 104 ++++++++++++++++++------------------------- 1 file changed, 43 insertions(+), 61 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d50ac8747..68a1c199a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,24 +24,6 @@ rc_branch_only: &rc_branch_only only: - /^Version-v(\d+)[.](\d+)[.](\d+)/ -aliases: - # Shallow Git Clone - - &shallow-git-clone - name: Shallow Git Clone - command: | - #!/bin/bash - set -e - set -u - set -o pipefail - - # Set up SSH access - # This SSH key is the current github.com SSH key as of April 2023, but it will need to be changed whenever github changes their key (probably every few years) - GITHUB_SSH_KEY="AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl" - mkdir -p ~/.ssh - echo github.com ssh-ed25519 $GITHUB_SSH_KEY >> ~/.ssh/known_hosts - - git clone --depth 1 "$CIRCLE_REPOSITORY_URL" --branch "$CIRCLE_BRANCH" . - workflows: test_and_release: jobs: @@ -252,7 +234,7 @@ jobs: trigger-beta-build: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - when: @@ -281,7 +263,7 @@ jobs: create_release_pull_request: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -300,7 +282,7 @@ jobs: prep-deps: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - restore_cache: keys: # First try to get the specific cache for the checksum of the yarn.lock file. @@ -350,7 +332,7 @@ jobs: validate-lavamoat-config: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -365,7 +347,7 @@ jobs: prep-build: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - when: @@ -399,7 +381,7 @@ jobs: prep-build-desktop: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -423,7 +405,7 @@ jobs: prep-build-flask: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - when: @@ -463,7 +445,7 @@ jobs: prep-build-test-flask: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -484,7 +466,7 @@ jobs: prep-build-test-mv3: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -505,7 +487,7 @@ jobs: prep-build-test: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -526,7 +508,7 @@ jobs: prep-build-storybook: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -540,7 +522,7 @@ jobs: prep-build-ts-migration-dashboard: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -554,7 +536,7 @@ jobs: test-yarn-dedupe: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -564,7 +546,7 @@ jobs: test-lint: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -577,7 +559,7 @@ jobs: test-storybook: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -599,7 +581,7 @@ jobs: test-lint-lockfile: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -609,7 +591,7 @@ jobs: test-lint-changelog: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - when: @@ -635,7 +617,7 @@ jobs: test-deps-audit: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -645,7 +627,7 @@ jobs: test-deps-depcheck: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -656,7 +638,7 @@ jobs: executor: node-browsers parallelism: 8 steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -693,7 +675,7 @@ jobs: executor: node-browsers parallelism: 8 steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -721,7 +703,7 @@ jobs: executor: node-browsers parallelism: 4 steps: - - run: *shallow-git-clone + - checkout - run: name: Install Firefox command: ./.circleci/scripts/firefox-install.sh @@ -758,7 +740,7 @@ jobs: executor: node-browsers parallelism: 4 steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -795,7 +777,7 @@ jobs: executor: node-browsers-medium-plus parallelism: 8 steps: - - run: *shallow-git-clone + - checkout - run: name: Install Firefox command: ./.circleci/scripts/firefox-install.sh @@ -831,7 +813,7 @@ jobs: benchmark: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -857,7 +839,7 @@ jobs: user-actions-benchmark: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -883,7 +865,7 @@ jobs: stats-module-load-init: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - run: name: Re-Install Chrome command: ./.circleci/scripts/chrome-install.sh @@ -980,7 +962,7 @@ jobs: job-publish-release: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1000,7 +982,7 @@ jobs: - add_ssh_keys: fingerprints: - '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8' - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1015,7 +997,7 @@ jobs: - add_ssh_keys: fingerprints: - '8b:21:e3:20:7c:c9:db:82:74:2d:86:d6:11:a7:2f:49' - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1029,7 +1011,7 @@ jobs: test-unit-mocha: executor: node-browsers-medium-plus steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1044,7 +1026,7 @@ jobs: test-unit-jest-development: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1061,7 +1043,7 @@ jobs: executor: node-browsers-medium-plus parallelism: 12 steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1077,7 +1059,7 @@ jobs: upload-and-validate-coverage: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - codecov/upload @@ -1092,7 +1074,7 @@ jobs: test-unit-global: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1102,7 +1084,7 @@ jobs: validate-source-maps: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1112,7 +1094,7 @@ jobs: validate-source-maps-beta: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1123,7 +1105,7 @@ jobs: validate-source-maps-desktop: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1139,7 +1121,7 @@ jobs: validate-source-maps-flask: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1155,7 +1137,7 @@ jobs: test-mozilla-lint: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1165,7 +1147,7 @@ jobs: test-mozilla-lint-beta: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1176,7 +1158,7 @@ jobs: test-mozilla-lint-desktop: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: @@ -1192,7 +1174,7 @@ jobs: test-mozilla-lint-flask: executor: node-browsers steps: - - run: *shallow-git-clone + - checkout - attach_workspace: at: . - run: From a827c444fbc8998ff46b86075f829477d8f900c7 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 25 Apr 2023 08:09:22 +0000 Subject: [PATCH 17/60] devDeps: security updates roundup (#18739) * devDeps: resolutions: git-url-parse@^12=>13.1.0 - CVE-2022-2900 / GHSA-j9fq-vwqv-2fm2 Depended on from now abandoned @storybook/storybook-deployer - https://github.com/storybook-eol/storybook-deployer/pull/131 - https://github.com/IonicaBizau/git-url-parse/releases/tag/13.0.0 - https://github.com/IonicaBizau/git-up/releases/tag/7.0.0 * devDeps: source-map-explorer@2.4.2->2.5.3 * devDeps: bump terser dependencies - CVE-2022-25858 / GHSA-4wf5-vphf-c2xc * devDeps: shelljs@0.8.4->0.8.5 - CVE-2022-0144 / GHSA-4rq4-32rv-6wp6 * devDeps: serve-handler@6.1.3->6.1.5, minimatch@3.0.4->3.1.2 - CVE-2022-3517 / GHSA-f8q6-p94x-37v3 * devDeps: bump x-default-browser-id in resolutions - CVE-2021-33623 / CVE-2021-33623 - https://npm-diff.app/x-default-browser@0.4.0...x-default-browser@0.5.2 * devDeps: pin glob-parent@^6.0.2 in resolutions - CVE-2020-28469 / GHSA-ww39-953v-wcq6 --- lavamoat/build-system/policy.json | 65 +---- package.json | 3 + yarn.lock | 403 +++++++++--------------------- 3 files changed, 136 insertions(+), 335 deletions(-) diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 11a78a286..efbd0f05a 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1926,10 +1926,10 @@ "packages": { "chokidar>braces": true, "chokidar>fsevents": true, - "chokidar>glob-parent": true, "chokidar>is-binary-path": true, "chokidar>normalize-path": true, "depcheck>readdirp": true, + "eslint>glob-parent": true, "eslint>is-glob": true, "watchify>anymatch": true } @@ -1959,15 +1959,6 @@ }, "native": true }, - "chokidar>glob-parent": { - "builtin": { - "os.platform": true, - "path.posix.dirname": true - }, - "packages": { - "eslint>is-glob": true - } - }, "chokidar>is-binary-path": { "builtin": { "path.extname": true @@ -3074,9 +3065,9 @@ "process.cwd": true }, "packages": { + "eslint>glob-parent": true, "fast-glob>@nodelib/fs.stat": true, "fast-glob>@nodelib/fs.walk": true, - "fast-glob>glob-parent": true, "globby>merge2": true, "stylelint>micromatch": true } @@ -3131,15 +3122,6 @@ "fast-glob>@nodelib/fs.walk>fastq>reusify": true } }, - "fast-glob>glob-parent": { - "builtin": { - "os.platform": true, - "path.posix.dirname": true - }, - "packages": { - "eslint>is-glob": true - } - }, "fs-extra": { "builtin": { "assert": true, @@ -4073,11 +4055,11 @@ "setTimeout": true }, "packages": { + "eslint>glob-parent": true, "gulp-watch>ansi-colors": true, "gulp-watch>anymatch": true, "gulp-watch>chokidar": true, "gulp-watch>fancy-log": true, - "gulp-watch>glob-parent": true, "gulp-watch>path-is-absolute": true, "gulp-watch>slash": true, "gulp-watch>vinyl-file": true, @@ -4221,15 +4203,7 @@ "path.dirname": true }, "packages": { - "gulp-watch>anymatch>micromatch>parse-glob>glob-base>glob-parent": true, - "gulp-watch>anymatch>micromatch>parse-glob>glob-base>is-glob": true - } - }, - "gulp-watch>anymatch>micromatch>parse-glob>glob-base>glob-parent": { - "builtin": { - "path.dirname": true - }, - "packages": { + "eslint>glob-parent": true, "gulp-watch>anymatch>micromatch>parse-glob>glob-base>is-glob": true } }, @@ -4282,6 +4256,7 @@ }, "packages": { "chokidar>normalize-path": true, + "eslint>glob-parent": true, "eslint>is-glob": true, "gulp-watch>chokidar>anymatch": true, "gulp-watch>chokidar>async-each": true, @@ -4885,30 +4860,6 @@ "fancy-log>time-stamp": true } }, - "gulp-watch>glob-parent": { - "builtin": { - "os.platform": true, - "path": true - }, - "packages": { - "gulp-watch>glob-parent>is-glob": true, - "gulp-watch>glob-parent>path-dirname": true - } - }, - "gulp-watch>glob-parent>is-glob": { - "packages": { - "gulp-watch>glob-parent>is-glob>is-extglob": true - } - }, - "gulp-watch>glob-parent>path-dirname": { - "builtin": { - "path": true, - "util.inspect": true - }, - "globals": { - "process.platform": true - } - }, "gulp-watch>path-is-absolute": { "globals": { "process.platform": true @@ -5206,9 +5157,9 @@ }, "packages": { "chokidar>normalize-path": true, + "eslint>glob-parent": true, "eslint>is-glob": true, "gulp-watch>chokidar>async-each": true, - "gulp-watch>glob-parent": true, "gulp-watch>path-is-absolute": true, "gulp>glob-watcher>anymatch": true, "gulp>glob-watcher>chokidar>braces": true, @@ -5652,7 +5603,7 @@ "process.nextTick": true }, "packages": { - "gulp-watch>glob-parent": true, + "eslint>glob-parent": true, "gulp>glob-watcher>is-negated-glob": true, "gulp>vinyl-fs>glob-stream>ordered-read-streams": true, "gulp>vinyl-fs>glob-stream>pumpify": true, @@ -7610,7 +7561,7 @@ }, "terser": { "globals": { - "Buffer.from": true, + "Buffer": true, "atob": true, "btoa": true, "console.log": true, diff --git a/package.json b/package.json index 4ae6f6aac..b7f0f3568 100644 --- a/package.json +++ b/package.json @@ -97,9 +97,12 @@ "resolutions": { "analytics-node/axios": "^0.21.2", "ganache-core/lodash": "^4.17.21", + "git-url-parse@^12.0.0": "^13.1.0", + "glob-parent": "^6.0.2", "netmask": "^2.0.1", "json-schema": "^0.4.0", "ast-types": "^0.14.2", + "x-default-browser": "^0.5.2", "web3-provider-engine/eth-json-rpc-filters": "^6.0.0", "typescript@~4.4.0": "patch:typescript@npm:4.4.4#.yarn/patches/typescript-npm-4.4.4-3fedcc07a3.patch", "acorn@^7.0.0": "patch:acorn@npm:7.4.1#.yarn/patches/acorn-npm-7.4.1-f450b4646c.patch", diff --git a/yarn.lock b/yarn.lock index b5582b8de..e69767e1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3276,13 +3276,13 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.13, @jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.17 - resolution: "@jridgewell/trace-mapping@npm:0.3.17" +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.13, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.18 + resolution: "@jridgewell/trace-mapping@npm:0.3.18" dependencies: "@jridgewell/resolve-uri": 3.1.0 "@jridgewell/sourcemap-codec": 1.4.14 - checksum: 9d703b859cff5cd83b7308fd457a431387db5db96bd781a63bf48e183418dd9d3d44e76b9e4ae13237f6abeeb25d739ec9215c1d5bfdd08f66f750a50074a339 + checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 languageName: node linkType: hard @@ -9540,13 +9540,6 @@ __metadata: languageName: node linkType: hard -"array-find-index@npm:^1.0.1": - version: 1.0.2 - resolution: "array-find-index@npm:1.0.2" - checksum: aac128bf369e1ac6c06ff0bb330788371c0e256f71279fb92d745e26fb4b9db8920e485b4ec25e841c93146bf71a34dcdbcefa115e7e0f96927a214d237b7081 - languageName: node - linkType: hard - "array-flatten@npm:1.1.1": version: 1.1.1 resolution: "array-flatten@npm:1.1.1" @@ -9837,13 +9830,6 @@ __metadata: languageName: node linkType: hard -"async@npm:0.9.x": - version: 0.9.2 - resolution: "async@npm:0.9.2" - checksum: 87dbf129292b8a6c32a4e07f43f462498162aa86f404a7e11f978dbfdf75cfb163c26833684bb07b9d436083cd604cbbf730a57bfcbe436c6ae1ed266cdc56bb - languageName: node - linkType: hard - "async@npm:^1.4.2": version: 1.5.2 resolution: "async@npm:1.5.2" @@ -9860,6 +9846,13 @@ __metadata: languageName: node linkType: hard +"async@npm:^3.2.3": + version: 3.2.4 + resolution: "async@npm:3.2.4" + checksum: 43d07459a4e1d09b84a20772414aa684ff4de085cbcaec6eea3c7a8f8150e8c62aa6cd4e699fe8ee93c3a5b324e777d34642531875a0817a35697522c1b02e89 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -11566,16 +11559,6 @@ __metadata: languageName: node linkType: hard -"camelcase-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "camelcase-keys@npm:2.1.0" - dependencies: - camelcase: ^2.0.0 - map-obj: ^1.0.0 - checksum: 97d2993da5db44d45e285910c70a54ce7f83a2be05afceaafd9831f7aeaf38a48dcdede5ca3aae2b2694852281d38dc459706e346942c5df0bf755f4133f5c39 - languageName: node - linkType: hard - "camelcase-keys@npm:^6.2.2": version: 6.2.2 resolution: "camelcase-keys@npm:6.2.2" @@ -11594,13 +11577,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^2.0.0": - version: 2.1.1 - resolution: "camelcase@npm:2.1.1" - checksum: 20a3ef08f348de832631d605362ffe447d883ada89617144a82649363ed5860923b021f8e09681624ef774afb93ff3597cfbcf8aaf0574f65af7648f1aea5e50 - languageName: node - linkType: hard - "camelcase@npm:^3.0.0": version: 3.0.0 resolution: "camelcase@npm:3.0.0" @@ -11616,9 +11592,9 @@ __metadata: linkType: hard "camelcase@npm:^6.0.0, camelcase@npm:^6.2.0": - version: 6.2.0 - resolution: "camelcase@npm:6.2.0" - checksum: 8335cfd0ecc472eae685896a42afd8c9dacd193a91f569120b931c87deb053a1ba82102031b9b48a4dbc1d18066caeacf2e4ace8c3c7f0d02936d348dc0b5a87 + version: 6.3.0 + resolution: "camelcase@npm:6.3.0" + checksum: 8c96818a9076434998511251dcb2761a94817ea17dbdc37f47ac080bd088fc62c7369429a19e2178b993497132c8cbcf5cc1f44ba963e76782ba469c0474938d languageName: node linkType: hard @@ -11741,7 +11717,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.1.0, chalk@npm:^4.1.1": +"chalk@npm:4.1.2, chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -13366,15 +13342,6 @@ __metadata: languageName: node linkType: hard -"currently-unhandled@npm:^0.4.1": - version: 0.4.1 - resolution: "currently-unhandled@npm:0.4.1" - dependencies: - array-find-index: ^1.0.1 - checksum: 1f59fe10b5339b54b1a1eee110022f663f3495cf7cf2f480686e89edc7fa8bfe42dbab4b54f85034bc8b092a76cc7becbc2dad4f9adad332ab5831bec39ad540 - languageName: node - linkType: hard - "cwd@npm:^0.10.0": version: 0.10.0 resolution: "cwd@npm:0.10.0" @@ -13555,7 +13522,7 @@ __metadata: languageName: node linkType: hard -"decamelize@npm:^1.1.0, decamelize@npm:^1.1.1, decamelize@npm:^1.1.2, decamelize@npm:^1.2.0": +"decamelize@npm:^1.1.0, decamelize@npm:^1.1.1, decamelize@npm:^1.2.0": version: 1.2.0 resolution: "decamelize@npm:1.2.0" checksum: ad8c51a7e7e0720c70ec2eeb1163b66da03e7616d7b98c9ef43cce2416395e84c1e9548dd94f5f6ffecfee9f8b94251fc57121a8b021f2ff2469b2bae247b8aa @@ -13657,16 +13624,14 @@ __metadata: languageName: node linkType: hard -"default-browser-id@npm:^1.0.4": - version: 1.0.4 - resolution: "default-browser-id@npm:1.0.4" +"default-browser-id@npm:^2.0.0": + version: 2.0.0 + resolution: "default-browser-id@npm:2.0.0" dependencies: bplist-parser: ^0.1.0 - meow: ^3.1.0 + pify: ^2.3.0 untildify: ^2.0.0 - bin: - default-browser-id: cli.js - checksum: c6576428ebdd304d209e09c40803c974de3236232fdfa564d82bd1e985246a0d0f0b344f2b207fcbf663b925c20d30ab4d77fbe2755d2be3a6073f12620b9056 + checksum: c0de7b2c4dcc0a6e7df7c407b716f56ac8164941dd066b4bac4b653c49a84373f26d088ddd78b69eafbe0e33a786596ce6885ab8776bef629aabe5a6f984acdb languageName: node linkType: hard @@ -14460,10 +14425,10 @@ __metadata: languageName: node linkType: hard -"duplexer@npm:^0.1.1, duplexer@npm:~0.1.1": - version: 0.1.1 - resolution: "duplexer@npm:0.1.1" - checksum: fc7937c4a43808493cd63dfa59f4deb6cf02beea783cb17f39677b53ccacb9fba48f87731b8944048dd6dfa8f456d0725f86f3fd587ab780532d9a8e2914e8b7 +"duplexer@npm:^0.1.1, duplexer@npm:^0.1.2, duplexer@npm:~0.1.1": + version: 0.1.2 + resolution: "duplexer@npm:0.1.2" + checksum: 62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 languageName: node linkType: hard @@ -14529,14 +14494,14 @@ __metadata: languageName: node linkType: hard -"ejs@npm:^3.0.2": - version: 3.1.5 - resolution: "ejs@npm:3.1.5" +"ejs@npm:^3.1.5": + version: 3.1.9 + resolution: "ejs@npm:3.1.9" dependencies: - jake: ^10.6.1 + jake: ^10.8.5 bin: - ejs: ./bin/cli.js - checksum: c735d1ffb9560e6427a64a26d26fbccbeefa733417be6c1ee9944b75242ef9ab0b23e382afe203786d099e8ccb4b901539b256b630665a6920e913def340bf5c + ejs: bin/cli.js + checksum: af6f10eb815885ff8a8cfacc42c6b6cf87daf97a4884f87a30e0c3271fedd85d76a3a297d9c33a70e735b97ee632887f85e32854b9cdd3a2d97edf931519a35f languageName: node linkType: hard @@ -17842,13 +17807,6 @@ __metadata: languageName: node linkType: hard -"get-stdin@npm:^4.0.1": - version: 4.0.1 - resolution: "get-stdin@npm:4.0.1" - checksum: 4f73d3fe0516bc1f3dc7764466a68ad7c2ba809397a02f56c2a598120e028430fcff137a648a01876b2adfb486b4bc164119f98f1f7d7c0abd63385bdaa0113f - languageName: node - linkType: hard - "get-stdin@npm:^8.0.0": version: 8.0.0 resolution: "get-stdin@npm:8.0.0" @@ -17946,22 +17904,22 @@ __metadata: languageName: node linkType: hard -"git-up@npm:^6.0.0": - version: 6.0.0 - resolution: "git-up@npm:6.0.0" +"git-up@npm:^7.0.0": + version: 7.0.0 + resolution: "git-up@npm:7.0.0" dependencies: is-ssh: ^1.4.0 - parse-url: ^7.0.2 - checksum: 145a1f546d7a078cdfc2616556e518e634d134e34a31c6bf2ed89e44158659cb525dbd451c338121f7107f55cef066d0b37a7bbf178555befc9304b3940b435e + parse-url: ^8.1.0 + checksum: 2faadbab51e94d2ffb220e426e950087cc02c15d664e673bd5d1f734cfa8196fed8b19493f7bf28fe216d087d10e22a7fd9b63687e0ba7d24f0ddcfb0a266d6e languageName: node linkType: hard -"git-url-parse@npm:^12.0.0": - version: 12.0.0 - resolution: "git-url-parse@npm:12.0.0" +"git-url-parse@npm:^13.1.0": + version: 13.1.0 + resolution: "git-url-parse@npm:13.1.0" dependencies: - git-up: ^6.0.0 - checksum: b4c8530b816202ecf9d4dabf755f785a314a096b56145018385b3d7171e862f9d0d9b38cce620c0af354b269750fe7b2d9aa95815c7150922090a11dac4ab1e6 + git-up: ^7.0.0 + checksum: 212a9b0343e9199998b6a532efe2014476a7a1283af393663ca49ac28d4768929aad16d3322e2685236065ee394dbc93e7aa63a48956531e984c56d8b5edb54d languageName: node linkType: hard @@ -17996,35 +17954,7 @@ __metadata: languageName: node linkType: hard -"glob-parent@npm:^2.0.0": - version: 2.0.0 - resolution: "glob-parent@npm:2.0.0" - dependencies: - is-glob: ^2.0.0 - checksum: 734fc461d9d2753dd490dd072df6ce41fe4ebb60e9319b108bc538707b21780af3a61c3961ec2264131fad5d3d9a493e013a775aef11a69ac2f49fd7d8f46457 - languageName: node - linkType: hard - -"glob-parent@npm:^3.0.1, glob-parent@npm:^3.1.0": - version: 3.1.0 - resolution: "glob-parent@npm:3.1.0" - dependencies: - is-glob: ^3.1.0 - path-dirname: ^1.0.0 - checksum: 653d559237e89a11b9934bef3f392ec42335602034c928590544d383ff5ef449f7b12f3cfa539708e74bc0a6c28ab1fe51d663cc07463cdf899ba92afd85a855 - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.1, glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: ^4.0.1 - checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.1": +"glob-parent@npm:^6.0.2": version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: @@ -18716,13 +18646,12 @@ __metadata: languageName: node linkType: hard -"gzip-size@npm:^5.1.1": - version: 5.1.1 - resolution: "gzip-size@npm:5.1.1" +"gzip-size@npm:^6.0.0": + version: 6.0.0 + resolution: "gzip-size@npm:6.0.0" dependencies: - duplexer: ^0.1.1 - pify: ^4.0.1 - checksum: 6451ba2210877368f6d9ee9b4dc0d14501671472801323bf81fbd38bdeb8525f40a78be45a59d0182895d51e6b60c6314b7d02bd6ed40e7225a01e8d038aac1b + duplexer: ^0.1.2 + checksum: 2df97f359696ad154fc171dcb55bc883fe6e833bca7a65e457b9358f3cb6312405ed70a8da24a77c1baac0639906cd52358dc0ce2ec1a937eaa631b934c94194 languageName: node linkType: hard @@ -19641,15 +19570,6 @@ __metadata: languageName: node linkType: hard -"indent-string@npm:^2.1.0": - version: 2.1.0 - resolution: "indent-string@npm:2.1.0" - dependencies: - repeating: ^2.0.0 - checksum: 2fe7124311435f4d7a98f0a314d8259a4ec47ecb221110a58e2e2073e5f75c8d2b4f775f2ed199598fbe20638917e57423096539455ca8bff8eab113c9bee12c - languageName: node - linkType: hard - "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" @@ -20146,13 +20066,6 @@ __metadata: languageName: node linkType: hard -"is-finite@npm:^1.0.0": - version: 1.1.0 - resolution: "is-finite@npm:1.1.0" - checksum: 532b97ed3d03e04c6bd203984d9e4ba3c0c390efee492bad5d1d1cd1802a68ab27adbd3ef6382f6312bed6c8bb1bd3e325ea79a8dc8fe080ed7a06f5f97b93e7 - languageName: node - linkType: hard - "is-fn@npm:^1.0.0": version: 1.0.0 resolution: "is-fn@npm:1.0.0" @@ -20937,17 +20850,17 @@ __metadata: languageName: node linkType: hard -"jake@npm:^10.6.1": - version: 10.8.2 - resolution: "jake@npm:10.8.2" +"jake@npm:^10.8.5": + version: 10.8.5 + resolution: "jake@npm:10.8.5" dependencies: - async: 0.9.x - chalk: ^2.4.2 + async: ^3.2.3 + chalk: ^4.0.2 filelist: ^1.0.1 minimatch: ^3.0.4 bin: jake: ./bin/cli.js - checksum: b604c51863260e374ccd62cd0cfe0b659f72cb71beb7d5fb5137dd65b04cf9d5603abd01f9f6eaaac8f4182f396d6cfae01e0b0844c2215c9c1e200572307cf9 + checksum: 56c913ecf5a8d74325d0af9bc17a233bad50977438d44864d925bb6c45c946e0fee8c4c1f5fe2225471ef40df5222e943047982717ebff0d624770564d3c46ba languageName: node linkType: hard @@ -23461,16 +23374,6 @@ __metadata: languageName: node linkType: hard -"loud-rejection@npm:^1.0.0": - version: 1.6.0 - resolution: "loud-rejection@npm:1.6.0" - dependencies: - currently-unhandled: ^0.4.1 - signal-exit: ^3.0.0 - checksum: 750e12defde34e8cbf263c2bff16f028a89b56e022ad6b368aa7c39495b5ac33f2349a8d00665a9b6d25c030b376396524d8a31eb0dde98aaa97956d7324f927 - languageName: node - linkType: hard - "lower-case-first@npm:^1.0.0": version: 1.0.2 resolution: "lower-case-first@npm:1.0.2" @@ -23728,7 +23631,7 @@ __metadata: languageName: node linkType: hard -"map-obj@npm:^1.0.0, map-obj@npm:^1.0.1": +"map-obj@npm:^1.0.0": version: 1.0.1 resolution: "map-obj@npm:1.0.1" checksum: 9949e7baec2a336e63b8d4dc71018c117c3ce6e39d2451ccbfd3b8350c547c4f6af331a4cbe1c83193d7c6b786082b6256bde843db90cb7da2a21e8fcc28afed @@ -24030,42 +23933,22 @@ __metadata: languageName: node linkType: hard -"meow@npm:^3.1.0": - version: 3.7.0 - resolution: "meow@npm:3.7.0" - dependencies: - camelcase-keys: ^2.0.0 - decamelize: ^1.1.2 - loud-rejection: ^1.0.0 - map-obj: ^1.0.1 - minimist: ^1.1.3 - normalize-package-data: ^2.3.4 - object-assign: ^4.0.1 - read-pkg-up: ^1.0.1 - redent: ^1.0.0 - trim-newlines: ^1.0.0 - checksum: 65a412e5d0d643615508007a9292799bb3e4e690597d54c9e98eb0ca3adb7b8ca8899f41ea7cb7d8277129cdcd9a1a60202b31f88e0034e6aaae02894d80999a - languageName: node - linkType: hard - "meow@npm:^7.0.1": - version: 7.0.1 - resolution: "meow@npm:7.0.1" + version: 7.1.1 + resolution: "meow@npm:7.1.1" dependencies: "@types/minimist": ^1.2.0 - arrify: ^2.0.1 - camelcase: ^6.0.0 camelcase-keys: ^6.2.2 decamelize-keys: ^1.1.0 hard-rejection: ^2.1.0 - minimist-options: ^4.0.2 + minimist-options: 4.1.0 normalize-package-data: ^2.5.0 read-pkg-up: ^7.0.1 redent: ^3.0.0 trim-newlines: ^3.0.0 type-fest: ^0.13.1 yargs-parser: ^18.1.3 - checksum: 7edd097f0e3d5b746a50a39777c9a833dbc1f9fcbec84a78b54dd409d308bb4d1d6bbbb2a81846c7aba2e9ef38963e5c2bfb52aef55653b0d12dfab7dcc904cb + checksum: 87bba177ab858a9b606ee52220e6bf395277beebafefe8ab5dbdf178f5825274a24ca16dca7e0ddd41e5ac3533164ee52e3d0eec87b66d78aae796d24a817842 languageName: node linkType: hard @@ -24718,7 +24601,7 @@ __metadata: languageName: node linkType: hard -"minimist-options@npm:^4.0.2": +"minimist-options@npm:4.1.0": version: 4.1.0 resolution: "minimist-options@npm:4.1.0" dependencies: @@ -25676,7 +25559,7 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^2.0.0, normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.3.4, normalize-package-data@npm:^2.5.0": +"normalize-package-data@npm:^2.0.0, normalize-package-data@npm:^2.3.2, normalize-package-data@npm:^2.5.0": version: 2.5.0 resolution: "normalize-package-data@npm:2.5.0" dependencies: @@ -25725,7 +25608,7 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^6.0.1, normalize-url@npm:^6.1.0": +"normalize-url@npm:^6.0.1": version: 6.1.0 resolution: "normalize-url@npm:6.1.0" checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 @@ -26199,7 +26082,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^7.0.3": +"open@npm:^7.0.3, open@npm:^7.3.1": version: 7.4.2 resolution: "open@npm:7.4.2" dependencies: @@ -26739,12 +26622,12 @@ __metadata: languageName: node linkType: hard -"parse-path@npm:^5.0.0": - version: 5.0.0 - resolution: "parse-path@npm:5.0.0" +"parse-path@npm:^7.0.0": + version: 7.0.0 + resolution: "parse-path@npm:7.0.0" dependencies: protocols: ^2.0.0 - checksum: e9f670559cd8e535f39f548bf5d41ad96a220190ea98df33d0babd9dfaa7c3c70ee2e55394078517d5e7e93c6a39c8eac1261ed3f9e68033656614fc954262e8 + checksum: 244b46523a58181d251dda9b888efde35d8afb957436598d948852f416d8c76ddb4f2010f9fc94218b4be3e5c0f716aa0d2026194a781e3b8981924142009302 languageName: node linkType: hard @@ -26762,15 +26645,12 @@ __metadata: languageName: node linkType: hard -"parse-url@npm:^7.0.2": - version: 7.0.2 - resolution: "parse-url@npm:7.0.2" +"parse-url@npm:^8.1.0": + version: 8.1.0 + resolution: "parse-url@npm:8.1.0" dependencies: - is-ssh: ^1.4.0 - normalize-url: ^6.1.0 - parse-path: ^5.0.0 - protocols: ^2.0.1 - checksum: 3e26852706bebe9fac409909316716dee52883d2fb5c82d65577effba1507abb7bc42bb59ce0ba6c8659168fb99acf89000bd8fe096ed3ad7124fa85227436d7 + parse-path: ^7.0.0 + checksum: b93e21ab4c93c7d7317df23507b41be7697694d4c94f49ed5c8d6288b01cba328fcef5ba388e147948eac20453dee0df9a67ab2012415189fff85973bdffe8d9 languageName: node linkType: hard @@ -26874,13 +26754,6 @@ __metadata: languageName: node linkType: hard -"path-dirname@npm:^1.0.0": - version: 1.0.2 - resolution: "path-dirname@npm:1.0.2" - checksum: 0d2f6604ae05a252a0025318685f290e2764ecf9c5436f203cdacfc8c0b17c24cdedaa449d766beb94ab88cc7fc70a09ec21e7933f31abc2b719180883e5e33f - languageName: node - linkType: hard - "path-exists@npm:^2.0.0": version: 2.1.0 resolution: "path-exists@npm:2.1.0" @@ -29120,16 +28993,6 @@ __metadata: languageName: node linkType: hard -"redent@npm:^1.0.0": - version: 1.0.0 - resolution: "redent@npm:1.0.0" - dependencies: - indent-string: ^2.1.0 - strip-indent: ^1.0.1 - checksum: 2bb8f76fda9c9f44e26620047b0ba9dd1834b0a80309d0badcc23fdcf7bb27a7ca74e66b683baa0d4b8cb5db787f11be086504036d63447976f409dd3e73fd7d - languageName: node - linkType: hard - "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -29599,15 +29462,6 @@ __metadata: languageName: node linkType: hard -"repeating@npm:^2.0.0": - version: 2.0.1 - resolution: "repeating@npm:2.0.1" - dependencies: - is-finite: ^1.0.0 - checksum: d2db0b69c5cb0c14dd750036e0abcd6b3c3f7b2da3ee179786b755cf737ca15fa0fff417ca72de33d6966056f4695440e680a352401fc02c95ade59899afbdd0 - languageName: node - linkType: hard - "replace-ext@npm:0.0.1": version: 0.0.1 resolution: "replace-ext@npm:0.0.1" @@ -30722,7 +30576,7 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:6.0.0, serialize-javascript@npm:^6.0.0": +"serialize-javascript@npm:6.0.0": version: 6.0.0 resolution: "serialize-javascript@npm:6.0.0" dependencies: @@ -30749,6 +30603,15 @@ __metadata: languageName: node linkType: hard +"serialize-javascript@npm:^6.0.1": + version: 6.0.1 + resolution: "serialize-javascript@npm:6.0.1" + dependencies: + randombytes: ^2.1.0 + checksum: 3c4f4cb61d0893b988415bdb67243637333f3f574e9e9cc9a006a2ced0b390b0b3b44aef8d51c951272a9002ec50885eefdc0298891bc27eb2fe7510ea87dc4f + languageName: node + linkType: hard + "serve-favicon@npm:^2.5.0": version: 2.5.0 resolution: "serve-favicon@npm:2.5.0" @@ -30970,15 +30833,15 @@ __metadata: linkType: hard "shelljs@npm:^0.8.1": - version: 0.8.4 - resolution: "shelljs@npm:0.8.4" + version: 0.8.5 + resolution: "shelljs@npm:0.8.5" dependencies: glob: ^7.0.0 interpret: ^1.0.0 rechoir: ^0.6.2 bin: shjs: bin/shjs - checksum: 27f83206ef6a4f5b74a493726c3e6b4c3e07a9c2aac94c5e692d800a61353c18a8234967bd8523b1346abe718beb563843687fb57f466529ba06db3cae6f0bb3 + checksum: 7babc46f732a98f4c054ec1f048b55b9149b98aa2da32f6cf9844c434b43c6251efebd6eec120937bd0999e13811ebd45efe17410edb3ca938f82f9381302748 languageName: node linkType: hard @@ -31216,24 +31079,25 @@ __metadata: linkType: hard "source-map-explorer@npm:^2.4.2": - version: 2.4.2 - resolution: "source-map-explorer@npm:2.4.2" + version: 2.5.3 + resolution: "source-map-explorer@npm:2.5.3" dependencies: btoa: ^1.2.1 - chalk: ^3.0.0 + chalk: ^4.1.0 convert-source-map: ^1.7.0 - ejs: ^3.0.2 + ejs: ^3.1.5 escape-html: ^1.0.3 glob: ^7.1.6 - gzip-size: ^5.1.1 - lodash: ^4.17.15 - open: ^7.0.3 - source-map: ^0.7.3 - temp: ^0.9.1 - yargs: ^15.3.1 + gzip-size: ^6.0.0 + lodash: ^4.17.20 + open: ^7.3.1 + source-map: ^0.7.4 + temp: ^0.9.4 + yargs: ^16.2.0 bin: - source-map-explorer: dist/cli.js - checksum: 89fb55c5bf2b08104e7a51d3322aa5561db9fe57724fc5baa5bae152c1c6c9df48e6f425e1f35c61b197002d31b1cd6673dc166b24204135582f6a1970a03e33 + sme: bin/cli.js + source-map-explorer: bin/cli.js + checksum: 1d4e619d7eb224f38a3dadfb20eb34a56cfc29bd237b4815b60257e7fe5ee9f791fda3e0bba91318e0f2beffec5cca573abb8b5030a95f305ce4abee93296065 languageName: node linkType: hard @@ -31317,10 +31181,10 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.7.2, source-map@npm:^0.7.3": - version: 0.7.3 - resolution: "source-map@npm:0.7.3" - checksum: cd24efb3b8fa69b64bf28e3c1b1a500de77e84260c5b7f2b873f88284df17974157cc88d386ee9b6d081f08fdd8242f3fc05c953685a6ad81aad94c7393dedea +"source-map@npm:^0.7.2, source-map@npm:^0.7.3, source-map@npm:^0.7.4": + version: 0.7.4 + resolution: "source-map@npm:0.7.4" + checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5 languageName: node linkType: hard @@ -32068,17 +31932,6 @@ __metadata: languageName: node linkType: hard -"strip-indent@npm:^1.0.1": - version: 1.0.1 - resolution: "strip-indent@npm:1.0.1" - dependencies: - get-stdin: ^4.0.1 - bin: - strip-indent: cli.js - checksum: 81ad9a0b8a558bdbd05b66c6c437b9ab364aa2b5479ed89969ca7908e680e21b043d40229558c434b22b3d640622e39b66288e0456d601981ac9289de9700fbd - languageName: node - linkType: hard - "strip-indent@npm:^3.0.0": version: 3.0.0 resolution: "strip-indent@npm:3.0.0" @@ -32564,12 +32417,13 @@ __metadata: languageName: node linkType: hard -"temp@npm:^0.9.1": - version: 0.9.1 - resolution: "temp@npm:0.9.1" +"temp@npm:^0.9.4": + version: 0.9.4 + resolution: "temp@npm:0.9.4" dependencies: + mkdirp: ^0.5.1 rimraf: ~2.6.2 - checksum: 568be30ec54f2a9d74b10caebb0c8e169577741122822aaeee13150af83fab2a73954ef12d7772b85f136529ffa80e940a51b42735d010dea0a634fbc70c0223 + checksum: 8709d4d63278bd309ca0e49e80a268308dea543a949e71acd427b3314cd9417da9a2cc73425dd9c21c6780334dbffd67e05e7be5aaa73e9affe8479afc6f20e3 languageName: node linkType: hard @@ -32651,14 +32505,14 @@ __metadata: linkType: hard "terser-webpack-plugin@npm:^5.0.3, terser-webpack-plugin@npm:^5.1.3": - version: 5.3.6 - resolution: "terser-webpack-plugin@npm:5.3.6" + version: 5.3.7 + resolution: "terser-webpack-plugin@npm:5.3.7" dependencies: - "@jridgewell/trace-mapping": ^0.3.14 + "@jridgewell/trace-mapping": ^0.3.17 jest-worker: ^27.4.5 schema-utils: ^3.1.1 - serialize-javascript: ^6.0.0 - terser: ^5.14.1 + serialize-javascript: ^6.0.1 + terser: ^5.16.5 peerDependencies: webpack: ^5.1.0 peerDependenciesMeta: @@ -32668,26 +32522,26 @@ __metadata: optional: true uglify-js: optional: true - checksum: 8f3448d7fdb0434ce6a0c09d95c462bfd2f4a5a430233d854163337f734a7f5c07c74513d16081e06d4ca33d366d5b1a36f5444219bc41a7403afd6162107bad + checksum: 095e699fdeeb553cdf2c6f75f983949271b396d9c201d7ae9fc633c45c1c1ad14c7257ef9d51ccc62213dd3e97f875870ba31550f6d4f1b6674f2615562da7f7 languageName: node linkType: hard "terser@npm:^4.1.2, terser@npm:^4.6.3": - version: 4.8.0 - resolution: "terser@npm:4.8.0" + version: 4.8.1 + resolution: "terser@npm:4.8.1" dependencies: commander: ^2.20.0 source-map: ~0.6.1 source-map-support: ~0.5.12 bin: terser: bin/terser - checksum: f980789097d4f856c1ef4b9a7ada37beb0bb022fb8aa3057968862b5864ad7c244253b3e269c9eb0ab7d0caf97b9521273f2d1cf1e0e942ff0016e0583859c71 + checksum: b342819bf7e82283059aaa3f22bb74deb1862d07573ba5a8947882190ad525fd9b44a15074986be083fd379c58b9a879457a330b66dcdb77b485c44267f9a55a languageName: node linkType: hard -"terser@npm:^5.10.0, terser@npm:^5.14.1, terser@npm:^5.3.4, terser@npm:^5.7.0": - version: 5.15.1 - resolution: "terser@npm:5.15.1" +"terser@npm:^5.10.0, terser@npm:^5.16.5, terser@npm:^5.3.4, terser@npm:^5.7.0": + version: 5.17.1 + resolution: "terser@npm:5.17.1" dependencies: "@jridgewell/source-map": ^0.3.2 acorn: ^8.5.0 @@ -32695,7 +32549,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 9880a1e0956983a1ce5de204ea35121c0009fa41d582a6904ae850e1953a1a2cc021168439565280c5a8eee67c85a874175627e24989b046c7a72589b81c3979 + checksum: 69b0e80e3c4084db2819de4d6ae8a2ba79f2fcd7ed6df40fe4b602ec7bfd8e889cc63c7d5268f30990ffecbf6eeda18f857adad9386fe2c2331b398d58ed855c languageName: node linkType: hard @@ -33102,13 +32956,6 @@ __metadata: languageName: node linkType: hard -"trim-newlines@npm:^1.0.0": - version: 1.0.0 - resolution: "trim-newlines@npm:1.0.0" - checksum: ed96eea318581c6f894c0a98d0c4f16dcce11a41794ce140a79db55f1cab709cd9117578ee5e49a9b52f41e9cd93eaf3efa6c4bddbc77afbf91128b396fadbc1 - languageName: node - linkType: hard - "trim-newlines@npm:^3.0.0": version: 3.0.1 resolution: "trim-newlines@npm:3.0.1" @@ -35252,17 +35099,17 @@ __metadata: languageName: node linkType: hard -"x-default-browser@npm:^0.4.0": - version: 0.4.0 - resolution: "x-default-browser@npm:0.4.0" +"x-default-browser@npm:^0.5.2": + version: 0.5.2 + resolution: "x-default-browser@npm:0.5.2" dependencies: - default-browser-id: ^1.0.4 + default-browser-id: ^2.0.0 dependenciesMeta: default-browser-id: optional: true bin: x-default-browser: bin/x-default-browser.js - checksum: 9649fe6b4b91de93d5a48a5042b55a6e15c87d2514bc4f2e12582f8b25c1a6810fafc6f4c454fb531540e431e32a0a26ac130e418c0ce5c6ca892fb01945ea9e + checksum: 0af8f907efb7af4f84b1b0f694c8c588cb00bb0a7d4db2b05a900399ba9208673d9ca28f0cdea21aee9075ac780a92a97ddde1b36a0689fb6fce81f78981969f languageName: node linkType: hard @@ -35498,7 +35345,7 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^15.0.0, yargs@npm:^15.0.2, yargs@npm:^15.3.1": +"yargs@npm:^15.0.0, yargs@npm:^15.0.2": version: 15.4.1 resolution: "yargs@npm:15.4.1" dependencies: From 64d4bfbbe9de72b2a38b9c8ac11114b46db26e97 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 25 Apr 2023 08:25:58 +0000 Subject: [PATCH 18/60] Use SIWE origin validation logic from @metamask/controller-utils (#18518) * feat: use SIWE origin domain validation from @metamask/controller-utils * deps: @metamask/controller-utils@3.2.0->3.3.0 --- lavamoat/browserify/beta/policy.json | 1 + lavamoat/browserify/desktop/policy.json | 1 + lavamoat/browserify/flask/policy.json | 1 + lavamoat/browserify/main/policy.json | 1 + package.json | 2 +- .../signature-request-siwe.js | 13 ++----------- yarn.lock | 10 +++++----- 7 files changed, 12 insertions(+), 17 deletions(-) diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 987ae295a..6b48762c4 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -750,6 +750,7 @@ }, "@metamask/controller-utils": { "globals": { + "URL": true, "console.error": true, "fetch": true, "setTimeout": true diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 826073a45..f84728167 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -750,6 +750,7 @@ }, "@metamask/controller-utils": { "globals": { + "URL": true, "console.error": true, "fetch": true, "setTimeout": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 826073a45..f84728167 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -750,6 +750,7 @@ }, "@metamask/controller-utils": { "globals": { + "URL": true, "console.error": true, "fetch": true, "setTimeout": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 987ae295a..6b48762c4 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -750,6 +750,7 @@ }, "@metamask/controller-utils": { "globals": { + "URL": true, "console.error": true, "fetch": true, "setTimeout": true diff --git a/package.json b/package.json index b7f0f3568..01d1e9abc 100644 --- a/package.json +++ b/package.json @@ -232,7 +232,7 @@ "@metamask/assets-controllers": "^6.0.0", "@metamask/base-controller": "^2.0.0", "@metamask/contract-metadata": "^2.3.1", - "@metamask/controller-utils": "^3.2.0", + "@metamask/controller-utils": "^3.3.0", "@metamask/design-tokens": "^1.9.0", "@metamask/desktop": "^0.3.0", "@metamask/eth-json-rpc-infura": "^8.0.0", diff --git a/ui/components/app/signature-request-siwe/signature-request-siwe.js b/ui/components/app/signature-request-siwe/signature-request-siwe.js index 5fab50ab2..82f46e746 100644 --- a/ui/components/app/signature-request-siwe/signature-request-siwe.js +++ b/ui/components/app/signature-request-siwe/signature-request-siwe.js @@ -2,6 +2,7 @@ import React, { useCallback, useContext, useState } from 'react'; import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import log from 'loglevel'; +import { isValidSIWEOrigin } from '@metamask/controller-utils'; import { BannerAlert, Text } from '../../component-library'; import Popover from '../../ui/popover'; import Checkbox from '../../ui/check-box'; @@ -51,17 +52,7 @@ export default function SignatureRequestSIWE({ const isMatchingAddress = from.toLowerCase() === parsedMessage.address.toLowerCase(); - const checkSIWEDomain = () => { - let isSIWEDomainValid = false; - - if (origin) { - const { host } = new URL(origin); - isSIWEDomainValid = parsedMessage.domain === host; - } - return isSIWEDomainValid; - }; - - const isSIWEDomainValid = checkSIWEDomain(); + const isSIWEDomainValid = isValidSIWEOrigin(txData.msgParams); const [isShowingDomainWarning, setIsShowingDomainWarning] = useState(false); const [hasAgreedToDomainWarning, setHasAgreedToDomainWarning] = diff --git a/yarn.lock b/yarn.lock index e69767e1b..ee7c95592 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3725,9 +3725,9 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^3.0.0, @metamask/controller-utils@npm:^3.1.0, @metamask/controller-utils@npm:^3.2.0": - version: 3.2.0 - resolution: "@metamask/controller-utils@npm:3.2.0" +"@metamask/controller-utils@npm:^3.0.0, @metamask/controller-utils@npm:^3.1.0, @metamask/controller-utils@npm:^3.2.0, @metamask/controller-utils@npm:^3.3.0": + version: 3.3.0 + resolution: "@metamask/controller-utils@npm:3.3.0" dependencies: "@metamask/utils": ^5.0.1 "@spruceid/siwe-parser": 1.1.3 @@ -3736,7 +3736,7 @@ __metadata: ethereumjs-util: ^7.0.10 ethjs-unit: ^0.1.6 fast-deep-equal: ^3.1.3 - checksum: 06b27f9273719ca6eb556c032b77e9066c8d38ad4ff081896a68046e1e4764482f244bf849d51fc622f425e54c9063cc697abdb0cb2f2aaab9a0d8807f2310f3 + checksum: 54e19f7bfd7b7762913313877484f0cfe9ac3e66cf43eabc6573e22433a7a36154a1f04fa5834807644a780b4b2200e0cafc06a0f0ef9fcead44304d742b2ad3 languageName: node linkType: hard @@ -24063,7 +24063,7 @@ __metadata: "@metamask/auto-changelog": ^2.1.0 "@metamask/base-controller": ^2.0.0 "@metamask/contract-metadata": ^2.3.1 - "@metamask/controller-utils": ^3.2.0 + "@metamask/controller-utils": ^3.3.0 "@metamask/design-tokens": ^1.9.0 "@metamask/desktop": ^0.3.0 "@metamask/eslint-config": ^9.0.0 From c1614ec670f2042a369d0c394b06b70e8b6dc6d1 Mon Sep 17 00:00:00 2001 From: Bernardo Garces Chapero Date: Tue, 25 Apr 2023 11:47:49 +0200 Subject: [PATCH 19/60] Approvals selector refactor (#18664) --- ui/pages/home/home.component.js | 10 +++---- ui/pages/home/home.container.js | 10 +++++-- ui/selectors/approvals.test.ts | 48 +++++++++++++++++++++++++++++++++ ui/selectors/approvals.ts | 19 +++++++++++++ ui/selectors/index.js | 1 + 5 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 ui/selectors/approvals.test.ts create mode 100644 ui/selectors/approvals.ts diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index 4001d0ca1..6fabafdf9 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -88,7 +88,7 @@ export default class Home extends PureComponent { static propTypes = { history: PropTypes.object, forgottenPassword: PropTypes.bool, - suggestedAssets: PropTypes.array, + hasWatchAssetPendingApprovals: PropTypes.bool, unconfirmedTransactionsCount: PropTypes.number, shouldShowSeedPhraseReminder: PropTypes.bool.isRequired, isPopup: PropTypes.bool, @@ -169,7 +169,7 @@ export default class Home extends PureComponent { haveSwapsQuotes, isNotification, showAwaitingSwapScreen, - suggestedAssets = [], + hasWatchAssetPendingApprovals, swapsFetchParams, unconfirmedTransactionsCount, } = this.props; @@ -180,7 +180,7 @@ export default class Home extends PureComponent { } else if ( firstPermissionsRequestId || unconfirmedTransactionsCount > 0 || - suggestedAssets.length > 0 || + hasWatchAssetPendingApprovals || (!isNotification && (showAwaitingSwapScreen || haveSwapsQuotes || swapsFetchParams)) ) { @@ -193,7 +193,7 @@ export default class Home extends PureComponent { firstPermissionsRequestId, history, isNotification, - suggestedAssets = [], + hasWatchAssetPendingApprovals, unconfirmedTransactionsCount, haveSwapsQuotes, showAwaitingSwapScreen, @@ -210,7 +210,7 @@ export default class Home extends PureComponent { history.push(`${CONNECT_ROUTE}/${firstPermissionsRequestId}`); } else if (unconfirmedTransactionsCount > 0) { history.push(CONFIRM_TRANSACTION_ROUTE); - } else if (suggestedAssets.length > 0) { + } else if (hasWatchAssetPendingApprovals) { history.push(CONFIRM_ADD_SUGGESTED_TOKEN_ROUTE); } else if (pendingConfirmations.length > 0) { history.push(CONFIRMATION_V_NEXT_ROUTE); diff --git a/ui/pages/home/home.container.js b/ui/pages/home/home.container.js index 0601c7e1e..9ffaf1094 100644 --- a/ui/pages/home/home.container.js +++ b/ui/pages/home/home.container.js @@ -1,6 +1,7 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; +import { ApprovalType } from '@metamask/controller-utils'; import { activeTabHasPermissions, getFirstPermissionRequest, @@ -26,6 +27,7 @@ import { getNewTokensImported, getShouldShowSeedPhraseReminder, getRemoveNftMessage, + hasPendingApprovalsSelector, } from '../../selectors'; import { @@ -65,7 +67,6 @@ import Home from './home.component'; const mapStateToProps = (state) => { const { metamask, appState } = state; const { - suggestedAssets, seedPhraseBackedUp, selectedAddress, connectedStatusPopoverHasBeenShown, @@ -108,9 +109,14 @@ const mapStateToProps = (state) => { hasUnsignedQRHardwareTransaction(state) || hasUnsignedQRHardwareMessage(state); + const hasWatchAssetPendingApprovals = hasPendingApprovalsSelector( + state, + ApprovalType.WatchAsset, + ); + return { forgottenPassword, - suggestedAssets, + hasWatchAssetPendingApprovals, swapsEnabled, unconfirmedTransactionsCount: unconfirmedTransactionsCountSelector(state), shouldShowSeedPhraseReminder: getShouldShowSeedPhraseReminder(state), diff --git a/ui/selectors/approvals.test.ts b/ui/selectors/approvals.test.ts new file mode 100644 index 000000000..384d4d1be --- /dev/null +++ b/ui/selectors/approvals.test.ts @@ -0,0 +1,48 @@ +import { ApprovalType } from '@metamask/controller-utils'; +import { hasPendingApprovalsSelector } from './approvals'; + +describe('approval selectors', () => { + const mockedState = { + metamask: { + 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.EthSignTypedData, + requestData: {}, + requestState: null, + }, + }, + }, + }; + + describe('hasPendingApprovalsSelector', () => { + it('should return true if there is a pending approval request', () => { + const result = hasPendingApprovalsSelector( + mockedState, + ApprovalType.WatchAsset, + ); + + expect(result).toBe(true); + }); + + it('should return false if there is no pending approval request', () => { + const result = hasPendingApprovalsSelector( + mockedState, + ApprovalType.Transaction, + ); + + expect(result).toBe(false); + }); + }); +}); diff --git a/ui/selectors/approvals.ts b/ui/selectors/approvals.ts new file mode 100644 index 000000000..f777185df --- /dev/null +++ b/ui/selectors/approvals.ts @@ -0,0 +1,19 @@ +import { ApprovalControllerState } from '@metamask/approval-controller'; +import { ApprovalType } from '@metamask/controller-utils'; + +type ApprovalsMetaMaskState = { + metamask: { + pendingApprovals: ApprovalControllerState['pendingApprovals']; + }; +}; + +export function hasPendingApprovalsSelector( + state: ApprovalsMetaMaskState, + approvalType: ApprovalType, +) { + const pendingApprovalRequests = Object.values( + state.metamask.pendingApprovals, + ).filter(({ type }) => type === approvalType); + + return pendingApprovalRequests.length > 0; +} diff --git a/ui/selectors/index.js b/ui/selectors/index.js index 28d8e9e34..552ce7408 100644 --- a/ui/selectors/index.js +++ b/ui/selectors/index.js @@ -5,3 +5,4 @@ export * from './metametrics'; export * from './permissions'; export * from './selectors'; export * from './transactions'; +export * from './approvals'; From 16dabdf802012309f38a947e3ead86b98271cc4b Mon Sep 17 00:00:00 2001 From: Shane T Date: Tue, 25 Apr 2023 11:47:12 +0100 Subject: [PATCH 20/60] [MMI] Adds a warning if message signing account mismatches selected account (#18659) * [MMI] Adds a warning if message signing account mismatches selected account * chore: fix code fencing * chore: remove render method to simplify * chore: remove renderMethods --- app/_locales/en/messages.json | 3 + .../signature-request-original.component.js | 66 ++++++++++++++++++- .../signature-request-original.container.js | 6 ++ .../signature-request-original.stories.js | 20 +++++- .../signature-request-original.test.js | 3 + .../signature-request.component.js | 57 +++++++++++++++- .../signature-request.component.test.js | 36 ++++++++++ .../signature-request.container.js | 6 ++ .../signature-request.container.test.js | 3 + .../signature-request.stories.js | 16 ++++- ui/pages/confirm-signature-request/index.js | 15 ++++- 11 files changed, 226 insertions(+), 5 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index df8a1d895..9330d0a95 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2142,6 +2142,9 @@ "metrics": { "message": "Metrics" }, + "mismatchAccount": { + "message": "Your selected account ($1) is different than the account trying to sign ($2)" + }, "mismatchedChainLinkText": { "message": "verify the network details", "description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key." 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 9d46e92d1..d6b432035 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 @@ -5,7 +5,13 @@ import { ObjectInspector } from 'react-inspector'; import LedgerInstructionField from '../ledger-instruction-field'; import { MESSAGE_TYPE } from '../../../../shared/constants/app'; -import { getURLHostName, sanitizeString } from '../../../helpers/utils/util'; +import { + getURLHostName, + sanitizeString, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + shortenAddress, + ///: END:ONLY_INCLUDE_IN +} from '../../../helpers/utils/util'; import { stripHexPrefix } from '../../../../shared/modules/hexstring-utils'; import Button from '../../ui/button'; import SiteOrigin from '../../ui/site-origin'; @@ -17,6 +23,13 @@ import { FONT_WEIGHT, TEXT_ALIGN, TextColor, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + IconColor, + DISPLAY, + BLOCK_SIZES, + TextVariant, + BackgroundColor, + ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/design-system'; import { NETWORK_TYPES } from '../../../../shared/constants/network'; import { Numeric } from '../../../../shared/modules/Numeric'; @@ -26,6 +39,11 @@ import SecurityProviderBannerMessage from '../security-provider-banner-message/s import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../security-provider-banner-message/security-provider-banner-message.constants'; import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils'; + +///: BEGIN:ONLY_INCLUDE_IN(mmi) +import { Icon, IconName, Text } from '../../component-library'; +import Box from '../../ui/box/box'; +///: END:ONLY_INCLUDE_IN import SignatureRequestOriginalWarning from './signature-request-original-warning'; export default class SignatureRequestOriginal extends Component { @@ -55,6 +73,9 @@ export default class SignatureRequestOriginal extends Component { showRejectTransactionsConfirmationModal: PropTypes.func.isRequired, cancelAll: PropTypes.func.isRequired, provider: PropTypes.object, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + selectedAccount: PropTypes.object, + ///: END:ONLY_INCLUDE_IN }; state = { @@ -92,6 +113,16 @@ export default class SignatureRequestOriginal extends Component { } }; + renderAccountInfo = () => { + return ( +
+ {this.renderAccount()} + {this.renderRequestIcon()} + {this.renderBalance()} +
+ ); + }; + renderTypedData = (data) => { const { t } = this.context; const { domain, message } = JSON.parse(data); @@ -152,6 +183,39 @@ export default class SignatureRequestOriginal extends Component { securityProviderResponse={txData.securityProviderResponse} /> ) : null} + + { + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + this.props.selectedAccount.address === + this.props.fromAccount.address ? null : ( + + + + {this.context.t('mismatchAccount', [ + shortenAddress(this.props.selectedAccount.address), + shortenAddress(this.props.fromAccount.address), + ])} + + + ) + ///: END:ONLY_INCLUDE_IN + } +
{ diff --git a/ui/components/app/signature-request/signature-request.component.js b/ui/components/app/signature-request/signature-request.component.js index 92fb56a06..68390deb3 100644 --- a/ui/components/app/signature-request/signature-request.component.js +++ b/ui/components/app/signature-request/signature-request.component.js @@ -2,7 +2,13 @@ import React, { PureComponent } from 'react'; import { memoize } from 'lodash'; import PropTypes from 'prop-types'; import LedgerInstructionField from '../ledger-instruction-field'; -import { sanitizeMessage, getURLHostName } from '../../../helpers/utils/util'; +import { + sanitizeMessage, + getURLHostName, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + shortenAddress, + ///: END:ONLY_INCLUDE_IN +} from '../../../helpers/utils/util'; import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import SiteOrigin from '../../ui/site-origin'; import Button from '../../ui/button'; @@ -13,6 +19,13 @@ import { FONT_WEIGHT, TEXT_ALIGN, TextColor, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + IconColor, + DISPLAY, + BLOCK_SIZES, + TextVariant, + BackgroundColor, + ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/design-system'; import NetworkAccountBalanceHeader from '../network-account-balance-header'; import { NETWORK_TYPES } from '../../../../shared/constants/network'; @@ -23,6 +36,11 @@ import SecurityProviderBannerMessage from '../security-provider-banner-message/s import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../security-provider-banner-message/security-provider-banner-message.constants'; import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils'; +///: BEGIN:ONLY_INCLUDE_IN(mmi) +import { Icon, IconName, Text } from '../../component-library'; +import Box from '../../ui/box/box'; +///: END:ONLY_INCLUDE_IN + import Footer from './signature-request-footer'; import Message from './signature-request-message'; @@ -75,6 +93,11 @@ export default class SignatureRequest extends PureComponent { mostRecentOverviewPage: PropTypes.string, showRejectTransactionsConfirmationModal: PropTypes.func.isRequired, cancelAll: PropTypes.func.isRequired, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + // Used to show a warning if the signing account is not the selected account + // Largely relevant for contract wallet custodians + selectedAccount: PropTypes.object, + ///: END:ONLY_INCLUDE_IN }; static contextTypes = { @@ -255,6 +278,38 @@ export default class SignatureRequest extends PureComponent { securityProviderResponse={txData.securityProviderResponse} /> ) : null} + + { + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + this.props.selectedAccount.address === address ? null : ( + + + + {this.context.t('mismatchAccount', [ + shortenAddress(this.props.selectedAccount.address), + shortenAddress(address), + ])} + + + ) + ///: END:ONLY_INCLUDE_IN + } +
{ @@ -324,5 +327,38 @@ describe('Signature Request Component', () => { ).toBeNull(); expect(queryByText('This is based on information from')).toBeNull(); }); + + it('should render a warning when the selected account is not the one being used to sign', () => { + const msgParams = { + data: JSON.stringify(messageData), + version: 'V4', + origin: 'test', + }; + + const { container } = renderWithProvider( + , + store, + ); + + expect( + container.querySelector('.request-signature__mismatch-info'), + ).toBeInTheDocument(); + }); }); }); diff --git a/ui/components/app/signature-request/signature-request.container.js b/ui/components/app/signature-request/signature-request.container.js index 7ce1c76da..5aae9f3ca 100644 --- a/ui/components/app/signature-request/signature-request.container.js +++ b/ui/components/app/signature-request/signature-request.container.js @@ -10,6 +10,9 @@ import { getCurrentCurrency, getPreferences, conversionRateSelector, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + getSelectedAccount, + ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; import { isAddressLedger, @@ -55,6 +58,9 @@ function mapStateToProps(state, ownProps) { subjectMetadata: getSubjectMetadata(state), // not forwarded to component allAccounts: accountsWithSendEtherInfoSelector(state), + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + selectedAccount: getSelectedAccount(state), + ///: END:ONLY_INCLUDE_IN }; } diff --git a/ui/components/app/signature-request/signature-request.container.test.js b/ui/components/app/signature-request/signature-request.container.test.js index 13579552c..54a60c889 100644 --- a/ui/components/app/signature-request/signature-request.container.test.js +++ b/ui/components/app/signature-request/signature-request.container.test.js @@ -111,6 +111,9 @@ describe('Signature Request', () => { nativeCurrency: 'ETH', currentCurrency: 'usd', conversionRate: null, + selectedAccount: { + address: '0x123456789abcdef', + }, }; const propsWithFiat = { diff --git a/ui/components/app/signature-request/signature-request.stories.js b/ui/components/app/signature-request/signature-request.stories.js index 5050ac9ab..cfd118c5b 100644 --- a/ui/components/app/signature-request/signature-request.stories.js +++ b/ui/components/app/signature-request/signature-request.stories.js @@ -3,7 +3,9 @@ import testData from '../../../../.storybook/test-data'; import README from './README.mdx'; import SignatureRequest from './signature-request.component'; -const [MOCK_PRIMARY_IDENTITY] = Object.values(testData.metamask.identities); +const [MOCK_PRIMARY_IDENTITY, MOCK_SECONDARY_IDENTITY] = Object.values( + testData.metamask.identities, +); export default { title: 'Components/App/SignatureRequest', @@ -76,4 +78,16 @@ DefaultStory.args = { }, fromAccount: MOCK_PRIMARY_IDENTITY, provider: { name: 'Goerli ETH' }, + selectedAccount: MOCK_PRIMARY_IDENTITY, +}; + +export const AccountMismatchStory = (args) => { + return ; +}; + +AccountMismatchStory.storyName = 'AccountMismatch'; + +AccountMismatchStory.args = { + ...DefaultStory.args, + selectedAccount: MOCK_SECONDARY_IDENTITY, }; diff --git a/ui/pages/confirm-signature-request/index.js b/ui/pages/confirm-signature-request/index.js index 51d977c00..d93af8e94 100644 --- a/ui/pages/confirm-signature-request/index.js +++ b/ui/pages/confirm-signature-request/index.js @@ -10,7 +10,12 @@ import SignatureRequestSIWE from '../../components/app/signature-request-siwe'; import SignatureRequestOriginal from '../../components/app/signature-request-original'; import Loading from '../../components/ui/loading-screen'; import { useRouting } from '../../hooks/useRouting'; -import { getTotalUnapprovedSignatureRequestCount } from '../../selectors'; +import { + getTotalUnapprovedSignatureRequestCount, + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + getSelectedAccount, + ///: END:ONLY_INCLUDE_IN +} from '../../selectors'; import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { TransactionStatus } from '../../../shared/constants/transaction'; import { getSendTo } from '../../ducks/send'; @@ -68,6 +73,11 @@ const ConfirmTxScreen = ({ match }) => { provider: { chainId }, } = useSelector((state) => state.metamask); const { txId: index } = useSelector((state) => state.appState); + + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + const selectedAccount = useSelector(getSelectedAccount); + ///: END:ONLY_INCLUDE_IN + const [prevValue, setPrevValues] = useState(); useEffect(() => { @@ -212,6 +222,9 @@ const ConfirmTxScreen = ({ match }) => { cancelMessage={cancelMessage(SIGN_MESSAGE_TYPE.MESSAGE)} cancelPersonalMessage={cancelMessage(SIGN_MESSAGE_TYPE.PERSONAL)} cancelTypedMessage={cancelMessage(SIGN_MESSAGE_TYPE.TYPED)} + ///: BEGIN:ONLY_INCLUDE_IN(mmi) + selectedAccount={selectedAccount} + ///: END:ONLY_INCLUDE_IN /> ); }; From 41cf85e201bb26697f84e347708ef8e38ac4b7ae Mon Sep 17 00:00:00 2001 From: David Drazic Date: Tue, 25 Apr 2023 13:09:40 +0200 Subject: [PATCH 21/60] [FLASK] Update permissions to use IconName and IconSize design system enum (#18786) * Update permissions to use IconName and IconSize design system enum approach * Update webassembly to use IconName enum --- ui/helpers/utils/permission.js | 52 +++++++++++++++------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index d102b1966..982aca2ed 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -20,11 +20,9 @@ import { Text, Icon, ///: END:ONLY_INCLUDE_IN + IconName, + IconSize, } from '../../components/component-library'; -import { - ICON_NAMES, - ICON_SIZES, -} from '../../components/component-library/icon/deprecated'; ///: BEGIN:ONLY_INCLUDE_IN(flask) import { Color, @@ -43,11 +41,7 @@ const UNKNOWN_PERMISSION = Symbol('unknown'); ///: BEGIN:ONLY_INCLUDE_IN(flask) const RIGHT_INFO_ICON = ( - + ); ///: END:ONLY_INCLUDE_IN @@ -55,9 +49,9 @@ function getLeftIcon(iconName) { return ( ); @@ -66,7 +60,7 @@ function getLeftIcon(iconName) { export const PERMISSION_DESCRIPTIONS = deepFreeze({ [RestrictedMethods.eth_accounts]: ({ t }) => ({ label: t('permission_ethereumAccounts'), - leftIcon: getLeftIcon(ICON_NAMES.EYE), + leftIcon: getLeftIcon(IconName.Eye), rightIcon: null, weight: 2, }), @@ -74,13 +68,13 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ [RestrictedMethods.snap_dialog]: ({ t }) => ({ label: t('permission_dialog'), description: t('permission_dialogDescription'), - leftIcon: ICON_NAMES.MESSAGES, + leftIcon: IconName.Messages, weight: 3, }), [RestrictedMethods.snap_notify]: ({ t }) => ({ label: t('permission_notifications'), description: t('permission_notificationsDescription'), - leftIcon: ICON_NAMES.NOTIFICATION, + leftIcon: IconName.Notification, weight: 3, }), [RestrictedMethods.snap_getBip32PublicKey]: ({ @@ -90,7 +84,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ }) => permissionValue.caveats[0].value.map(({ path, curve }, i) => { const baseDescription = { - leftIcon: ICON_NAMES.SECURITY_SEARCH, + leftIcon: IconName.SecuritySearch, weight: 1, id: `public-key-access-bip32-${path .join('-') @@ -160,7 +154,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ }) => permissionValue.caveats[0].value.map(({ path, curve }, i) => { const baseDescription = { - leftIcon: ICON_NAMES.KEY, + leftIcon: IconName.Key, weight: 1, id: `key-access-bip32-${path .join('-') @@ -244,7 +238,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ t('unrecognizedProtocol', [coinType])} , ]), - leftIcon: ICON_NAMES.KEY, + leftIcon: IconName.Key, weight: 1, id: `key-access-bip44-${coinType}-${i}`, message: t('snapInstallWarningKeyAccess', [ @@ -266,19 +260,19 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ [RestrictedMethods.snap_getEntropy]: ({ t }) => ({ label: t('permission_getEntropy'), description: t('permission_getEntropyDescription'), - leftIcon: ICON_NAMES.SECURITY_KEY, + leftIcon: IconName.SecurityKey, weight: 3, }), [RestrictedMethods.snap_manageState]: ({ t }) => ({ label: t('permission_manageState'), description: t('permission_manageStateDescription'), - leftIcon: ICON_NAMES.ADD_SQUARE, + leftIcon: IconName.AddSquare, weight: 3, }), [RestrictedMethods.wallet_snap]: ({ t, permissionValue }) => { const snaps = permissionValue.caveats[0].value; const baseDescription = { - leftIcon: getLeftIcon(ICON_NAMES.FLASH), + leftIcon: getLeftIcon(IconName.Flash), rightIcon: RIGHT_INFO_ICON, }; @@ -306,20 +300,20 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ [EndowmentPermissions['endowment:network-access']]: ({ t }) => ({ label: t('permission_accessNetwork'), description: t('permission_accessNetworkDescription'), - leftIcon: ICON_NAMES.GLOBAL, + leftIcon: IconName.Global, weight: 2, }), [EndowmentPermissions['endowment:webassembly']]: ({ t }) => ({ label: t('permission_webAssembly'), description: t('permission_webAssemblyDescription'), - leftIcon: ICON_NAMES.DOCUMENT_CODE, + leftIcon: IconName.DocumentCode, rightIcon: null, weight: 2, }), [EndowmentPermissions['endowment:long-running']]: ({ t }) => ({ label: t('permission_longRunning'), description: t('permission_longRunningDescription'), - leftIcon: ICON_NAMES.LINK, + leftIcon: IconName.Link, weight: 3, }), [EndowmentPermissions['endowment:transaction-insight']]: ({ @@ -327,7 +321,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ permissionValue, }) => { const baseDescription = { - leftIcon: ICON_NAMES.SPEEDOMETER, + leftIcon: IconName.Speedometer, weight: 3, }; @@ -348,7 +342,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ ...baseDescription, label: t('permission_transactionInsightOrigin'), description: t('permission_transactionInsightOriginDescription'), - leftIcon: ICON_NAMES.EXPLORE, + leftIcon: IconName.Explore, }); } @@ -357,7 +351,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ [EndowmentPermissions['endowment:cronjob']]: ({ t }) => ({ label: t('permission_cronjob'), description: t('permission_cronjobDescription'), - leftIcon: ICON_NAMES.CLOCK, + leftIcon: IconName.Clock, weight: 2, }), [EndowmentPermissions['endowment:ethereum-provider']]: ({ @@ -366,14 +360,14 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ }) => ({ label: t('permission_ethereumProvider'), description: t('permission_ethereumProviderDescription'), - leftIcon: ICON_NAMES.ETHEREUM, + leftIcon: IconName.Ethereum, weight: 2, id: 'ethereum-provider-access', message: t('ethereumProviderAccess', [targetSubjectMetadata?.origin]), }), [EndowmentPermissions['endowment:rpc']]: ({ t, permissionValue }) => { const baseDescription = { - leftIcon: ICON_NAMES.HIERARCHY, + leftIcon: IconName.Hierarchy, weight: 2, }; @@ -401,7 +395,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ ///: END:ONLY_INCLUDE_IN [UNKNOWN_PERMISSION]: ({ t, permissionName }) => ({ label: t('permission_unknown', [permissionName ?? 'undefined']), - leftIcon: getLeftIcon(ICON_NAMES.QUESTION), + leftIcon: getLeftIcon(IconName.Question), rightIcon: null, weight: 4, }), From 9967b50015dc6c9857c72d137056ebc23f64b0af Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:56:58 +0530 Subject: [PATCH 22/60] Worked on #17670 & #18714 for 7 files. (#18789) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../detected-token-aggregators.js | 31 ++++----- .../detected-token-ignored-popover.js | 13 ++-- .../edit-gas-fee-button.js | 24 +++---- .../edit-gas-fee-popover.js | 13 ++-- .../edit-gas-tooltip/edit-gas-tooltip.js | 58 +++++++++------- .../contract-details-modal.js | 69 ++++++++++--------- .../secure-your-wallet/secure-your-wallet.js | 62 +++++++++-------- 7 files changed, 143 insertions(+), 127 deletions(-) diff --git a/ui/components/app/detected-token/detected-token-aggregators/detected-token-aggregators.js b/ui/components/app/detected-token/detected-token-aggregators/detected-token-aggregators.js index b2865d2ae..7052eabbc 100644 --- a/ui/components/app/detected-token/detected-token-aggregators/detected-token-aggregators.js +++ b/ui/components/app/detected-token/detected-token-aggregators/detected-token-aggregators.js @@ -5,12 +5,12 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; import Box from '../../../ui/box'; import Button from '../../../ui/button'; -import Typography from '../../../ui/typography/typography'; import { DISPLAY, - FONT_WEIGHT, - TypographyVariant, + FontWeight, + TextVariant, } from '../../../../helpers/constants/design-system'; +import { Text } from '../../../component-library'; const NUMBER_OF_AGGREGATORS_TO_DISPLAY = 2; @@ -22,15 +22,13 @@ const DetectedTokenAggregators = ({ aggregators }) => { return ( - + {t('fromTokenLists', [ numOfHiddenAggregators > 0 && !displayMore ? ( - {`${aggregators @@ -44,18 +42,19 @@ const DetectedTokenAggregators = ({ aggregators }) => { > {t('plusXMore', [numOfHiddenAggregators])} - + ) : ( - {`${aggregators.join(', ')}.`} - + ), ])} - + ); }; diff --git a/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js b/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js index 2a2566109..b32428c18 100644 --- a/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js +++ b/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js @@ -5,8 +5,8 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; import Popover from '../../../ui/popover'; import Button from '../../../ui/button'; -import Typography from '../../../ui/typography/typography'; -import { TypographyVariant } from '../../../../helpers/constants/design-system'; +import { TextVariant } from '../../../../helpers/constants/design-system'; +import { Text } from '../../../component-library'; const DetectedTokenIgnoredPopover = ({ partiallyIgnoreDetectedTokens, @@ -48,9 +48,10 @@ const DetectedTokenIgnoredPopover = ({ })} footer={footer} > - + ); }; diff --git a/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js b/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js index e3ee7fa00..70fb157e1 100644 --- a/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js +++ b/ui/components/app/edit-gas-fee-button/edit-gas-fee-button.js @@ -5,7 +5,7 @@ import { EditGasModes, PriorityLevels } from '../../../../shared/constants/gas'; import { Color, TextColor, - TypographyVariant, + TextVariant, } from '../../../helpers/constants/design-system'; import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas'; import { useGasFeeContext } from '../../../contexts/gasFee'; @@ -13,8 +13,7 @@ import { useI18nContext } from '../../../hooks/useI18nContext'; import { useTransactionEventFragment } from '../../../hooks/useTransactionEventFragment'; import { useTransactionModalContext } from '../../../contexts/transaction-modal'; import InfoTooltip from '../../ui/info-tooltip/info-tooltip'; -import Typography from '../../ui/typography/typography'; -import { Icon, IconName, IconSize } from '../../component-library'; +import { Icon, IconName, IconSize, Text } from '../../component-library'; export default function EditGasFeeButton({ userAcknowledgedGasMissing }) { const t = useI18nContext(); @@ -87,22 +86,23 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) { contentText={
{transaction?.origin && ( - {t('dappSuggestedTooltip', [transaction.origin])} - + )} - + {t('maxBaseFee')} {maxFeePerGas} - - + + {t('maxPriorityFee')} {maxPriorityFeePerGas} - - + + {t('gasLimit')} {gasLimit} - +
} position="top" diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js index 935bf4e2b..d057f042b 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-fee-popover.js @@ -6,16 +6,16 @@ import { useTransactionModalContext } from '../../../contexts/transaction-modal' import Box from '../../ui/box'; import ErrorMessage from '../../ui/error-message'; import Popover from '../../ui/popover'; -import Typography from '../../ui/typography/typography'; import { TextColor, - TypographyVariant, + TextVariant, } from '../../../helpers/constants/design-system'; import { INSUFFICIENT_FUNDS_ERROR_KEY } from '../../../helpers/constants/error-keys'; import { useGasFeeContext } from '../../../contexts/gasFee'; import AppLoadingSpinner from '../app-loading-spinner'; import ZENDESK_URLS from '../../../helpers/constants/zendesk-url'; +import { Text } from '../../component-library'; import EditGasItem from './edit-gas-item'; import NetworkStatistics from './network-statistics'; @@ -84,12 +84,13 @@ const EditGasFeePopover = () => { - {t('learnMoreAboutGas', [ { {t('learnMore')} , ])} - +
diff --git a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.js b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.js index 685354471..2d700e3c7 100644 --- a/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.js +++ b/ui/components/app/edit-gas-fee-popover/edit-gas-tooltip/edit-gas-tooltip.js @@ -5,13 +5,13 @@ import { PriorityLevels, } from '../../../../../shared/constants/gas'; import { - FONT_WEIGHT, + FontWeight, TextColor, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import { isMetamaskSuggestedGasEstimate } from '../../../../helpers/utils/gas'; import { roundToDecimalPlacesRemovingExtraZeroes } from '../../../../helpers/utils/util'; -import Typography from '../../../ui/typography'; +import { Text } from '../../../component-library'; const EditGasToolTip = ({ editGasMode, @@ -107,43 +107,47 @@ const EditGasToolTip = ({ ) : null} {toolTipMessage && (
- + {toolTipMessage} - +
)} {priorityLevel === PriorityLevels.custom || estimateGreaterThanGasUse ? null : (
- {t('maxBaseFee')} - + {maxFeePerGas && ( - {roundToDecimalPlacesRemovingExtraZeroes(maxFeePerGas, 4)} - + )}
- {t('priorityFeeProperCase')} - + {maxPriorityFeePerGas && ( - @@ -151,25 +155,27 @@ const EditGasToolTip = ({ maxPriorityFeePerGas, 4, )} - + )}
- {t('gasLimit')} - + {gasLimit && ( - {roundToDecimalPlacesRemovingExtraZeroes(gasLimit, 4)} - + )}
diff --git a/ui/components/app/modals/contract-details-modal/contract-details-modal.js b/ui/components/app/modals/contract-details-modal/contract-details-modal.js index 3316ff588..e6250a280 100644 --- a/ui/components/app/modals/contract-details-modal/contract-details-modal.js +++ b/ui/components/app/modals/contract-details-modal/contract-details-modal.js @@ -9,10 +9,9 @@ import { useI18nContext } from '../../../../hooks/useI18nContext'; import Identicon from '../../../ui/identicon'; import { ellipsify } from '../../../../pages/send/send.utils'; import Popover from '../../../ui/popover'; -import Typography from '../../../ui/typography'; import { - FONT_WEIGHT, - TypographyVariant, + FontWeight, + TextVariant, DISPLAY, Size, BorderStyle, @@ -25,7 +24,7 @@ import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard'; import { getAddressBookEntry } from '../../../../selectors'; import { TokenStandard } from '../../../../../shared/constants/transaction'; import NftCollectionImage from '../../../ui/nft-collection-image/nft-collection-image'; -import { ButtonIcon, IconName } from '../../../component-library'; +import { ButtonIcon, IconName, Text } from '../../../component-library'; export default function ContractDetailsModal({ onClose, @@ -62,32 +61,35 @@ export default function ContractDetailsModal({ paddingLeft={4} className="contract-details-modal__content" > - {t('contractTitle')} - - + {t('contractDescription')} - + {!isContractRequestingSignature && ( <> - {nft ? t('contractNFT') : t('contractToken')} - + )} - {tokenName || ellipsify(tokenAddress)} - + {tokenName && ( - {ellipsify(tokenAddress)} - + )} )} - + - {addressBookEntry?.data?.name || ellipsify(toAddress)} - + {addressBookEntry?.data?.name && ( - {ellipsify(toAddress)} - + )} - {t('seedPhraseIntroTitle')} - + - {t('seedPhraseIntroTitleCopy')} - +
From c9729009280920825bd110fb57e7fe8fd7ba8d0f Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:57:19 +0530 Subject: [PATCH 23/60] Update settings-tab.component.js (#18753) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../settings-tab/settings-tab.component.js | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/ui/pages/settings/settings-tab/settings-tab.component.js b/ui/pages/settings/settings-tab/settings-tab.component.js index dc0a5a428..a823478c2 100644 --- a/ui/pages/settings/settings-tab/settings-tab.component.js +++ b/ui/pages/settings/settings-tab/settings-tab.component.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import availableCurrencies from '../../../helpers/constants/available-conversions.json'; import { - TypographyVariant, + TextVariant, TextColor, } from '../../../helpers/constants/design-system'; import Dropdown from '../../../components/ui/dropdown'; @@ -11,7 +11,6 @@ import ToggleButton from '../../../components/ui/toggle-button'; import locales from '../../../../app/_locales/index.json'; import Jazzicon from '../../../components/ui/jazzicon'; import BlockieIdenticon from '../../../components/ui/identicon/blockieIdenticon'; -import Typography from '../../../components/ui/typography'; import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import { @@ -19,6 +18,7 @@ import { handleSettingsRefs, } from '../../../helpers/utils/settings-search'; import { ThemeType } from '../../../../shared/constants/preferences'; +import { Text } from '../../../components/component-library'; const sortedCurrencies = availableCurrencies.sort((a, b) => { return a.name.toLocaleLowerCase().localeCompare(b.name.toLocaleLowerCase()); @@ -195,12 +195,13 @@ export default class SettingsTab extends PureComponent { id="blockie-optin" >
- {t('accountIdenticon')} - + {t('jazzAndBlockies')} @@ -227,16 +228,17 @@ export default class SettingsTab extends PureComponent { style={getIconStyles()} />
- {t('jazzicons')} - +
- {t('blockies')} - +
From 935831658f770ef263641e0183bda59dfeb2903d Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:57:46 +0530 Subject: [PATCH 24/60] Update fee-card.js (#18746) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- ui/pages/swaps/fee-card/fee-card.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/pages/swaps/fee-card/fee-card.js b/ui/pages/swaps/fee-card/fee-card.js index f65c1c164..153174520 100644 --- a/ui/pages/swaps/fee-card/fee-card.js +++ b/ui/pages/swaps/fee-card/fee-card.js @@ -6,15 +6,15 @@ import InfoTooltip from '../../../components/ui/info-tooltip'; import { CHAIN_IDS } from '../../../../shared/constants/network'; import TransactionDetail from '../../../components/app/transaction-detail/transaction-detail.component'; import TransactionDetailItem from '../../../components/app/transaction-detail-item/transaction-detail-item.component'; -import Typography from '../../../components/ui/typography'; import { TextColor, - TypographyVariant, - FONT_WEIGHT, + TextVariant, + FontWeight, } from '../../../helpers/constants/design-system'; import { MetaMetricsContext } from '../../../contexts/metametrics'; import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import { getUseCurrencyRateCheck } from '../../../selectors'; +import { Text } from '../../../components/component-library'; const GAS_FEES_LEARN_MORE_URL = 'https://community.metamask.io/t/what-is-gas-why-do-transactions-take-so-long/3172'; @@ -120,14 +120,14 @@ export default function FeeCard({ (secondaryFee?.maxFee !== undefined || primaryFee?.maxFee !== undefined) && ( <> - {t('maxFee')} - + {useCurrencyRateCheck ? `: ${secondaryFee.maxFee}` : `: ${primaryFee.maxFee}`} From 19d69629577e7a103d816231815ce35ae5b8bdda Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Tue, 25 Apr 2023 18:58:03 +0530 Subject: [PATCH 25/60] Update slippage-buttons.js (#18745) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../swaps/slippage-buttons/slippage-buttons.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/pages/swaps/slippage-buttons/slippage-buttons.js b/ui/pages/swaps/slippage-buttons/slippage-buttons.js index 3040227e3..59a1c2386 100644 --- a/ui/pages/swaps/slippage-buttons/slippage-buttons.js +++ b/ui/pages/swaps/slippage-buttons/slippage-buttons.js @@ -7,15 +7,15 @@ import Button from '../../../components/ui/button'; import InfoTooltip from '../../../components/ui/info-tooltip'; import ToggleButton from '../../../components/ui/toggle-button'; import Box from '../../../components/ui/box'; -import Typography from '../../../components/ui/typography'; import { - TypographyVariant, - FONT_WEIGHT, + TextVariant, + FontWeight, AlignItems, DISPLAY, } from '../../../helpers/constants/design-system'; import { getTranslatedStxErrorMessage } from '../swaps.util'; import { Slippage } from '../../../../shared/constants/swaps'; +import { Text } from '../../../components/component-library'; export default function SlippageButtons({ onSelect, @@ -207,13 +207,14 @@ export default function SlippageButtons({ alignItems={AlignItems.center} paddingRight={3} > - {t('smartTransaction')} - + {currentSmartTransactionsError ? ( Date: Tue, 25 Apr 2023 18:58:22 +0530 Subject: [PATCH 26/60] Part of #17670 for file network-statistics.js (#18644) * Part of #17670 Replace Typography with Text component. * Worked on the mentioned lint issues. * Upgrading to enum version. Co-authored-by: George Marshall * Upgrading to enum version. Co-authored-by: George Marshall --------- Co-authored-by: George Marshall Co-authored-by: George Marshall --- .../network-statistics/network-statistics.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ui/components/app/edit-gas-fee-popover/network-statistics/network-statistics.js b/ui/components/app/edit-gas-fee-popover/network-statistics/network-statistics.js index 43baa0606..6a14f655b 100644 --- a/ui/components/app/edit-gas-fee-popover/network-statistics/network-statistics.js +++ b/ui/components/app/edit-gas-fee-popover/network-statistics/network-statistics.js @@ -1,14 +1,14 @@ import React, { useContext } from 'react'; import { - FONT_WEIGHT, + FontWeight, TextColor, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import { isNullish } from '../../../../helpers/utils/util'; import { formatGasFeeOrFeeRange } from '../../../../helpers/utils/gas'; import { I18nContext } from '../../../../contexts/i18n'; import { useGasFeeContext } from '../../../../contexts/gasFee'; -import Typography from '../../../ui/typography/typography'; +import { Text } from '../../../component-library'; import { BaseFeeTooltip, PriorityFeeTooltip } from './tooltips'; import StatusSlider from './status-slider'; @@ -29,15 +29,16 @@ const NetworkStatistics = () => { return (
- {t('networkStatus')} - +
{isNullish(formattedLatestBaseFee) ? null : (
Date: Tue, 25 Apr 2023 18:59:52 +0530 Subject: [PATCH 27/60] Part of #17670 for file custom-spending-cap-tooltip.js (#18686) * Replaced Typography with Text component in custom-spending-cap-tooltip.js * Worked on a lint issue. * Upgrading to enums. Co-authored-by: George Marshall * Upgrading to enums. * Fixing linting --------- Co-authored-by: George Marshall Co-authored-by: georgewrmarshall From cbe438e70444d58a8b4772b50015aeb7e7233e16 Mon Sep 17 00:00:00 2001 From: Monte Lai Date: Tue, 25 Apr 2023 21:33:43 +0800 Subject: [PATCH 28/60] Update keystone links (#18792) * update keystone links * update tests * fix lint --- app/_locales/en/messages.json | 3 ++ shared/constants/hardware-wallets.ts | 2 +- .../connect-hardware/index.test.tsx | 47 +++++++++++++++---- .../connect-hardware/select-hardware.js | 4 +- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 9330d0a95..1e4675388 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1970,6 +1970,9 @@ "message": "Want to $1 about gas?", "description": "$1 will be replaced by the learnMore translation key" }, + "learnMoreKeystone": { + "message": "Learn More" + }, "learnMoreUpperCase": { "message": "Learn more" }, diff --git a/shared/constants/hardware-wallets.ts b/shared/constants/hardware-wallets.ts index 4f549aa2f..9f5d6ba89 100644 --- a/shared/constants/hardware-wallets.ts +++ b/shared/constants/hardware-wallets.ts @@ -33,7 +33,7 @@ export enum HardwareAffiliateLinks { ledger = 'https://shop.ledger.com/?r=17c4991a03fa', gridplus = 'https://gridplus.io/?afmc=7p', trezor = 'https://shop.trezor.io/product/trezor-one-black?offer_id=35&aff_id=11009', - keystone = 'https://shop.keyst.one/?rfsn=6088257.656b3e9&utm_source=refersion&utm_medium=affiliate&utm_campaign=6088257.656b3e9', + keystone = 'https://keyst.one/metamask?rfsn=6088257.656b3e9&utm_source=refersion&utm_medium=affiliate&utm_campaign=6088257.656b3e9', airgap = 'https://airgap.it/', coolwallet = 'https://www.coolwallet.io/', dcent = 'https://dcentwallet.com/', diff --git a/ui/pages/create-account/connect-hardware/index.test.tsx b/ui/pages/create-account/connect-hardware/index.test.tsx index 770782462..e6f0e6538 100644 --- a/ui/pages/create-account/connect-hardware/index.test.tsx +++ b/ui/pages/create-account/connect-hardware/index.test.tsx @@ -18,25 +18,32 @@ jest.mock('../../../store/actions', () => ({ })); jest.mock('../../../selectors', () => ({ - getCurrentChainId: () => jest.fn().mockResolvedValue('0x1'), - getRpcPrefsForCurrentProvider: () => jest.fn().mockResolvedValue({}), - getMetaMaskAccountsConnected: () => jest.fn().mockResolvedValue([]), - getMetaMaskAccounts: () => jest.fn().mockResolvedValue([]), + getCurrentChainId: () => '0x1', + getRpcPrefsForCurrentProvider: () => { + return {}; + }, + getMetaMaskAccountsConnected: () => [], + getMetaMaskAccounts: () => { + return {}; + }, })); jest.mock('../../../ducks/history/history', () => ({ - getMostRecentOverviewPage: () => jest.fn().mockResolvedValue('/'), + getMostRecentOverviewPage: () => '', })); +const mockTrackEvent = jest.fn(); + const mockProps = { - forgetDevice: jest.fn(), - showAlert: jest.fn(), - hideAlert: jest.fn(), - unlockHardwareWalletAccount: jest.fn(), - setHardwareWalletDefaultHdPath: jest.fn(), + forgetDevice: () => jest.fn(), + showAlert: () => jest.fn(), + hideAlert: () => jest.fn(), + unlockHardwareWalletAccount: () => jest.fn(), + setHardwareWalletDefaultHdPath: () => jest.fn(), history: {}, defaultHdPath: "m/44'/60'/0'/0", mostRecentOverviewPage: '', + trackEvent: () => mockTrackEvent, }; const mockState = { @@ -148,4 +155,24 @@ describe('ConnectHardwareForm', () => { }); }); }); + + describe('QR Hardware Wallet Steps', () => { + it('should render the QR hardware wallet steps', async () => { + const { getByText, getByLabelText } = renderWithProvider( + , + mockStore, + ); + + const qrButton = getByLabelText('QRCode'); + + fireEvent.click(qrButton); + + await waitFor(() => { + expect(getByText('Keystone')).toBeInTheDocument(); + expect(getByText('AirGap Vault')).toBeInTheDocument(); + expect(getByText('CoolWallet')).toBeInTheDocument(); + expect(getByText("D'Cent")).toBeInTheDocument(); + }); + }); + }); }); diff --git a/ui/pages/create-account/connect-hardware/select-hardware.js b/ui/pages/create-account/connect-hardware/select-hardware.js index 9cb027eb9..0ef02d051 100644 --- a/ui/pages/create-account/connect-hardware/select-hardware.js +++ b/ui/pages/create-account/connect-hardware/select-hardware.js @@ -431,12 +431,12 @@ export default class SelectHardware extends Component { onClick={() => { this.context.trackEvent({ category: MetaMetricsEventCategory.Navigation, - event: 'Clicked Keystone Buy Now', + event: 'Clicked Keystone Learn More', }); openWindow(HardwareAffiliateLinks.keystone); }} > - {this.context.t('buyNow')} + {this.context.t('learnMoreKeystone')} +
+
+`; diff --git a/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js new file mode 100644 index 000000000..521274e67 --- /dev/null +++ b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.js @@ -0,0 +1,135 @@ +import React, { useContext } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { MetaMetricsContext } from '../../../contexts/metametrics'; +import { + MetaMetricsEventName, + MetaMetricsEventCategory, +} from '../../../../shared/constants/metametrics'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import withModalProps from '../../../helpers/higher-order-components/with-modal-props'; +import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; +import { mmiActionsFactory } from '../../../store/institutional/institution-background'; +import { hideModal, setSelectedAddress } from '../../../store/actions'; +import { getMetaMaskAccountsRaw } from '../../../selectors'; +import { + getMMIAddressFromModalOrAddress, + getCustodyAccountDetails, + getMMIConfiguration, +} from '../../../selectors/institutional/selectors'; +import Box from '../../ui/box/box'; +import { + AlignItems, + DISPLAY, + FLEX_DIRECTION, + FontWeight, + JustifyContent, + TextAlign, + TextColor, + TextVariant, +} from '../../../helpers/constants/design-system'; +import { Text, Button } from '../../component-library'; + +const CustodyConfirmLink = () => { + const t = useI18nContext(); + const dispatch = useDispatch(); + const mmiActions = mmiActionsFactory(); + const trackEvent = useContext(MetaMetricsContext); + const mmiAccounts = useSelector(getMetaMaskAccountsRaw); + const address = useSelector(getMMIAddressFromModalOrAddress); + const custodyAccountDetails = useSelector(getCustodyAccountDetails); + const { custodians } = useSelector(getMMIConfiguration); + const { custodianName } = + custodyAccountDetails[toChecksumHexAddress(address)] || {}; + const { displayName, iconUrl } = custodians.find( + (item) => item.name === custodianName || {}, + ); + const { url, ethereum, text, action } = useSelector( + (state) => state.appState.modal.modalState.props.link || {}, + ); + + const onClick = () => { + if (url) { + global.platform.openTab({ url }); + } + + if (ethereum) { + const ethAccount = Object.keys(mmiAccounts).find((account) => + ethereum.accounts.includes(account.toLowerCase()), + ); + + ethAccount && dispatch(setSelectedAddress(ethAccount.toLowerCase())); + } + + trackEvent({ + category: MetaMetricsEventCategory.MMI, + event: MetaMetricsEventName.UserClickedDeepLink, + }); + dispatch(mmiActions.setWaitForConfirmDeepLinkDialog(false)); + dispatch(hideModal()); + }; + + return ( + + {iconUrl ? ( + + MMI logo + {'>'} + {custodianName} + + ) : ( + + {custodianName} + + )} + + {t('awaitingApproval')} + + + {text || t('custodyDeeplinkDescription', [displayName])} + + + + ); +}; + +export default withModalProps(CustodyConfirmLink); diff --git a/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.stories.js b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.stories.js new file mode 100644 index 000000000..642bd1d59 --- /dev/null +++ b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.stories.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import configureStore from '../../../store/store'; +import testData from '../../../../.storybook/test-data'; +import CustodyConfirmLink from '.'; + +const customData = { + ...testData, + appState: { + ...testData.appState, + modal: { + modalState: { + props: { + link: { + url: 'test-url', + ethereum: { + accounts: [{}], + }, + text: '', + action: '', + }, + }, + }, + }, + }, + metamask: { + ...testData.metamask, + mmiConfiguration: { + custodians: [ + { + refreshTokenUrl: + 'https://saturn-custody.dev.metamask-institutional.io/oauth/token', + name: 'saturn-dev', + displayName: 'Saturn Custody', + enabled: true, + mmiApiUrl: 'https://api.dev.metamask-institutional.io/v1', + websocketApiUrl: + 'wss://websocket.dev.metamask-institutional.io/v1/ws', + apiBaseUrl: + 'https://saturn-custody.dev.metamask-institutional.io/eth', + iconUrl: + 'https://saturn-custody-ui.dev.metamask-institutional.io/saturn.svg', + isNoteToTraderSupported: true, + }, + ], + }, + custodyAccountDetails: { + '0xAddress': { + address: '0xAddress', + details: 'details', + custodyType: 'testCustody - Saturn', + custodianName: 'saturn-dev', + }, + }, + provider: { + type: 'test', + }, + selectedAddress: '0xAddress', + }, +}; + +const store = configureStore(customData); + +export default { + title: 'Components/Institutional/CustodyConfirmLink', + decorators: [(story) => {story()}], + component: CustodyConfirmLink, + args: {}, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'CustodyConfirmLink'; diff --git a/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.test.js b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.test.js new file mode 100644 index 000000000..c659623a9 --- /dev/null +++ b/ui/components/institutional/custody-confirm-link-modal/custody-confirm-link-modal.test.js @@ -0,0 +1,192 @@ +import React from 'react'; +import { fireEvent } from '@testing-library/react'; +import configureStore from 'redux-mock-store'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import testData from '../../../../.storybook/test-data'; +import { hideModal } from '../../../store/actions'; +import CustodyConfirmLink from '.'; + +const mockedSetWaitForConfirmDeepLinkDialog = jest + .fn() + .mockReturnValue({ type: 'TYPE' }); +jest.mock('../../../store/institutional/institution-background', () => ({ + mmiActionsFactory: () => ({ + setWaitForConfirmDeepLinkDialog: mockedSetWaitForConfirmDeepLinkDialog, + }), +})); + +jest.mock('../../../store/actions', () => ({ + hideModal: jest.fn().mockReturnValue({ type: 'TYPE' }), +})); + +const mockedCustodianName = 'saturn-dev'; + +describe('Custody Confirm Link', () => { + const mockStore = { + ...testData, + appState: { + ...testData.appState, + modal: { + modalState: { + props: { + link: { + url: 'test-url', + ethereum: { + accounts: [{}], + }, + text: '', + action: '', + }, + }, + }, + }, + }, + metamask: { + ...testData.metamask, + mmiConfiguration: { + custodians: [ + { + refreshTokenUrl: + 'https://saturn-custody.dev.metamask-institutional.io/oauth/token', + name: 'saturn-dev', + displayName: 'Saturn Custody', + enabled: true, + mmiApiUrl: 'https://api.dev.metamask-institutional.io/v1', + websocketApiUrl: + 'wss://websocket.dev.metamask-institutional.io/v1/ws', + apiBaseUrl: + 'https://saturn-custody.dev.metamask-institutional.io/eth', + iconUrl: + 'https://saturn-custody-ui.dev.metamask-institutional.io/saturn.svg', + isNoteToTraderSupported: true, + }, + ], + }, + custodyAccountDetails: { + '0xAddress': { + address: '0xAddress', + details: 'details', + custodyType: 'testCustody - Saturn', + custodianName: mockedCustodianName, + }, + }, + provider: { + type: 'test', + }, + selectedAddress: '0xAddress', + }, + }; + + let store = configureStore()(mockStore); + + it('tries to open new tab with deeplink URL', () => { + global.platform = { openTab: jest.fn() }; + const { getByRole } = renderWithProvider(, store); + fireEvent.click(getByRole('button')); + expect(global.platform.openTab).toHaveBeenCalledWith({ + url: 'test-url', + }); + expect(mockedSetWaitForConfirmDeepLinkDialog).toHaveBeenCalledWith(false); + expect(hideModal).toHaveBeenCalledTimes(1); + }); + + it('should match snapshot', () => { + const { container } = renderWithProvider(, store); + + expect(container).toMatchSnapshot(); + }); + + it('shows custodian name when iconUrl is undefined', () => { + const customMockStore = { + ...mockStore, + metamask: { + ...testData.metamask, + ...mockStore.metamask, + mmiConfiguration: { + custodians: [ + { + refreshTokenUrl: + 'https://saturn-custody.dev.metamask-institutional.io/oauth/token', + name: 'saturn-dev', + displayName: 'Saturn Custody', + enabled: true, + mmiApiUrl: 'https://api.dev.metamask-institutional.io/v1', + websocketApiUrl: + 'wss://websocket.dev.metamask-institutional.io/v1/ws', + apiBaseUrl: + 'https://saturn-custody.dev.metamask-institutional.io/eth', + iconUrl: null, + isNoteToTraderSupported: true, + }, + ], + }, + }, + }; + + store = configureStore()(customMockStore); + + const { getByText } = renderWithProvider(, store); + + expect(getByText(mockedCustodianName)).toBeVisible(); + }); + + it('shows text that comes from modal state if defined', () => { + const mockModalStateText = 'test modal state text'; + const customMockStore = { + ...mockStore, + appState: { + ...testData.appState, + modal: { + modalState: { + props: { + link: { + url: 'test-url', + ethereum: { + accounts: [{}], + }, + text: mockModalStateText, + action: '', + }, + }, + }, + }, + }, + }; + + store = configureStore()(customMockStore); + + const { getByText } = renderWithProvider(, store); + + expect(getByText(mockModalStateText)).toBeVisible(); + }); + + it('shows action text that comes from modal state if defined', () => { + const mockModalStateActionText = 'test modal state action text'; + const customMockStore = { + ...mockStore, + appState: { + ...testData.appState, + modal: { + modalState: { + props: { + link: { + url: 'test-url', + ethereum: { + accounts: [{}], + }, + text: '', + action: mockModalStateActionText, + }, + }, + }, + }, + }, + }; + + store = configureStore()(customMockStore); + + const { getByText } = renderWithProvider(, store); + + expect(getByText(mockModalStateActionText)).toBeVisible(); + }); +}); diff --git a/ui/components/institutional/custody-confirm-link-modal/index.js b/ui/components/institutional/custody-confirm-link-modal/index.js new file mode 100644 index 000000000..da3cf4bc2 --- /dev/null +++ b/ui/components/institutional/custody-confirm-link-modal/index.js @@ -0,0 +1,3 @@ +import CustodyConfirmLink from './custody-confirm-link-modal'; + +export default CustodyConfirmLink; diff --git a/ui/components/institutional/custody-confirm-link-modal/index.scss b/ui/components/institutional/custody-confirm-link-modal/index.scss new file mode 100644 index 000000000..f9771d761 --- /dev/null +++ b/ui/components/institutional/custody-confirm-link-modal/index.scss @@ -0,0 +1,18 @@ +.custody-confirm-link { + &__description { + border-bottom: 1px solid var(--brand-colors-grey-grey200); + } + + &__img { + margin: 0 20px; + display: block; + padding: 20px 0; + width: 45px; + text-align: center; + } + + &__btn { + width: 300px !important; + margin: 20px auto; + } +} diff --git a/ui/selectors/institutional/selectors.js b/ui/selectors/institutional/selectors.js index b40fe9833..b45786188 100644 --- a/ui/selectors/institutional/selectors.js +++ b/ui/selectors/institutional/selectors.js @@ -63,6 +63,17 @@ export function getIsCustodianSupportedChain(state) { : true; } +export function getMMIAddressFromModalOrAddress(state) { + return ( + state.appState.modal.modalState.props.address || + state.metamask.selectedAddress + ); +} + +export function getMMIConfiguration(state) { + return state.metamask.mmiConfiguration; +} + export function getInteractiveReplacementToken(state) { return state.metamask.interactiveReplacementToken || {}; } From 95c37e1ba35317bffafbef5194259a95dbfc1601 Mon Sep 17 00:00:00 2001 From: Olaf Tomalka Date: Tue, 25 Apr 2023 21:32:51 +0700 Subject: [PATCH 30/60] feat: add yaml feature management (#18125) * feat: add yaml feature management Add yaml feature file per build type. Also add method to parse yaml and set enabled features env to true. The build process will then replace any process.env[feature] that exists on the config by its value * chore: add example for desktop * Added initial draft of build features * [TMP] Sync between computers * Is able to succesfully build stable extension with snaps feature * Removing var context from builds.yml * Add asssets to builds.yml * Minor bug fixes and removing debug logs * [WIP] Test changes * Removed TODOs * Fix regession bug Also * remove debug logs * merge Variables.set and Variables.setMany with an overload * Fix build, lint and a bunch of issues * Update LavaMoat policies * Re-add desktop build type * Fix some tests * Fix desktop build * Define some env variables used by MV3 * Fix lint * Fix remove-fenced-code tests * Fix README typo * Move new code * Fix missing asset copy * Move Jest env setup * Fix path for test after rebase * Fix code fences * Fix fencing and LavaMoat policies * Fix MMI code-fencing after rebase * Fix MMI code fencing after merge * Fix more MMI code fencing --------- Co-authored-by: cryptotavares Co-authored-by: Frederik Bolding Co-authored-by: Brad Decker --- .metamaskrc.dist | 18 +- app/scripts/background.js | 16 +- app/scripts/controllers/metametrics.js | 2 +- .../controllers/network/network-controller.ts | 2 +- app/scripts/controllers/permissions/index.js | 4 +- .../{flask => snaps}/snap-permissions.js | 0 .../{flask => snaps}/snap-permissions.test.js | 0 .../controllers/permissions/specifications.js | 4 +- .../createMethodMiddleware.js | 4 +- app/scripts/lib/setupSentry.js | 3 +- app/scripts/metamask-controller.js | 63 ++-- app/scripts/platforms/extension.js | 2 +- app/scripts/ui.js | 16 +- builds.yml | 214 +++++++++++++ development/build/config.js | 226 ++++++++------ development/build/etc.js | 4 +- development/build/index.js | 63 ++-- development/build/manifest.js | 23 +- development/build/scripts.js | 218 ++++++++----- development/build/static.js | 54 ++-- development/build/transforms/README.md | 6 +- .../build/transforms/remove-fenced-code.d.ts | 4 + .../build/transforms/remove-fenced-code.js | 89 +++--- .../transforms/remove-fenced-code.test.js | 290 +++++++++++------- development/build/utils.js | 13 +- development/generate-lavamoat-policies.js | 10 +- development/lib/build-type.d.ts | 6 + development/lib/build-type.js | 179 ++++++++++- development/lib/get-version.js | 10 +- development/lib/variables.js | 114 +++++++ development/sentry-publish.js | 8 +- lavamoat/browserify/beta/policy.json | 29 +- lavamoat/browserify/desktop/policy.json | 44 ++- lavamoat/browserify/flask/policy.json | 44 ++- lavamoat/browserify/main/policy.json | 29 +- package.json | 1 + shared/constants/app.ts | 20 +- shared/constants/environment.js | 2 - shared/constants/metametrics.ts | 4 +- shared/constants/permissions.ts | 4 +- shared/constants/snaps.ts | 2 +- shared/constants/transaction.ts | 2 +- shared/lib/error-utils.js | 10 +- shared/lib/ui-utils.js | 14 +- test/env.js | 3 +- .../account-menu/account-menu.component.js | 12 +- .../account-menu/account-menu.container.js | 6 +- .../app/account-menu/keyring-label.js | 2 +- ui/components/app/app-components.scss | 18 +- .../app/app-header/app-header.component.js | 26 +- .../app/app-header/app-header.container.js | 16 +- ...onfirm-page-container-content.component.js | 10 +- .../confirm-page-container.component.js | 8 +- .../app/confirm-page-container/index.js | 4 +- .../app/confirm-page-container/index.scss | 4 +- .../{flask => snaps}/index.js | 0 .../{flask => snaps}/index.scss | 0 .../{flask => snaps}/snap-insight.js | 8 +- .../safe-component-list.js | 10 +- .../permission-page-container.component.js | 12 +- .../permission-page-container.container.js | 6 +- .../permissions-connect-header.component.js | 16 +- .../signature-request-original.component.js | 10 +- .../signature-request-original.container.js | 4 +- .../signature-request.component.js | 10 +- .../signature-request.container.js | 4 +- .../app/{flask => snaps}/copyable/copyable.js | 0 .../app/{flask => snaps}/copyable/index.js | 0 .../app/{flask => snaps}/copyable/index.scss | 0 .../{flask => snaps}/install-error/index.js | 0 .../install-error/install-error.js | 0 .../{flask => snaps}/snap-authorship/index.js | 0 .../snap-authorship/snap-authorship.js | 0 .../snap-authorship.stories.js | 0 .../app/{flask => snaps}/snap-avatar/index.js | 0 .../snap-avatar/snap-avatar.js | 0 .../snap-avatar/snap-avatar.stories.js | 0 .../snap-content-footer/index.js | 0 .../snap-content-footer/index.scss | 0 .../snap-content-footer.js | 0 .../snap-content-footer.stories.js | 0 .../{flask => snaps}/snap-delineator/index.js | 0 .../snap-delineator/index.scss | 0 .../snap-delineator/snap-delineator.js | 0 .../snap-delineator.stories.js | 0 .../snap-delineator/snap-delineator.test.js | 0 .../snap-install-warning/index.js | 0 .../snap-install-warning/index.scss | 0 .../snap-install-warning.js | 0 .../snap-permissions-list/index.js | 0 .../snap-permissions-list.js | 0 .../snap-permissions-list.stories.js | 0 .../snap-permissions-list.test.js | 0 .../snap-remove-warning/index.js | 0 .../snap-remove-warning/index.scss | 0 .../snap-remove-warning.js | 0 .../snap-settings-card/README.mdx | 0 .../snap-settings-card/index.js | 0 .../snap-settings-card/index.scss | 0 .../snap-settings-card/snap-settings-card.js | 0 .../snap-settings-card.stories.js | 0 .../snap-settings-card.test.js | 0 .../snap-ui-markdown/index.js | 0 .../snap-ui-markdown/index.scss | 0 .../snap-ui-markdown/snap-ui-markdown.js | 0 .../snap-ui-renderer/index.js | 0 .../snap-ui-renderer/index.scss | 0 .../snap-ui-renderer/snap-ui-renderer.js | 0 .../snap-ui-renderer.stories.js | 0 .../snap-ui-renderer/snap-ui-renderer.test.js | 0 .../update-snap-permission-list/index.js | 0 .../update-snap-permission-list/index.scss | 0 .../update-snap-permission-list.js | 0 .../update-snap-permission-list.stories.js | 0 .../app/wallet-overview/eth-overview.js | 12 +- .../ui/metafox-logo/metafox-logo.component.js | 6 +- .../dropdown-tab/dropdown-tab.js | 0 .../dropdown-tab/dropdown-tab.test.js | 0 .../{flask => snaps}/dropdown-tab/index.js | 0 ui/components/ui/tabs/tabs.stories.js | 2 +- ui/ducks/metamask/metamask.js | 2 +- ui/helpers/constants/common.ts | 16 +- ui/helpers/constants/notifications.ts | 2 +- ui/helpers/constants/routes.ts | 20 +- ui/helpers/constants/settings.js | 4 +- ui/helpers/utils/build-types.js | 18 +- ui/helpers/utils/permission.js | 12 +- ui/helpers/utils/util.js | 6 +- .../useTransactionInsightSnap.js | 0 ui/hooks/useTransactionInsights.js | 4 +- ui/index.js | 6 +- ui/pages/confirm-signature-request/index.js | 6 +- ui/pages/confirmation/confirmation.js | 18 +- ui/pages/confirmation/confirmation.scss | 2 +- ui/pages/confirmation/templates/index.js | 10 +- .../{flask => snaps}/snap-alert/snap-alert.js | 2 +- .../snap-confirmation/snap-confirmation.js | 2 +- .../{flask => snaps}/snap-prompt/index.scss | 0 .../snap-prompt/snap-prompt.js | 2 +- .../connect-hardware/select-hardware.js | 2 +- .../desktop-error/render-desktop-error.js | 2 +- ui/pages/home/home.component.js | 20 +- ui/pages/home/home.container.js | 10 +- .../onboarding-flow-switch.js | 11 +- ui/pages/onboarding-flow/onboarding-flow.js | 6 +- .../onboarding-flow/onboarding-flow.test.js | 2 +- ui/pages/permissions-connect/index.scss | 6 +- .../permissions-connect.component.js | 48 +-- .../permissions-connect.container.js | 20 +- .../{flask => snaps}/snap-install/index.js | 0 .../{flask => snaps}/snap-install/index.scss | 0 .../snap-install/snap-install.js | 8 +- .../{flask => snaps}/snap-result/index.js | 0 .../{flask => snaps}/snap-result/index.scss | 0 .../snap-result/snap-result.js | 4 +- .../{flask => snaps}/snap-update/index.js | 0 .../{flask => snaps}/snap-update/index.scss | 0 .../snap-update/snap-update.js | 8 +- .../{flask => snaps}/util.js | 0 ui/pages/routes/routes.component.js | 22 +- .../advanced-tab/advanced-tab.component.js | 6 +- .../advanced-tab/advanced-tab.container.js | 4 +- .../experimental-tab.component.js | 6 +- ui/pages/settings/index.scss | 4 +- .../settings/info-tab/info-tab.component.js | 14 +- .../settings-search/settings-search.js | 6 +- ui/pages/settings/settings.component.js | 14 +- .../{flask => snaps}/snaps-list-tab/index.js | 0 .../snaps-list-tab/index.scss | 0 .../snaps-list-tab/snap-list-tab.js | 2 +- .../snaps-list-tab/snap-list-tab.stories.js | 0 .../{flask => snaps}/view-snap/index.js | 0 .../{flask => snaps}/view-snap/index.scss | 0 .../{flask => snaps}/view-snap/view-snap.js | 6 +- .../view-snap/view-snap.test.js | 0 .../swaps/awaiting-swap/awaiting-swap.test.js | 2 +- .../__snapshots__/unlock-page.test.js.snap | 2 +- ui/selectors/permissions.js | 6 +- ui/selectors/selectors.js | 20 +- ui/store/actionConstants.ts | 2 +- ui/store/actions.ts | 19 +- ui/store/store.ts | 4 +- yarn.lock | 1 + 183 files changed, 1565 insertions(+), 933 deletions(-) rename app/scripts/controllers/permissions/{flask => snaps}/snap-permissions.js (100%) rename app/scripts/controllers/permissions/{flask => snaps}/snap-permissions.test.js (100%) create mode 100644 builds.yml create mode 100644 development/build/transforms/remove-fenced-code.d.ts create mode 100644 development/lib/build-type.d.ts create mode 100644 development/lib/variables.js delete mode 100644 shared/constants/environment.js rename ui/components/app/confirm-page-container/{flask => snaps}/index.js (100%) rename ui/components/app/confirm-page-container/{flask => snaps}/index.scss (100%) rename ui/components/app/confirm-page-container/{flask => snaps}/snap-insight.js (92%) rename ui/components/app/{flask => snaps}/copyable/copyable.js (100%) rename ui/components/app/{flask => snaps}/copyable/index.js (100%) rename ui/components/app/{flask => snaps}/copyable/index.scss (100%) rename ui/components/app/{flask => snaps}/install-error/index.js (100%) rename ui/components/app/{flask => snaps}/install-error/install-error.js (100%) rename ui/components/app/{flask => snaps}/snap-authorship/index.js (100%) rename ui/components/app/{flask => snaps}/snap-authorship/snap-authorship.js (100%) rename ui/components/app/{flask => snaps}/snap-authorship/snap-authorship.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-avatar/index.js (100%) rename ui/components/app/{flask => snaps}/snap-avatar/snap-avatar.js (100%) rename ui/components/app/{flask => snaps}/snap-avatar/snap-avatar.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-content-footer/index.js (100%) rename ui/components/app/{flask => snaps}/snap-content-footer/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-content-footer/snap-content-footer.js (100%) rename ui/components/app/{flask => snaps}/snap-content-footer/snap-content-footer.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-delineator/index.js (100%) rename ui/components/app/{flask => snaps}/snap-delineator/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-delineator/snap-delineator.js (100%) rename ui/components/app/{flask => snaps}/snap-delineator/snap-delineator.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-delineator/snap-delineator.test.js (100%) rename ui/components/app/{flask => snaps}/snap-install-warning/index.js (100%) rename ui/components/app/{flask => snaps}/snap-install-warning/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-install-warning/snap-install-warning.js (100%) rename ui/components/app/{flask => snaps}/snap-permissions-list/index.js (100%) rename ui/components/app/{flask => snaps}/snap-permissions-list/snap-permissions-list.js (100%) rename ui/components/app/{flask => snaps}/snap-permissions-list/snap-permissions-list.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-permissions-list/snap-permissions-list.test.js (100%) rename ui/components/app/{flask => snaps}/snap-remove-warning/index.js (100%) rename ui/components/app/{flask => snaps}/snap-remove-warning/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-remove-warning/snap-remove-warning.js (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/README.mdx (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/index.js (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/snap-settings-card.js (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/snap-settings-card.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-settings-card/snap-settings-card.test.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-markdown/index.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-markdown/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-ui-markdown/snap-ui-markdown.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-renderer/index.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-renderer/index.scss (100%) rename ui/components/app/{flask => snaps}/snap-ui-renderer/snap-ui-renderer.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-renderer/snap-ui-renderer.stories.js (100%) rename ui/components/app/{flask => snaps}/snap-ui-renderer/snap-ui-renderer.test.js (100%) rename ui/components/app/{flask => snaps}/update-snap-permission-list/index.js (100%) rename ui/components/app/{flask => snaps}/update-snap-permission-list/index.scss (100%) rename ui/components/app/{flask => snaps}/update-snap-permission-list/update-snap-permission-list.js (100%) rename ui/components/app/{flask => snaps}/update-snap-permission-list/update-snap-permission-list.stories.js (100%) rename ui/components/ui/tabs/{flask => snaps}/dropdown-tab/dropdown-tab.js (100%) rename ui/components/ui/tabs/{flask => snaps}/dropdown-tab/dropdown-tab.test.js (100%) rename ui/components/ui/tabs/{flask => snaps}/dropdown-tab/index.js (100%) rename ui/hooks/{flask => snaps}/useTransactionInsightSnap.js (100%) rename ui/pages/confirmation/templates/{flask => snaps}/snap-alert/snap-alert.js (91%) rename ui/pages/confirmation/templates/{flask => snaps}/snap-confirmation/snap-confirmation.js (92%) rename ui/pages/confirmation/templates/{flask => snaps}/snap-prompt/index.scss (100%) rename ui/pages/confirmation/templates/{flask => snaps}/snap-prompt/snap-prompt.js (95%) rename ui/pages/permissions-connect/{flask => snaps}/snap-install/index.js (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-install/index.scss (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-install/snap-install.js (95%) rename ui/pages/permissions-connect/{flask => snaps}/snap-result/index.js (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-result/index.scss (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-result/snap-result.js (96%) rename ui/pages/permissions-connect/{flask => snaps}/snap-update/index.js (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-update/index.scss (100%) rename ui/pages/permissions-connect/{flask => snaps}/snap-update/snap-update.js (96%) rename ui/pages/permissions-connect/{flask => snaps}/util.js (100%) rename ui/pages/settings/{flask => snaps}/snaps-list-tab/index.js (100%) rename ui/pages/settings/{flask => snaps}/snaps-list-tab/index.scss (100%) rename ui/pages/settings/{flask => snaps}/snaps-list-tab/snap-list-tab.js (98%) rename ui/pages/settings/{flask => snaps}/snaps-list-tab/snap-list-tab.stories.js (100%) rename ui/pages/settings/{flask => snaps}/view-snap/index.js (100%) rename ui/pages/settings/{flask => snaps}/view-snap/index.scss (100%) rename ui/pages/settings/{flask => snaps}/view-snap/view-snap.js (97%) rename ui/pages/settings/{flask => snaps}/view-snap/view-snap.test.js (100%) diff --git a/.metamaskrc.dist b/.metamaskrc.dist index d430e090f..d00289cdb 100644 --- a/.metamaskrc.dist +++ b/.metamaskrc.dist @@ -1,11 +1,15 @@ ; Extra environment variables -PASSWORD=METAMASK PASSWORD +; Defaults are set in builds.yml + +; This variable is required INFURA_PROJECT_ID=00000000000 -SEGMENT_WRITE_KEY= -SWAPS_USE_DEV_APIS= -PORTFOLIO_URL= -TRANSACTION_SECURITY_PROVIDER= -MULTICHAIN= + +;PASSWORD=METAMASK PASSWORD +,SEGMENT_WRITE_KEY= +;SWAPS_USE_DEV_APIS= +;PORTFOLIO_URL= +;TRANSACTION_SECURITY_PROVIDER= +;MULTICHAIN= ; Set this to test changes to the phishing warning page. -PHISHING_WARNING_PAGE_URL= +;PHISHING_WARNING_PAGE_URL= diff --git a/app/scripts/background.js b/app/scripts/background.js index b10511d24..dceea1b5e 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -18,7 +18,7 @@ import { ENVIRONMENT_TYPE_FULLSCREEN, EXTENSION_MESSAGES, PLATFORM_FIREFOX, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) MESSAGE_TYPE, ///: END:ONLY_INCLUDE_IN } from '../../shared/constants/app'; @@ -55,7 +55,7 @@ import { deferredPromise, getPlatform } from './lib/util'; /* eslint-enable import/first */ /* eslint-disable import/order */ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import { CONNECTION_TYPE_EXTERNAL, CONNECTION_TYPE_INTERNAL, @@ -105,7 +105,7 @@ const PHISHING_WARNING_PAGE_TIMEOUT = ONE_SECOND_IN_MILLISECONDS; const ACK_KEEP_ALIVE_MESSAGE = 'ACK_KEEP_ALIVE_MESSAGE'; const WORKER_KEEP_ALIVE_MESSAGE = 'WORKER_KEEP_ALIVE_MESSAGE'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) const OVERRIDE_ORIGIN = { EXTENSION: 'EXTENSION', DESKTOP: 'DESKTOP_APP', @@ -263,7 +263,7 @@ async function initialize() { const initState = await loadStateFromPersistence(); const initLangCode = await getFirstPreferredLangCode(); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) await DesktopManager.init(platform.getVersion()); ///: END:ONLY_INCLUDE_IN @@ -525,7 +525,7 @@ export function setupController( * @param {Port} remotePort - The port provided by a new context. */ connectRemote = async (remotePort) => { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) if ( DesktopManager.isDesktopEnabled() && OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.() @@ -651,7 +651,7 @@ export function setupController( // communication with page or other extension connectExternal = (remotePort) => { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) if ( DesktopManager.isDesktopEnabled() && OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.() @@ -769,7 +769,7 @@ export function setupController( Object.values(controller.approvalController.state.pendingApprovals).forEach( ({ id, type }) => { switch (type) { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) case MESSAGE_TYPE.SNAP_DIALOG_ALERT: case MESSAGE_TYPE.SNAP_DIALOG_PROMPT: controller.approvalController.accept(id, null); @@ -791,7 +791,7 @@ export function setupController( updateBadge(); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) if (OVERRIDE_ORIGIN.DESKTOP !== overrides?.getOrigin?.()) { controller.store.subscribe((state) => { DesktopManager.setState(state); diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index c433b3f5e..23f74b21d 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -724,7 +724,7 @@ export default class MetaMetricsController { [MetaMetricsUserTrait.Theme]: metamaskState.theme || 'default', [MetaMetricsUserTrait.TokenDetectionEnabled]: metamaskState.useTokenDetection, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) [MetaMetricsUserTrait.DesktopEnabled]: metamaskState.desktopEnabled || false, ///: END:ONLY_INCLUDE_IN diff --git a/app/scripts/controllers/network/network-controller.ts b/app/scripts/controllers/network/network-controller.ts index 545e47ccc..51c6fad21 100644 --- a/app/scripts/controllers/network/network-controller.ts +++ b/app/scripts/controllers/network/network-controller.ts @@ -327,7 +327,7 @@ function buildDefaultProviderConfigState(): ProviderConfiguration { }; } else if ( process.env.METAMASK_DEBUG || - process.env.METAMASK_ENV === 'test' + process.env.METAMASK_ENVIRONMENT === 'test' ) { return { type: NETWORK_TYPES.GOERLI, diff --git a/app/scripts/controllers/permissions/index.js b/app/scripts/controllers/permissions/index.js index c091882ad..bcc708439 100644 --- a/app/scripts/controllers/permissions/index.js +++ b/app/scripts/controllers/permissions/index.js @@ -4,6 +4,6 @@ export * from './enums'; export * from './permission-log'; export * from './specifications'; export * from './selectors'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -export * from './flask/snap-permissions'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +export * from './snaps/snap-permissions'; ///: END:ONLY_INCLUDE_IN diff --git a/app/scripts/controllers/permissions/flask/snap-permissions.js b/app/scripts/controllers/permissions/snaps/snap-permissions.js similarity index 100% rename from app/scripts/controllers/permissions/flask/snap-permissions.js rename to app/scripts/controllers/permissions/snaps/snap-permissions.js diff --git a/app/scripts/controllers/permissions/flask/snap-permissions.test.js b/app/scripts/controllers/permissions/snaps/snap-permissions.test.js similarity index 100% rename from app/scripts/controllers/permissions/flask/snap-permissions.test.js rename to app/scripts/controllers/permissions/snaps/snap-permissions.test.js diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 4072398d1..b6f23d4be 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -2,7 +2,7 @@ import { constructPermission, PermissionType, } from '@metamask/permission-controller'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { endowmentCaveatSpecifications as snapsEndowmentCaveatSpecifications } from '@metamask/snaps-controllers'; import { caveatSpecifications as snapsCaveatsSpecifications } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN @@ -71,7 +71,7 @@ export const getCaveatSpecifications = ({ getIdentities }) => { validateCaveatAccounts(caveat.value, getIdentities), }, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) ...snapsCaveatsSpecifications, ...snapsEndowmentCaveatSpecifications, ///: END:ONLY_INCLUDE_IN diff --git a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js index 8815b6556..79e1ce64d 100644 --- a/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js +++ b/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { handlers as permittedSnapMethods } from '@metamask/rpc-methods/dist/permitted'; ///: END:ONLY_INCLUDE_IN import { permissionRpcMethods } from '@metamask/permission-controller'; @@ -72,7 +72,7 @@ export function createMethodMiddleware(hooks) { }; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) const snapHandlerMap = permittedSnapMethods.reduce((map, handler) => { for (const methodName of handler.methodNames) { map.set(methodName, handler); diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index bc0150b84..03241b288 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -1,7 +1,6 @@ import * as Sentry from '@sentry/browser'; import { Dedupe, ExtraErrorData } from '@sentry/integrations'; -import { BuildType } from '../../../shared/constants/app'; import { FilterEvents } from './sentry-filter-events'; import extractEthjsErrorMessage from './extractEthjsErrorMessage'; @@ -90,7 +89,7 @@ export default function setupSentry({ release, getState }) { } const environment = - METAMASK_BUILD_TYPE === BuildType.main + METAMASK_BUILD_TYPE === 'main' ? METAMASK_ENVIRONMENT : `${METAMASK_ENVIRONMENT}-${METAMASK_BUILD_TYPE}`; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 494dd3c86..a789ae227 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -48,12 +48,12 @@ import { SubjectMetadataController, SubjectType, } from '@metamask/subject-metadata-controller'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { RateLimitController } from '@metamask/rate-limit-controller'; import { NotificationController } from '@metamask/notification-controller'; ///: END:ONLY_INCLUDE_IN import SmartTransactionsController from '@metamask/smart-transactions-controller'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { CronjobController, JsonSnapsRegistry, @@ -83,7 +83,7 @@ import { KeyringType } from '../../shared/constants/keyring'; import { CaveatTypes, RestrictedMethods, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) EndowmentPermissions, ExcludedSnapPermissions, ExcludedSnapEndowments, @@ -95,7 +95,7 @@ import { MILLISECOND, SECOND } from '../../shared/constants/time'; import { ORIGIN_METAMASK, MESSAGE_TYPE, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) SNAP_DIALOG_TYPES, ///: END:ONLY_INCLUDE_IN POLLING_TOKEN_ENVIRONMENT_TYPES, @@ -115,8 +115,7 @@ import { STATIC_MAINNET_TOKEN_LIST } from '../../shared/constants/tokens'; import { getTokenValueParam } from '../../shared/lib/metamask-controller-utils'; import { isManifestV3 } from '../../shared/modules/mv3.utils'; import { hexToDecimal } from '../../shared/modules/conversion.utils'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -import { isMain, isFlask } from '../../shared/constants/environment'; +///: BEGIN:ONLY_INCLUDE_IN(desktop) // eslint-disable-next-line import/order import { DesktopController } from '@metamask/desktop/dist/controllers/desktop'; ///: END:ONLY_INCLUDE_IN @@ -131,7 +130,7 @@ import createDupeReqFilterMiddleware from './lib/createDupeReqFilterMiddleware'; import createLoggerMiddleware from './lib/createLoggerMiddleware'; import { createMethodMiddleware, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) createSnapMethodMiddleware, ///: END:ONLY_INCLUDE_IN } from './lib/rpc-method-middleware'; @@ -175,7 +174,7 @@ import { NOTIFICATION_NAMES, PermissionLogController, unrestrictedMethods, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) buildSnapEndowmentSpecifications, buildSnapRestrictedMethodSpecifications, ///: END:ONLY_INCLUDE_IN @@ -786,7 +785,7 @@ export default class MetamaskController extends EventEmitter { ); }, }), - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) ...this.getSnapPermissionSpecifications(), ///: END:ONLY_INCLUDE_IN }, @@ -807,7 +806,7 @@ export default class MetamaskController extends EventEmitter { subjectCacheLimit: 100, }); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const snapExecutionServiceArgs = { iframeUrl: new URL('https://execution.metamask.io/0.15.1/index.html'), messenger: this.controllerMessenger.getRestricted({ @@ -852,6 +851,9 @@ export default class MetamaskController extends EventEmitter { ], }); + const allowLocalSnaps = process.env.ALLOW_LOCAL_SNAPS; + const requireAllowlist = process.env.REQUIRE_SNAPS_ALLOWLIST; + this.snapController = new SnapController({ environmentEndowmentPermissions: Object.values(EndowmentPermissions), excludedPermissions: { @@ -863,8 +865,8 @@ export default class MetamaskController extends EventEmitter { messenger: snapControllerMessenger, featureFlags: { dappsCanUpdateSnaps: true, - allowLocalSnaps: isFlask, - requireAllowlist: isMain, + allowLocalSnaps, + requireAllowlist, }, }); @@ -933,8 +935,8 @@ export default class MetamaskController extends EventEmitter { this.snapsRegistry = new JsonSnapsRegistry({ state: initState.SnapsRegistry, messenger: snapsRegistryMessenger, - refetchOnAllowlistMiss: isMain, - failOnUnavailableRegistry: isMain, + refetchOnAllowlistMiss: requireAllowlist, + failOnUnavailableRegistry: requireAllowlist, url: { registry: 'https://acl.execution.metamask.io/latest/registry.json', signature: 'https://acl.execution.metamask.io/latest/signature.json', @@ -943,6 +945,9 @@ export default class MetamaskController extends EventEmitter { '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6', }); + ///: END:ONLY_INCLUDE_IN + + ///: BEGIN:ONLY_INCLUDE_IN(desktop) this.desktopController = new DesktopController({ initState: initState.DesktopController, }); @@ -1374,11 +1379,13 @@ export default class MetamaskController extends EventEmitter { SmartTransactionsController: this.smartTransactionsController, NftController: this.nftController, PhishingController: this.phishingController, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, SnapsRegistry: this.snapsRegistry, NotificationController: this.notificationController, + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) DesktopController: this.desktopController.store, ///: END:ONLY_INCLUDE_IN ...resetOnRestartStore, @@ -1408,11 +1415,13 @@ export default class MetamaskController extends EventEmitter { TokensController: this.tokensController, SmartTransactionsController: this.smartTransactionsController, NftController: this.nftController, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, SnapsRegistry: this.snapsRegistry, NotificationController: this.notificationController, + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) DesktopController: this.desktopController.store, ///: END:ONLY_INCLUDE_IN ...resetOnRestartStore, @@ -1504,7 +1513,7 @@ export default class MetamaskController extends EventEmitter { } canUseHardwareWallets() { - return !isManifestV3 || process.env.CONF?.HARDWARE_WALLETS_MV3; + return !isManifestV3 || process.env.HARDWARE_WALLETS_MV3; } resetStates(resetMethods) { @@ -1517,7 +1526,7 @@ export default class MetamaskController extends EventEmitter { }); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * Constructor helper for getting Snap permission specifications. */ @@ -1659,7 +1668,7 @@ export default class MetamaskController extends EventEmitter { getPermittedAccountsByOrigin, ); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) // Record Snap metadata whenever a Snap is added to state. this.controllerMessenger.subscribe( `${this.snapController.name}:snapAdded`, @@ -2165,7 +2174,7 @@ export default class MetamaskController extends EventEmitter { rejectPermissionsRequest: this.rejectPermissionsRequest, ...getPermissionBackgroundApiMethods(permissionController), - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) // snaps removeSnapError: this.controllerMessenger.call.bind( this.controllerMessenger, @@ -2189,6 +2198,8 @@ export default class MetamaskController extends EventEmitter { ), dismissNotifications: this.dismissNotifications.bind(this), markNotificationsAsRead: this.markNotificationsAsRead.bind(this), + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) // Desktop getDesktopEnabled: this.desktopController.getDesktopEnabled.bind( this.desktopController, @@ -2488,7 +2499,7 @@ export default class MetamaskController extends EventEmitter { // clear permissions this.permissionController.clearState(); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) // Clear snap state this.snapController.clearState(); // Clear notification state @@ -2614,7 +2625,7 @@ export default class MetamaskController extends EventEmitter { async _loginUser() { try { // Automatic login via config password - const password = process.env.CONF?.PASSWORD; + const password = process.env.PASSWORD; if (password && !process.env.IN_TEST) { await this.submitPassword(password); } @@ -3543,7 +3554,7 @@ export default class MetamaskController extends EventEmitter { if (subjectType === SubjectType.Internal) { origin = ORIGIN_METAMASK; } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) else if (subjectType === SubjectType.Snap) { origin = sender.snapId; } @@ -3591,7 +3602,7 @@ export default class MetamaskController extends EventEmitter { }); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * For snaps running in workers. * @@ -3749,7 +3760,7 @@ export default class MetamaskController extends EventEmitter { }), ); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) engine.push( createSnapMethodMiddleware(subjectType === SubjectType.Snap, { getUnlockPromise: this.appStateController.getUnlockPromise.bind( @@ -4247,7 +4258,7 @@ export default class MetamaskController extends EventEmitter { } }; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) updateCaveat = (origin, target, caveatType, caveatValue) => { try { this.controllerMessenger.call( diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js index 1ac0c853e..c4d64af8f 100644 --- a/app/scripts/platforms/extension.js +++ b/app/scripts/platforms/extension.js @@ -194,7 +194,7 @@ export default class ExtensionPlatform { let message = `Transaction ${nonce} failed! ${ errorMessage || txMeta.err.message }`; - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) if (isNaN(nonce)) { message = `Transaction failed! ${errorMessage || txMeta.err.message}`; } diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 2ac1f8227..148ce0397 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -22,7 +22,7 @@ import { checkForLastErrorAndLog } from '../../shared/modules/browser-runtime.ut import { SUPPORT_LINK } from '../../shared/lib/ui-utils'; import { getErrorHtml, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) registerDesktopErrorActions, ///: END:ONLY_INCLUDE_IN } from '../../shared/lib/error-utils'; @@ -264,7 +264,7 @@ async function start() { ( err, store, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) backgroundConnection, ///: END:ONLY_INCLUDE_IN ) => { @@ -274,7 +274,7 @@ async function start() { 'troubleStarting', err, store, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) backgroundConnection, ///: END:ONLY_INCLUDE_IN ); @@ -302,7 +302,7 @@ async function start() { displayCriticalError( 'troubleStarting', err, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) undefined, backgroundConnection, ///: END:ONLY_INCLUDE_IN @@ -345,7 +345,7 @@ function initializeUi(activeTab, connectionStream, cb) { cb( err, null, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) backgroundConnection, ///: END:ONLY_INCLUDE_IN ); @@ -367,7 +367,7 @@ async function displayCriticalError( errorKey, err, metamaskState, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) backgroundConnection, ///: END:ONLY_INCLUDE_IN ) { @@ -375,14 +375,14 @@ async function displayCriticalError( errorKey, SUPPORT_LINK, metamaskState, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) err, ///: END:ONLY_INCLUDE_IN ); container.innerHTML = html; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) registerDesktopErrorActions(backgroundConnection, browser); ///: END:ONLY_INCLUDE_IN diff --git a/builds.yml b/builds.yml new file mode 100644 index 000000000..fe455afbe --- /dev/null +++ b/builds.yml @@ -0,0 +1,214 @@ +# TODO(ritave): Add support for environments (/development/build/constants.js:@ENVIRONMENT) +# TODO(ritave): Add support for build targets (/development/build/constants.js:@BUILD_TARGETS) +# TODO(ritave): Warn if not all of declared variables have been defined / used + +# The priority order of variable definitions (most important to least important): +# ; ; .metamaskprodrc; .metamaskrc; builds.yml:.buildTypes..env; builds.yml:.features..env; builds.yml:.env + +# The build type to use when no build type provided in the cli +default: &default main + +# Declaration of build types +# Each build type is composed of features, env variables and assets. +# Also known as productFlavors in Android lingo +buildTypes: + main: + features: + - build-main + # Additional env variables that are specific to this build + env: + - INFURA_PROD_PROJECT_ID + - SEGMENT_PROD_WRITE_KEY + - INFURA_ENV_KEY_REF: INFURA_PROD_PROJECT_ID + - SEGMENT_WRITE_KEY_REF: SEGMENT_PROD_WRITE_KEY + + beta: + features: + - build-beta + env: + - INFURA_BETA_PROJECT_ID + - SEGMENT_BETA_WRITE_KEY + - INFURA_ENV_KEY_REF: INFURA_BETA_PROJECT_ID + - SEGMENT_WRITE_KEY_REF: SEGMENT_BETA_WRITE_KEY + # Modifies how the version is displayed. + # eg. instead of 10.25.0 -> 10.25.0-beta.2 + isPrerelease: true + # Folder which contains overrides to browser manifests + manifestOverrides: ./app/build-types/mmi/manifest/ + + flask: + # Code surrounded using code fences for that feature + # will not be removed + features: + - snaps + - desktop + - build-flask + env: + - INFURA_FLASK_PROJECT_ID + - SEGMENT_FLASK_WRITE_KEY + - ALLOW_LOCAL_SNAPS: true + - REQUIRE_SNAPS_ALLOWLIST: false + - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc + - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new + - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID + - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY + isPrerelease: true + + desktop: + features: + - snaps + - desktop + - build-flask + env: + - INFURA_FLASK_PROJECT_ID + - SEGMENT_FLASK_WRITE_KEY + - ALLOW_LOCAL_SNAPS: true + - REQUIRE_SNAPS_ALLOWLIST: false + - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc + - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new + - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID + - SEGMENT_WRITE_KEY_REF: SEGMENT_FLASK_WRITE_KEY + isPrerelease: true + + mmi: + features: + - build-mmi + env: + - INFURA_MMI_PROJECT_ID + - SEGMENT_MMI_WRITE_KEY + - INFURA_ENV_KEY_REF: INFURA_MMI_PROJECT_ID + - SEGMENT_WRITE_KEY_REF: SEGMENT_MMI_WRITE_KEY + - SUPPORT_LINK: https://mmi-support.zendesk.com/hc/en-us + - SUPPORT_REQUEST_LINK: https://mmi-support.zendesk.com/hc/en-us/requests/new + # For some reason, MMI uses this type of versioning + # Leaving it on for backwards compatibility + isPrerelease: true + +# Build types are composed of a set of features. +# Each feature can have code fences that add new code +# as well declaring, defining and overriding env variables +features: + snaps: + # Each feature might have variables that only exist when built with that feature active + env: + # Whether to allow snaps from localhost - local://localhost:8080/snap.manifest.json + # Enabled in Flask, will be disabled in Main + - ALLOW_LOCAL_SNAPS + # Whether to verify that a snap can be installed using an allow list + - REQUIRE_SNAPS_ALLOWLIST + assets: + - ./{app,shared,ui}/**/snaps/** + desktop: + env: + - COMPATIBILITY_VERSION_EXTENSION: 1 + - DISABLE_WEB_SOCKET_ENCRYPTION: false + - SKIP_OTP_PAIRING_FLOW: false + - WEB_SOCKET_PORT: null + + ### + # Build Type code extensions. Things like different support links, warning pages, banners + ### + + build-main: + build-beta: + assets: + # Assets that will be copied + - src: ./app/build-types/beta/images/ + dest: images + # Assets that are exclusively included in this feature and ignored in others + # Supports globs + - ./{app,shared,ui}/**/beta/** + build-mmi: + assets: + - src: ./app/build-types/mmi/images/ + dest: images + - ./{app,shared,ui}/**/mmi/** + build-flask: + assets: + - src: ./app/build-types/flask/images/ + dest: images + - ./{app,shared,ui}/**/flask/** + +# Env variables that are required for all types of builds +# +# env object supports both declarations (- FOO), and definitions (- FOO: BAR). +# Variables that were declared have to be defined somewhere in the load chain before usage +env: + - SWAPS_USE_DEV_APIS: false + - PORTFOLIO_URL: https://portfolio.metamask.io + - TOKEN_ALLOWANCE_IMPROVEMENTS: false + - TRANSACTION_SECURITY_PROVIDER: false + # The unlock password + - PASSWORD: null + # Also see METAMASK_DEBUG and NODE_DEBUG + - DEBUG: null + - SUPPORT_LINK: https://support.metamask.io + - SUPPORT_REQUEST_LINK: https://metamask.zendesk.com/hc/en-us + - SKIP_BACKGROUND_INITIALIZATION: false + - MULTICHAIN: false + + # TODO(ritave): Move ManifestV3 into a feature? + - ENABLE_MV3: false + - HARDWARE_WALLETS_MV3: false + # These are exclusively used for MV3 + - APPLY_LAVAMOAT + - FILE_NAMES + + ### + # API keys to 3rd party services + ### + + - PUBNUB_PUB_KEY: null + - PUBNUB_SUB_KEY: null + - SEGMENT_HOST: null + - SENTRY_DSN: null + - SENTRY_DSN_DEV: null + - OPENSEA_KEY: null + - ETHERSCAN_KEY: null + # also INFURA_PROJECT_ID below + + ### + # Build system backwards compatibility + ### + + - INFURA_ENV_KEY_REF + - SEGMENT_WRITE_KEY_REF + + ### + # Variables that are modified with hardcoded code + ### + + # Used for debugging changes to the phishing warning page. + # Modified in /development/build/scripts.js:@getPhishingWarningPageUrl + - PHISHING_WARNING_PAGE_URL: null + # Modified in /development/build/scripts.js:@getInfuraProjectId + - INFURA_PROJECT_ID + # Modified in /development/build/scripts.js:@getSegmentWriteKey + - SEGMENT_WRITE_KEY: '' + # Modified in /development/build/scripts.js:@setEnvironmentVariables + # Also see DEBUG and NODE_DEBUG + - METAMASK_DEBUG: false + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - ICON_NAMES + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - IN_TEST + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - METAMASK_ENVIRONMENT + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - METAMASK_VERSION + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - METAMASK_BUILD_TYPE + # Modified in /development/build/scripts.js:@setEnvironmentVariables + - NODE_ENV + # Defined by node itself + # For the purposes of the build system we define it as empty below + # if it's not inside process.env + # Also see DEBUG and METAMASK_DEBUG + - NODE_DEBUG: '' + + ### + # Meta variables + ### + + # Uses yaml anchors to DRY - https://juju.is/docs/sdk/yaml-anchors-and-aliases + - METAMASK_BUILD_TYPE_DEFAULT: *default diff --git a/development/build/config.js b/development/build/config.js index b7b0f984c..d318b5a88 100644 --- a/development/build/config.js +++ b/development/build/config.js @@ -1,26 +1,13 @@ const path = require('path'); const { readFile } = require('fs/promises'); +const assert = require('assert'); +const { AssertionError } = require('assert'); const ini = require('ini'); -const { BuildType } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); +const { Variables } = require('../lib/variables'); +const { ENVIRONMENT } = require('./constants'); -const configurationPropertyNames = [ - 'MULTICHAIN', - 'INFURA_PROJECT_ID', - 'PHISHING_WARNING_PAGE_URL', - 'PORTFOLIO_URL', - 'SEGMENT_HOST', - 'SEGMENT_WRITE_KEY', - 'SENTRY_DSN_DEV', - 'SWAPS_USE_DEV_APIS', - // Desktop - 'COMPATIBILITY_VERSION_EXTENSION', - 'DISABLE_WEB_SOCKET_ENCRYPTION', - 'METAMASK_DEBUG', - 'SKIP_OTP_PAIRING_FLOW', - 'ENABLE_MV3', -]; - -const productionConfigurationPropertyNames = [ +const VARIABLES_REQUIRED_IN_PRODUCTION = [ 'INFURA_BETA_PROJECT_ID', 'INFURA_FLASK_PROJECT_ID', 'INFURA_PROD_PROJECT_ID', @@ -30,96 +17,145 @@ const productionConfigurationPropertyNames = [ 'SENTRY_DSN', ]; -/** - * Get configuration for non-production builds. - * - * @returns {object} The production configuration. - */ -async function getConfig() { - const configPath = path.resolve(__dirname, '..', '..', '.metamaskrc'); +async function fromIniFile(filepath) { let configContents = ''; try { - configContents = await readFile(configPath, { + configContents = await readFile(filepath, { encoding: 'utf8', }); } catch (error) { if (error.code !== 'ENOENT') { throw error; } + return undefined; } - const environmentVariables = {}; - for (const propertyName of configurationPropertyNames) { - if (process.env[propertyName]) { - environmentVariables[propertyName] = process.env[propertyName]; + const variables = ini.parse(configContents); + assert( + !Object.values(variables).some((variable) => typeof variable === 'object'), + `When loading ${filepath} - INI categories are not supported`, + ); + const entries = Object.entries(variables); + + const declarations = new Set( + entries.filter(([, value]) => value === '').map(([key]) => key), + ); + const definitions = new Map( + entries + .filter(([, value]) => value !== '') + .map(([key, value]) => [key, value]), + ); + + return { declarations, definitions }; +} + +function fromEnv(declarations) { + const definitions = new Map( + [...declarations] + .filter((declaration) => declaration in process.env) + .map((declaration) => [declaration, process.env[declaration]]), + ); + return { definitions, declarations: new Set() }; +} + +function fromBuildsYML(buildType, config) { + const extractDeclarations = (envArray) => + envArray === undefined + ? [] + : envArray.map((env) => (typeof env === 'string' ? env : env.key)); + const extractDefinitions = (envArray) => + envArray === undefined + ? [] + : envArray.filter((env) => typeof env !== 'string'); + + // eslint-disable-next-line no-param-reassign + buildType = buildType ?? config.default; + const activeBuild = config.buildTypes[buildType]; + const activeFeatures = activeBuild.features ?? []; + + let declarations = [...extractDeclarations(config.env)]; + + activeFeatures + .map((feature) => config.features[feature]) + .filter((feature) => feature !== null) + .forEach(({ env }) => declarations.push(...extractDeclarations(env))); + + declarations.push(...extractDeclarations(activeBuild.env)); + declarations = new Set(declarations); + + const definitions = new Map(); + + // 1. root env + extractDefinitions(config.env).forEach(({ key, value }) => + definitions.set(key, value), + ); + // 2. features env + activeFeatures + .filter((key) => config.features[key] !== null) + .map((key) => config.features[key].env) + .map(extractDefinitions) + .flat() + .forEach(({ key, value }) => definitions.set(key, value)); + // 3. build type env + extractDefinitions(activeBuild.env).forEach(({ key, value }) => + definitions.set(key, value), + ); + + return { declarations, definitions, activeFeatures, activeBuild }; +} + +/** + * + * @param {string?} buildType - The chosen build type to build + * @param environment + * @returns Parsed configuration of the build pipeline + */ +async function getConfig(buildType, environment) { + const config = loadBuildTypesConfig(); + const { + declarations: ymlDeclarations, + definitions: ymlDefinitions, + activeBuild, + activeFeatures, + } = await fromBuildsYML(buildType, config); + + const variables = new Variables(ymlDeclarations); + + // notice that maps have inverted value and key pair in forEach + ymlDefinitions.forEach((value, key) => variables.set(key, value)); + + ( + await fromIniFile(path.resolve(__dirname, '..', '..', '.metamaskrc')) + )?.definitions.forEach((value, key) => variables.set(key, value)); + ( + await fromIniFile(path.resolve(__dirname, '..', '..', '.metamaskprodrc')) + )?.definitions.forEach((value, key) => variables.set(key, value)); + + fromEnv(ymlDeclarations).definitions.forEach((value, key) => + variables.set(key, value), + ); + + // TODO(ritave): Move build targets and environments to builds.yml + if (environment === ENVIRONMENT.PRODUCTION) { + const undefinedVariables = VARIABLES_REQUIRED_IN_PRODUCTION.filter( + (variable) => !variables.isDefined(variable), + ); + if (undefinedVariables.length !== 0) { + const message = `Some variables required to build production target are not defined. + - ${undefinedVariables.join('\n - ')} +`; + throw new AssertionError({ message }); } } return { - ...ini.parse(configContents), - ...environmentVariables, + variables, + activeBuild, + activeFeatures, + buildsYml: config, }; } -/** - * Get configuration for production builds and perform validation. - * - * This function validates that all required variables are present, and that - * the production configuration file doesn't include any extraneous entries. - * - * @param {BuildType} buildType - The current build type (e.g. "main", "flask", - * etc.). - * @returns {object} The production configuration. - */ -async function getProductionConfig(buildType) { - const prodConfigPath = path.resolve(__dirname, '..', '..', '.metamaskprodrc'); - let prodConfigContents = ''; - try { - prodConfigContents = await readFile(prodConfigPath, { - encoding: 'utf8', - }); - } catch (error) { - if (error.code !== 'ENOENT') { - throw error; - } - } - - const environmentVariables = {}; - for (const propertyName of productionConfigurationPropertyNames) { - if (process.env[propertyName]) { - environmentVariables[propertyName] = process.env[propertyName]; - } - } - - const prodConfig = { - ...ini.parse(prodConfigContents), - ...environmentVariables, - }; - - const requiredEnvironmentVariables = { - all: ['SENTRY_DSN'], - [BuildType.beta]: ['INFURA_BETA_PROJECT_ID', 'SEGMENT_BETA_WRITE_KEY'], - [BuildType.flask]: ['INFURA_FLASK_PROJECT_ID', 'SEGMENT_FLASK_WRITE_KEY'], - [BuildType.main]: ['INFURA_PROD_PROJECT_ID', 'SEGMENT_PROD_WRITE_KEY'], - [BuildType.mmi]: ['INFURA_MMI_PROJECT_ID', 'SEGMENT_MMI_WRITE_KEY'], - }; - - for (const required of [ - ...requiredEnvironmentVariables.all, - ...requiredEnvironmentVariables[buildType], - ]) { - if (!prodConfig[required]) { - throw new Error(`Missing '${required}' environment variable`); - } - } - - const allValid = Object.values(requiredEnvironmentVariables).flat(); - for (const environmentVariable of Object.keys(prodConfig)) { - if (!allValid.includes(environmentVariable)) { - throw new Error(`Invalid environment variable: '${environmentVariable}'`); - } - } - return prodConfig; -} - -module.exports = { getConfig, getProductionConfig }; +module.exports = { + getConfig, +}; diff --git a/development/build/etc.js b/development/build/etc.js index 3da86409f..0479f5eee 100644 --- a/development/build/etc.js +++ b/development/build/etc.js @@ -6,7 +6,7 @@ const del = require('del'); const pify = require('pify'); const pump = pify(require('pump')); -const { BuildType } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS } = require('./constants'); const { createTask, composeParallel } = require('./task'); @@ -42,7 +42,7 @@ function createEtcTasks({ browserPlatforms, buildType, livereload, version }) { function createZipTask(platform, buildType, version) { return async () => { const path = - buildType === BuildType.main + buildType === loadBuildTypesConfig().default ? `metamask-${platform}-${version}` : `metamask-${buildType}-${platform}-${version}`; await pump( diff --git a/development/build/index.js b/development/build/index.js index 6c667bc9d..91d12815d 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -10,8 +10,10 @@ const yargs = require('yargs/yargs'); const { hideBin } = require('yargs/helpers'); const { sync: globby } = require('globby'); const lavapack = require('@lavamoat/lavapack'); +const difference = require('lodash/difference'); +const { intersection } = require('lodash'); const { getVersion } = require('../lib/get-version'); -const { BuildType, BuildTypeInheritance } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS, ENVIRONMENT } = require('./constants'); const { createTask, @@ -275,9 +277,9 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, type: 'boolean', }) .option('build-type', { - default: BuildType.main, + default: loadBuildTypesConfig().default, description: 'The type of build to create.', - choices: Object.keys(BuildType), + choices: Object.keys(loadBuildTypesConfig().buildTypes), }) .option('build-version', { default: 0, @@ -380,29 +382,36 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, * build, or `null` if no files are to be ignored. */ function getIgnoredFiles(currentBuildType) { - const inheritedBuildTypes = BuildTypeInheritance[currentBuildType] || []; - const excludedFiles = Object.values(BuildType) - // This filter removes "main" and the current build type. The files of any - // build types that remain in the array will be excluded. "main" is the - // default build type, and has no files that are excluded from other builds. - .filter( - (buildType) => - buildType !== BuildType.main && - buildType !== currentBuildType && - !inheritedBuildTypes.includes(buildType), - ) - // Compute globs targeting files for exclusion for each excluded build - // type. - .reduce((excludedGlobs, excludedBuildType) => { - return excludedGlobs.concat([ - `../../app/**/${excludedBuildType}/**`, - `../../shared/**/${excludedBuildType}/**`, - `../../ui/**/${excludedBuildType}/**`, - ]); - }, []) - // This creates absolute paths of the form: - // PATH_TO_REPOSITORY_ROOT/app/**/${excludedBuildType}/** - .map((pathGlob) => path.resolve(__dirname, pathGlob)); + const buildConfig = loadBuildTypesConfig(); + const cwd = process.cwd(); - return globby(excludedFiles); + const exclusiveAssetsForFeatures = (features) => + globby( + features + .flatMap( + (feature) => + buildConfig.features[feature].assets + ?.filter((asset) => 'exclusiveInclude' in asset) + .map((asset) => asset.exclusiveInclude) ?? [], + ) + .map((pathGlob) => path.resolve(cwd, pathGlob)), + ); + + const allFeatures = Object.keys(buildConfig.features); + const activeFeatures = + buildConfig.buildTypes[currentBuildType].features ?? []; + const inactiveFeatures = difference(allFeatures, activeFeatures); + + const ignoredPaths = exclusiveAssetsForFeatures(inactiveFeatures); + // We do a sanity check to verify that any inactive feature haven't excluded files + // that active features are trying to include + const activePaths = exclusiveAssetsForFeatures(activeFeatures); + const conflicts = intersection(activePaths, ignoredPaths); + if (conflicts.length !== 0) { + throw new Error(`Below paths are required exclusively by both active and inactive features resulting in a conflict: +\t-> ${conflicts.join('\n\t-> ')} +Please fix builds.yml`); + } + + return ignoredPaths; } diff --git a/development/build/manifest.js b/development/build/manifest.js index e95690868..6d240dbfa 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -6,7 +6,7 @@ const { mergeWith, cloneDeep, capitalize } = require('lodash'); const baseManifest = process.env.ENABLE_MV3 ? require('../../app/manifest/v3/_base.json') : require('../../app/manifest/v2/_base.json'); -const { BuildType } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS, ENVIRONMENT } = require('./constants'); const { createTask, composeSeries } = require('./task'); @@ -165,25 +165,24 @@ async function writeJson(obj, file) { * Get manifest modifications for the given build type, including modifications specific to the * given platform. * - * @param {BuildType} buildType - The build type. + * @param {string} buildType - The build type. * @param {string} platform - The platform (i.e. the browser). - * @returns {object} The build modificantions for the given build type and platform. + * @returns {object} The build modifications for the given build type and platform. */ async function getBuildModifications(buildType, platform) { - if (!Object.values(BuildType).includes(buildType)) { + const buildConfig = loadBuildTypesConfig(); + if (!(buildType in buildConfig.buildTypes)) { throw new Error(`Invalid build type: ${buildType}`); - } else if (buildType === BuildType.main) { + } + + const overridesPath = buildConfig.buildTypes[buildType].manifestOverrides; + if (overridesPath === undefined) { return {}; } const builtTypeManifestDirectoryPath = path.resolve( - __dirname, - '..', - '..', - 'app', - 'build-types', - buildType, - 'manifest', + process.cwd(), + overridesPath, ); const baseBuildTypeModificationsPath = path.join( diff --git a/development/build/scripts.js b/development/build/scripts.js index cd7f1f0d9..2ac455878 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -1,7 +1,10 @@ +// TODO(ritave): Remove switches on hardcoded build types + const { callbackify } = require('util'); const path = require('path'); const { writeFileSync, readFileSync } = require('fs'); const EventEmitter = require('events'); +const assert = require('assert'); const gulp = require('gulp'); const watch = require('gulp-watch'); const Vinyl = require('vinyl'); @@ -29,10 +32,9 @@ const bifyModuleGroups = require('bify-module-groups'); const phishingWarningManifest = require('@metamask/phishing-warning/package.json'); const { streamFlatMap } = require('../stream-flat-map'); -const { BuildType } = require('../lib/build-type'); const { generateIconNames } = require('../generate-icon-names'); const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); -const { getConfig, getProductionConfig } = require('./config'); +const { getConfig } = require('./config'); const { isDevBuild, isTestBuild, @@ -101,67 +103,79 @@ const standardScuttlingConfig = { * Get the appropriate Infura project ID. * * @param {object} options - The Infura project ID options. - * @param {BuildType} options.buildType - The current build type. - * @param {object} options.config - The environment variable configuration. + * @param {string} options.buildType - The current build type. * @param {ENVIRONMENT[keyof ENVIRONMENT]} options.environment - The build environment. * @param {boolean} options.testing - Whether this is a test build or not. + * @param options.variables * @returns {string} The Infura project ID. */ -function getInfuraProjectId({ buildType, config, environment, testing }) { +function getInfuraProjectId({ buildType, variables, environment, testing }) { if (testing) { return '00000000000000000000000000000000'; } else if (environment !== ENVIRONMENT.PRODUCTION) { // Skip validation because this is unset on PRs from forks. - return config.INFURA_PROJECT_ID; - } else if (buildType === BuildType.main) { - return config.INFURA_PROD_PROJECT_ID; - } else if (buildType === BuildType.beta) { - return config.INFURA_BETA_PROJECT_ID; - } else if (buildType === BuildType.flask) { - return config.INFURA_FLASK_PROJECT_ID; - } else if (buildType === BuildType.mmi) { - return config.INFURA_MMI_PROJECT_ID; + return variables.get('INFURA_PROJECT_ID'); } - throw new Error(`Invalid build type: '${buildType}'`); + /** @type {string|undefined} */ + const infuraKeyReference = process.env.INFURA_ENV_KEY_REF; + assert( + typeof infuraKeyReference === 'string' && infuraKeyReference.length > 0, + `Build type "${buildType}" has improperly set INFURA_ENV_KEY_REF in builds.yml. Current value: "${infuraKeyReference}"`, + ); + /** @type {string|undefined} */ + const infuraProjectId = variables.get(infuraKeyReference); + assert( + typeof infuraProjectId === 'string' && infuraProjectId.length > 0, + `Infura Project ID environmental variable "${infuraKeyReference}" is set improperly.`, + ); + return infuraProjectId; } /** * Get the appropriate Segment write key. * * @param {object} options - The Segment write key options. - * @param {BuildType} options.buildType - The current build type. - * @param {object} options.config - The environment variable configuration. + * @param {string} options.buildType - The current build type. * @param {keyof ENVIRONMENT} options.environment - The current build environment. + * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline * @returns {string} The Segment write key. */ -function getSegmentWriteKey({ buildType, config, environment }) { +function getSegmentWriteKey({ buildType, variables, environment }) { if (environment !== ENVIRONMENT.PRODUCTION) { // Skip validation because this is unset on PRs from forks, and isn't necessary for development builds. - return config.SEGMENT_WRITE_KEY; - } else if (buildType === BuildType.main) { - return config.SEGMENT_PROD_WRITE_KEY; - } else if (buildType === BuildType.beta) { - return config.SEGMENT_BETA_WRITE_KEY; - } else if (buildType === BuildType.flask) { - return config.SEGMENT_FLASK_WRITE_KEY; - } else if (buildType === BuildType.mmi) { - return config.SEGMENT_MMI_WRITE_KEY; + return variables.get('SEGMENT_WRITE_KEY'); } - throw new Error(`Invalid build type: '${buildType}'`); + + const segmentKeyReference = process.env.SEGMENT_WRITE_KEY_REF; + assert( + typeof segmentKeyReference === 'string' && segmentKeyReference.length > 0, + `Build type "${buildType}" has improperly set SEGMENT_WRITE_KEY_REF in builds.yml. Current value: "${segmentKeyReference}"`, + ); + + const segmentWriteKey = variables.get(segmentKeyReference); + assert( + typeof segmentWriteKey === 'string' && segmentWriteKey.length > 0, + `Segment Write Key environmental variable "${segmentKeyReference}" is set improperly.`, + ); + return segmentWriteKey; } /** * Get the URL for the phishing warning page, if it has been set. * * @param {object} options - The phishing warning page options. - * @param {object} options.config - The environment variable configuration. * @param {boolean} options.testing - Whether this is a test build or not. + * @param {import('../lib/variables').Variables} options.variables - Object containing all variables that modify the build pipeline * @returns {string} The URL for the phishing warning page, or `undefined` if no URL is set. */ -function getPhishingWarningPageUrl({ config, testing }) { - let phishingWarningPageUrl = config.PHISHING_WARNING_PAGE_URL; +function getPhishingWarningPageUrl({ variables, testing }) { + let phishingWarningPageUrl = variables.get('PHISHING_WARNING_PAGE_URL'); - if (!phishingWarningPageUrl) { + assert( + phishingWarningPageUrl === null || + typeof phishingWarningPageUrl === 'string', + ); + if (phishingWarningPageUrl === null) { phishingWarningPageUrl = testing ? 'http://localhost:9999/' : `https://metamask.github.io/phishing-warning/v${phishingWarningManifest.version}/`; @@ -209,7 +223,7 @@ module.exports = createScriptTasks; * LavaMoat at runtime or not. * @param {string[]} options.browserPlatforms - A list of browser platforms to * build bundles for. - * @param {BuildType} options.buildType - The current build type (e.g. "main", + * @param {string} options.buildType - The current build type (e.g. "main", * "flask", etc.). * @param {string[] | null} options.ignoredFiles - A list of files to exclude * from the current build. @@ -455,7 +469,7 @@ function createScriptTasks({ * @param {string[]} options.browserPlatforms - A list of browser platforms to * build bundles for. * @param {BUILD_TARGETS} options.buildTarget - The current build target. - * @param {BuildType} options.buildType - The current build type (e.g. "main", + * @param {string} options.buildType - The current build type (e.g. "main", * "flask", etc.). * @param {string[] | null} options.ignoredFiles - A list of files to exclude * from the current build. @@ -541,7 +555,7 @@ async function createManifestV3AppInitializationBundle({ * @param {string[]} options.browserPlatforms - A list of browser platforms to * build bundles for. * @param {BUILD_TARGETS} options.buildTarget - The current build target. - * @param {BuildType} options.buildType - The current build type (e.g. "main", + * @param {string} options.buildType - The current build type (e.g. "main", * "flask", etc.). * @param {string[]} options.entryFiles - A list of entry point file paths, * relative to the repository root directory. @@ -576,18 +590,29 @@ function createFactoredBuild({ const reloadOnChange = isDevBuild(buildTarget); const minify = !isDevBuild(buildTarget); - const envVars = await getEnvironmentVariables({ + const environment = getEnvironment({ buildTarget }); + const config = await getConfig(buildType, environment); + const { variables, activeBuild } = config; + await setEnvironmentVariables({ buildTarget, buildType, + environment, + variables, + activeBuild, version, }); + const features = { + active: new Set(activeBuild.features ?? []), + all: new Set(Object.keys(config.buildsYml.features)), + }; setupBundlerDefaults(buildConfiguration, { buildTarget, - buildType, - envVars, + variables, + envVars: buildSafeVariableObject(variables), ignoredFiles, policyOnly, minify, + features, reloadOnChange, shouldLintFenceFiles, }); @@ -760,7 +785,7 @@ function createFactoredBuild({ * @param {string[]} options.browserPlatforms - A list of browser platforms to * build the bundle for. * @param {BUILD_TARGETS} options.buildTarget - The current build target. - * @param {BuildType} options.buildType - The current build type (e.g. "main", + * @param {string} options.buildType - The current build type (e.g. "main", * "flask", etc.). * @param {string} options.destFilepath - The file path the bundle should be * written to. @@ -806,20 +831,31 @@ function createNormalBundle({ const reloadOnChange = Boolean(devMode); const minify = Boolean(devMode) === false; - const envVars = { - ...(await getEnvironmentVariables({ - buildTarget, - buildType, - version, - })), - ...extraEnvironmentVariables, + const environment = getEnvironment({ buildTarget }); + const config = await getConfig(buildType, environment); + const { activeBuild, variables } = config; + await setEnvironmentVariables({ + buildTarget, + buildType, + variables, + environment, + activeBuild, + version, + }); + Object.entries(extraEnvironmentVariables ?? {}).forEach(([key, value]) => + variables.set(key, value), + ); + + const features = { + active: new Set(activeBuild.features ?? []), + all: new Set(Object.keys(config.buildsYml.features)), }; setupBundlerDefaults(buildConfiguration, { - buildType, - envVars, + envVars: buildSafeVariableObject(variables), ignoredFiles, policyOnly, minify, + features, reloadOnChange, shouldLintFenceFiles, applyLavaMoat, @@ -865,11 +901,11 @@ function setupBundlerDefaults( buildConfiguration, { buildTarget, - buildType, envVars, ignoredFiles, policyOnly, minify, + features, reloadOnChange, shouldLintFenceFiles, applyLavaMoat, @@ -882,7 +918,7 @@ function setupBundlerDefaults( // Source transforms transform: [ // // Remove code that should be excluded from builds of the current type - createRemoveFencedCodeTransform(buildType, shouldLintFenceFiles), + createRemoveFencedCodeTransform(features, shouldLintFenceFiles), // Transpile top-level code [ babelify, @@ -1090,56 +1126,55 @@ async function createBundle(buildConfiguration, { reloadOnChange }) { } /** - * Get environment variables to inject in the current build. + * Sets environment variables to inject in the current build. * * @param {object} options - Build options. * @param {BUILD_TARGETS} options.buildTarget - The current build target. - * @param {BuildType} options.buildType - The current build type (e.g. "main", + * @param {string} options.buildType - The current build type (e.g. "main", * "flask", etc.). * @param {string} options.version - The current version of the extension. - * @returns {object} A map of environment variables to inject. + * @param options.activeBuild + * @param options.variables + * @param options.environment */ -async function getEnvironmentVariables({ buildTarget, buildType, version }) { - const environment = getEnvironment({ buildTarget }); - const config = - environment === ENVIRONMENT.PRODUCTION - ? await getProductionConfig(buildType) - : await getConfig(); - +async function setEnvironmentVariables({ + buildTarget, + buildType, + activeBuild, + environment, + variables, + version, +}) { const devMode = isDevBuild(buildTarget); const testing = isTestBuild(buildTarget); const iconNames = await generateIconNames(); - return { + + variables.set({ ICON_NAMES: iconNames, - MULTICHAIN: config.MULTICHAIN === '1', - CONF: devMode ? config : {}, - ENABLE_MV3: config.ENABLE_MV3, IN_TEST: testing, INFURA_PROJECT_ID: getInfuraProjectId({ buildType, - config, + activeBuild, + variables, environment, testing, }), - METAMASK_DEBUG: devMode || config.METAMASK_DEBUG === '1', + METAMASK_DEBUG: devMode || variables.getMaybe('METAMASK_DEBUG') === true, METAMASK_ENVIRONMENT: environment, METAMASK_VERSION: version, METAMASK_BUILD_TYPE: buildType, NODE_ENV: devMode ? ENVIRONMENT.DEVELOPMENT : ENVIRONMENT.PRODUCTION, - PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ config, testing }), - PORTFOLIO_URL: config.PORTFOLIO_URL || 'https://portfolio.metamask.io', - SEGMENT_HOST: config.SEGMENT_HOST, - SEGMENT_WRITE_KEY: getSegmentWriteKey({ buildType, config, environment }), - SENTRY_DSN: config.SENTRY_DSN, - SENTRY_DSN_DEV: config.SENTRY_DSN_DEV, - SWAPS_USE_DEV_APIS: config.SWAPS_USE_DEV_APIS === '1', - TOKEN_ALLOWANCE_IMPROVEMENTS: config.TOKEN_ALLOWANCE_IMPROVEMENTS === '1', - TRANSACTION_SECURITY_PROVIDER: config.TRANSACTION_SECURITY_PROVIDER === '1', - // Desktop - COMPATIBILITY_VERSION_EXTENSION: config.COMPATIBILITY_VERSION_EXTENSION, - DISABLE_WEB_SOCKET_ENCRYPTION: config.DISABLE_WEB_SOCKET_ENCRYPTION === '1', - SKIP_OTP_PAIRING_FLOW: config.SKIP_OTP_PAIRING_FLOW === '1', - }; + PHISHING_WARNING_PAGE_URL: getPhishingWarningPageUrl({ + variables, + testing, + }), + SEGMENT_WRITE_KEY: getSegmentWriteKey({ + buildType, + activeBuild, + variables, + environment, + }), + }); } function renderHtmlFile({ @@ -1172,6 +1207,29 @@ function renderHtmlFile({ }); } +/** + * Builds a javascript object that throws an error when trying to access a property that wasn't defined properly + * + * @param {Variables} variables + * @returns {{[key: string]: unknown }} Variable definitions + */ +function buildSafeVariableObject(variables) { + return new Proxy( + {}, + { + has(_, key) { + return key !== '_'; // loose-envify uses "_" for settings + }, + get(_, key) { + if (key === '_') { + return undefined; // loose-envify uses "_" for settings + } + return variables.get(key); + }, + }, + ); +} + function beep() { process.stdout.write('\x07'); } diff --git a/development/build/static.js b/development/build/static.js index 15fa0f06c..644105c87 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -4,7 +4,7 @@ const watch = require('gulp-watch'); const glob = require('fast-glob'); const locales = require('../../app/_locales/index.json'); -const { BuildType } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); const { TASKS } = require('./constants'); const { createTask, composeSeries } = require('./task'); @@ -31,41 +31,23 @@ module.exports = function createStaticAssetTasks({ copyTargetsDevs[browser] = copyTargetsDev; }); - const additionalBuildTargets = { - [BuildType.beta]: [ - { - src: './app/build-types/beta/images/', - dest: `images`, - }, - ], - [BuildType.flask]: [ - { - src: './app/build-types/flask/images/', - dest: `images`, - }, - ], - [BuildType.desktop]: [ - { - src: './app/build-types/desktop/images/', - dest: `images`, - }, - ], - [BuildType.mmi]: [ - { - src: './app/build-types/mmi/images/', - dest: `images`, - }, - ], - }; + const buildConfig = loadBuildTypesConfig(); - if (Object.keys(additionalBuildTargets).includes(buildType)) { - Object.entries(copyTargetsProds).forEach(([_, copyTargetsProd]) => - copyTargetsProd.push(...additionalBuildTargets[buildType]), - ); - Object.entries(copyTargetsDevs).forEach(([_, copyTargetsDev]) => - copyTargetsDev.push(...additionalBuildTargets[buildType]), - ); - } + const activeFeatures = buildConfig.buildTypes[buildType].features ?? []; + + const additionalAssets = activeFeatures.flatMap( + (feature) => + buildConfig.features[feature].assets?.filter( + (asset) => !('exclusiveInclude' in asset), + ) ?? [], + ); + + Object.entries(copyTargetsProds).forEach(([_, copyTargetsProd]) => + copyTargetsProd.push(...additionalAssets), + ); + Object.entries(copyTargetsDevs).forEach(([_, copyTargetsDev]) => + copyTargetsDev.push(...additionalAssets), + ); const prodTasks = []; Object.entries(copyTargetsProds).forEach(([browser, copyTargetsProd]) => { @@ -120,7 +102,7 @@ module.exports = function createStaticAssetTasks({ await Promise.all( sources.map(async (src) => { const relativePath = path.relative(baseDir, src); - await fs.copy(src, `${dest}${relativePath}`); + await fs.copy(src, `${dest}${relativePath}`, { overwrite: true }); }), ); } diff --git a/development/build/transforms/README.md b/development/build/transforms/README.md index de1e8d0c5..6d8655e22 100644 --- a/development/build/transforms/README.md +++ b/development/build/transforms/README.md @@ -29,7 +29,7 @@ this.store.updateStructure({ ..., GasFeeController: this.gasFeeController, TokenListController: this.tokenListController, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) SnapController: this.snapController, ///: END:ONLY_INCLUDE_IN }); @@ -49,7 +49,7 @@ Note that multiple build types can be specified by separating them with commands inside the parameter parentheses: ```javascript -///: BEGIN:ONLY_INCLUDE_IN(beta,flask) +///: BEGIN:ONLY_INCLUDE_IN(build-beta,build-flask) ``` ### Gotchas @@ -114,7 +114,7 @@ only be included in a particular build type, say `beta`, they should be wrapped as follows: ```javascript -///: BEGIN:ONLY_INCLUDE_IN(beta) +///: BEGIN:ONLY_INCLUDE_IN(build-beta) console.log('I am only included in beta builds.'); ///: END:ONLY_INCLUDE_IN ``` diff --git a/development/build/transforms/remove-fenced-code.d.ts b/development/build/transforms/remove-fenced-code.d.ts new file mode 100644 index 000000000..81d249c52 --- /dev/null +++ b/development/build/transforms/remove-fenced-code.d.ts @@ -0,0 +1,4 @@ +export type Features = { + active: ReadonlySet; + all: ReadonlySet; +}; diff --git a/development/build/transforms/remove-fenced-code.js b/development/build/transforms/remove-fenced-code.js index 367173329..3f2a7b5cd 100644 --- a/development/build/transforms/remove-fenced-code.js +++ b/development/build/transforms/remove-fenced-code.js @@ -1,6 +1,5 @@ const path = require('path'); const { PassThrough, Transform } = require('stream'); -const { BuildType, BuildTypeInheritance } = require('../../lib/build-type'); const { lintTransformedFile } = require('./utils'); const hasKey = (obj, key) => Reflect.hasOwnProperty.call(obj, key); @@ -18,14 +17,14 @@ class RemoveFencedCodeTransform extends Transform { * Optionally lints the file if it was modified. * * @param {string} filePath - The path to the file being transformed. - * @param {string} buildType - The type of the current build process. + * @param {import('./remove-fenced-code').Features} features - Features that are currently enabled. * @param {boolean} shouldLintTransformedFiles - Whether the file should be * linted if modified by the transform. */ - constructor(filePath, buildType, shouldLintTransformedFiles) { + constructor(filePath, features, shouldLintTransformedFiles) { super(); this.filePath = filePath; - this.buildType = buildType; + this.features = features; this.shouldLintTransformedFiles = shouldLintTransformedFiles; this._fileBuffers = []; } @@ -45,7 +44,7 @@ class RemoveFencedCodeTransform extends Transform { try { [fileContent, didModify] = removeFencedCode( this.filePath, - this.buildType, + this.features, Buffer.concat(this._fileBuffers).toString('utf8'), ); } catch (error) { @@ -82,20 +81,14 @@ class RemoveFencedCodeTransform extends Transform { * file is ignored by ESLint, since linting is our first line of defense against * making un-syntactic modifications to files using code fences. * - * @param {string} buildType - The type of the current build. + * @param {import('./remove-fenced-code').Features} features - Features that are currently enabled. * @param {boolean} shouldLintTransformedFiles - Whether to lint transformed files. * @returns {(filePath: string) => Transform} The transform function. */ function createRemoveFencedCodeTransform( - buildType, + features, shouldLintTransformedFiles = true, ) { - if (!hasKey(BuildType, buildType)) { - throw new Error( - `Code fencing transform received unrecognized build type "${buildType}".`, - ); - } - // Browserify transforms are functions that receive a file name and return a // duplex stream. The stream receives the file contents piecemeal in the form // of Buffers. @@ -117,7 +110,7 @@ function createRemoveFencedCodeTransform( return new RemoveFencedCodeTransform( filePath, - buildType, + features, shouldLintTransformedFiles, ); }; @@ -132,31 +125,39 @@ const DirectiveCommands = { ONLY_INCLUDE_IN: 'ONLY_INCLUDE_IN', }; -const CommandValidators = { - [DirectiveCommands.ONLY_INCLUDE_IN]: (params, filePath) => { - if (!params || params.length === 0) { - throw new Error( - getInvalidParamsMessage( - filePath, - DirectiveCommands.ONLY_INCLUDE_IN, - `No params specified.`, - ), - ); - } - - params.forEach((param) => { - if (!hasKey(BuildType, param)) { +/** + * Factory function for command validators. + * + * @param {{ features: import('./remove-fenced-code').Features }} config - Configuration required for validation. + * @returns A mapping of command -> validator function. + */ +function CommandValidators({ features }) { + return { + [DirectiveCommands.ONLY_INCLUDE_IN]: (params, filePath) => { + if (!params || params.length === 0) { throw new Error( getInvalidParamsMessage( filePath, DirectiveCommands.ONLY_INCLUDE_IN, - `"${param}" is not a valid build type.`, + `No params specified.`, ), ); } - }); - }, -}; + + for (const param of params) { + if (!features.all.has(param)) { + throw new Error( + getInvalidParamsMessage( + filePath, + DirectiveCommands.ONLY_INCLUDE_IN, + `"${param}" is not a declared build feature.`, + ), + ); + } + } + }, + }; +} // Matches lines starting with "///:", and any preceding whitespace, except // newlines. We except newlines to avoid eating blank lines preceding a fenced @@ -171,7 +172,8 @@ const fenceSentinelRegex = /^\s*\/\/\/:/u; // At this stage of parsing, we are looking for one of: // - TERMINUS:COMMAND(PARAMS) // - TERMINUS:COMMAND -const directiveParsingRegex = /^([A-Z]+):([A-Z_]+)(?:\(((?:\w+,)*\w+)\))?$/u; +const directiveParsingRegex = + /^([A-Z]+):([A-Z_]+)(?:\(((?:\w[-\w]*,)*\w[-\w]*)\))?$/u; /** * Removes fenced code from the given JavaScript source string. "Fenced code" @@ -186,7 +188,7 @@ const directiveParsingRegex = /^([A-Z]+):([A-Z_]+)(?:\(((?:\w+,)*\w+)\))?$/u; * Here's an example of a valid fence: * * ```javascript - * ///: BEGIN:ONLY_INCLUDE_IN(flask) + * ///: BEGIN:ONLY_INCLUDE_IN(build-flask) * console.log('I am Flask.'); * ///: END:ONLY_INCLUDE_IN * ``` @@ -194,12 +196,12 @@ const directiveParsingRegex = /^([A-Z]+):([A-Z_]+)(?:\(((?:\w+,)*\w+)\))?$/u; * For details, please see the documentation. * * @param {string} filePath - The path to the file being transformed. - * @param {string} typeOfCurrentBuild - The type of the current build. + * @param {import('./remove-fenced-code').Features} features - Features that are currently active. * @param {string} fileContent - The contents of the file being transformed. * @returns {[string, modified]} A tuple of the post-transform file contents and * a boolean indicating whether they were modified. */ -function removeFencedCode(filePath, typeOfCurrentBuild, fileContent) { +function removeFencedCode(filePath, features, fileContent) { // Do not modify the file if we detect an inline sourcemap. For reasons // yet to be determined, the transform receives every file twice while in // watch mode, the second after Babel has transpiled the file. Babel adds @@ -318,6 +320,7 @@ function removeFencedCode(filePath, typeOfCurrentBuild, fileContent) { const splicingIndices = []; let shouldSplice = false; let currentCommand; + const commandValidators = CommandValidators({ features }); for (let i = 0; i < parsedDirectives.length; i++) { const { line, indices, terminus, command, parameters } = @@ -335,21 +338,17 @@ function removeFencedCode(filePath, typeOfCurrentBuild, fileContent) { currentCommand = command; // Throws an error if the command parameters are invalid - CommandValidators[command](parameters, filePath); + commandValidators[command](parameters, filePath); - const validBuildTypes = [ - typeOfCurrentBuild, - ...(BuildTypeInheritance[typeOfCurrentBuild] || []), - ]; - - const buildTypeMatches = validBuildTypes.some((validBuildType) => - parameters.includes(validBuildType), + const blockIsActive = parameters.some((param) => + features.active.has(param), ); - if (buildTypeMatches) { + if (blockIsActive) { shouldSplice = false; } else { shouldSplice = true; + // Add start index of BEGIN directive line to splicing indices splicingIndices.push(indices[0]); } diff --git a/development/build/transforms/remove-fenced-code.test.js b/development/build/transforms/remove-fenced-code.test.js index c38550cd4..ac39cc394 100644 --- a/development/build/transforms/remove-fenced-code.test.js +++ b/development/build/transforms/remove-fenced-code.test.js @@ -1,5 +1,5 @@ const deepFreeze = require('deep-freeze-strict'); -const { BuildType } = require('../../lib/build-type'); +const { loadBuildTypesConfig } = require('../../lib/build-type'); const { createRemoveFencedCodeTransform, removeFencedCode, @@ -14,12 +14,22 @@ jest.mock('./utils', () => ({ // file because it takes up a lot of lines and is very distracting. const testData = getTestData(); -const getMinimalFencedCode = (params = 'flask') => +const MAIN_BUILD = 'build-main'; +const FLASK_BUILD = 'build-flask'; + +const getMinimalFencedCode = (params = FLASK_BUILD) => `///: BEGIN:ONLY_INCLUDE_IN(${params}) Conditionally_Included ///: END:ONLY_INCLUDE_IN `; +const getFeatures = ({ all, active }) => ({ + all: new Set(all), + active: new Set(active), +}); + +const buildTypesConfig = loadBuildTypesConfig(); + describe('build/transforms/remove-fenced-code', () => { describe('createRemoveFencedCodeTransform', () => { const { lintTransformedFile: lintTransformedFileMock } = transformUtils; @@ -29,15 +39,14 @@ describe('build/transforms/remove-fenced-code', () => { lintTransformedFileMock.mockImplementation(() => Promise.resolve()); }); - it('rejects invalid build types', () => { - expect(() => createRemoveFencedCodeTransform('foobar')).toThrow( - /received unrecognized build type "foobar".$/u, - ); - }); - it('returns a PassThrough stream for files with ignored extensions', async () => { const fileContent = '"Valid JSON content"\n'; - const stream = createRemoveFencedCodeTransform('main')('file.json'); + const stream = createRemoveFencedCodeTransform( + getFeatures({ + active: [MAIN_BUILD], + all: [MAIN_BUILD], + }), + )('file.json'); let streamOutput = ''; await new Promise((resolve) => { @@ -60,7 +69,12 @@ describe('build/transforms/remove-fenced-code', () => { const filePrefix = '// A comment\n'; const fileContent = filePrefix.concat(getMinimalFencedCode()); - const stream = createRemoveFencedCodeTransform('main')(mockJsFileName); + const stream = createRemoveFencedCodeTransform( + getFeatures({ + active: [MAIN_BUILD], + all: [MAIN_BUILD, FLASK_BUILD], + }), + )(mockJsFileName); let streamOutput = ''; await new Promise((resolve) => { @@ -92,7 +106,12 @@ describe('build/transforms/remove-fenced-code', () => { .filter((line) => line !== '') .map((line) => `${line}\n`); - const stream = createRemoveFencedCodeTransform('main')(mockJsFileName); + const stream = createRemoveFencedCodeTransform( + getFeatures({ + active: [MAIN_BUILD], + all: [MAIN_BUILD, FLASK_BUILD], + }), + )(mockJsFileName); let streamOutput = ''; await new Promise((resolve) => { @@ -116,9 +135,14 @@ describe('build/transforms/remove-fenced-code', () => { }); it('handles file with fences that is unmodified by the transform', async () => { - const fileContent = getMinimalFencedCode('main'); + const fileContent = getMinimalFencedCode(MAIN_BUILD); - const stream = createRemoveFencedCodeTransform('main')(mockJsFileName); + const stream = createRemoveFencedCodeTransform( + getFeatures({ + active: [MAIN_BUILD], + all: [MAIN_BUILD], + }), + )(mockJsFileName); let streamOutput = ''; await new Promise((resolve) => { @@ -141,7 +165,7 @@ describe('build/transforms/remove-fenced-code', () => { const fileContent = filePrefix.concat(getMinimalFencedCode()); const stream = createRemoveFencedCodeTransform( - 'main', + getFeatures({ all: [MAIN_BUILD, FLASK_BUILD], active: [MAIN_BUILD] }), false, )(mockJsFileName); let streamOutput = ''; @@ -166,7 +190,9 @@ describe('build/transforms/remove-fenced-code', () => { '///: END:ONLY_INCLUDE_IN', ); - const stream = createRemoveFencedCodeTransform('main')(mockJsFileName); + const stream = createRemoveFencedCodeTransform( + getFeatures({ all: [MAIN_BUILD, FLASK_BUILD], active: [MAIN_BUILD] }), + )(mockJsFileName); await new Promise((resolve) => { stream.on('error', (error) => { @@ -191,7 +217,9 @@ describe('build/transforms/remove-fenced-code', () => { const filePrefix = '// A comment\n'; const fileContent = filePrefix.concat(getMinimalFencedCode()); - const stream = createRemoveFencedCodeTransform('main')(mockJsFileName); + const stream = createRemoveFencedCodeTransform( + getFeatures({ all: [FLASK_BUILD], active: [] }), + )(mockJsFileName); await new Promise((resolve) => { stream.on('error', (error) => { @@ -213,12 +241,15 @@ describe('build/transforms/remove-fenced-code', () => { const mockFileName = 'file.js'; // Valid inputs - Object.keys(BuildType).forEach((buildType) => { + ['main', 'flask', 'beta'].forEach((buildType) => { + const active = buildTypesConfig.buildTypes[buildType].features; + const all = Object.keys(buildTypesConfig.features); + const features = getFeatures({ all, active }); it(`transforms file with fences for build type "${buildType}"`, () => { expect( removeFencedCode( mockFileName, - buildType, + features, testData.validInputs.withFences, ), ).toStrictEqual(testData.validOutputs[buildType]); @@ -226,15 +257,15 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - buildType, + features, testData.validInputs.extraContentWithFences, ), ).toStrictEqual(testData.validOutputsWithExtraContent[buildType]); // Ensure that the minimal input template is in fact valid - const minimalInput = getMinimalFencedCode(buildType); + const minimalInput = getMinimalFencedCode(`build-${buildType}`); expect( - removeFencedCode(mockFileName, buildType, minimalInput), + removeFencedCode(mockFileName, features, minimalInput), ).toStrictEqual([minimalInput, false]); }); @@ -242,7 +273,7 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - buildType, + features, testData.validInputs.withoutFences, ), ).toStrictEqual([testData.validInputs.withoutFences, false]); @@ -250,7 +281,7 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - buildType, + features, testData.validInputs.extraContentWithoutFences, ), ).toStrictEqual([ @@ -265,29 +296,17 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - BuildType.flask, - getMinimalFencedCode('main'), + getFeatures({ + active: [FLASK_BUILD], + all: [FLASK_BUILD, MAIN_BUILD], + }), + getMinimalFencedCode(MAIN_BUILD), ), ).toStrictEqual(['', true]); }); - it('keeps fences with inherited build types', () => { - // Desktop inherits from the flask build type - const minimalCode = - getMinimalFencedCode(BuildType.flask) + - getMinimalFencedCode(BuildType.desktop); - - expect( - removeFencedCode(mockFileName, BuildType.desktop, minimalCode), - ).toStrictEqual([minimalCode, false]); - - expect( - removeFencedCode(mockFileName, BuildType.flask, minimalCode), - ).toStrictEqual([getMinimalFencedCode(BuildType.flask), true]); - }); - it('ignores sentinels preceded by non-whitespace', () => { - const validBeginDirective = '///: BEGIN:ONLY_INCLUDE_IN(flask)\n'; + const validBeginDirective = '///: BEGIN:ONLY_INCLUDE_IN(build-flask)\n'; const ignoredLines = [ `a ${validBeginDirective}`, `2 ${validBeginDirective}`, @@ -299,8 +318,11 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - BuildType.flask, - getMinimalFencedCode('main').concat(ignoredLine), + getFeatures({ + active: [FLASK_BUILD], + all: [FLASK_BUILD, MAIN_BUILD], + }), + getMinimalFencedCode(MAIN_BUILD).concat(ignoredLine), ), ).toStrictEqual([ignoredLine, true]); @@ -311,7 +333,7 @@ describe('build/transforms/remove-fenced-code', () => { expect( removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), modifiedInputWithoutFences, ), ).toStrictEqual([modifiedInputWithoutFences, false]); @@ -341,7 +363,11 @@ describe('build/transforms/remove-fenced-code', () => { inputs.forEach((input) => { expect(() => - removeFencedCode(mockFileName, BuildType.flask, input), + removeFencedCode( + mockFileName, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), + input, + ), ).toThrow( `Empty fence found in file "${mockFileName}":\n${emptyFence}`, ); @@ -368,7 +394,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().replace( fenceSentinelAndTerminusRegex, replacement, @@ -382,53 +408,53 @@ describe('build/transforms/remove-fenced-code', () => { it('rejects malformed BEGIN directives', () => { // This is the first line of the minimal input template - const directiveString = '///: BEGIN:ONLY_INCLUDE_IN(flask)'; + const directiveString = '///: BEGIN:ONLY_INCLUDE_IN(build-flask)'; const replacements = [ // Invalid terminus - '///: BE_GIN:ONLY_INCLUDE_IN(flask)', - '///: BE6IN:ONLY_INCLUDE_IN(flask)', - '///: BEGIN7:ONLY_INCLUDE_IN(flask)', - '///: BeGIN:ONLY_INCLUDE_IN(flask)', - '///: BE3:ONLY_INCLUDE_IN(flask)', - '///: BEG-IN:ONLY_INCLUDE_IN(flask)', - '///: BEG N:ONLY_INCLUDE_IN(flask)', + '///: BE_GIN:BEGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BE6IN:BEGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BEGIN7:BEGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BeGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BE3:BEGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BEG-IN:BEGIN:ONLY_INCLUDE_IN(build-flask)', + '///: BEG N:BEGIN:ONLY_INCLUDE_IN(build-flask)', // Invalid commands '///: BEGIN:ONLY-INCLUDE_IN(flask)', '///: BEGIN:ONLY_INCLUDE:IN(flask)', '///: BEGIN:ONL6_INCLUDE_IN(flask)', '///: BEGIN:ONLY_IN@LUDE_IN(flask)', - '///: BEGIN:ONLy_INCLUDE_IN(flask)', + '///: BEGIN:ONLy_INCLUDE_IN(build-flask)', '///: BEGIN:ONLY INCLUDE_IN(flask)', // Invalid parameters '///: BEGIN:ONLY_INCLUDE_IN(,flask)', - '///: BEGIN:ONLY_INCLUDE_IN(flask,)', - '///: BEGIN:ONLY_INCLUDE_IN(flask,,main)', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask,)', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask,,main)', '///: BEGIN:ONLY_INCLUDE_IN(,)', '///: BEGIN:ONLY_INCLUDE_IN()', '///: BEGIN:ONLY_INCLUDE_IN( )', - '///: BEGIN:ONLY_INCLUDE_IN(flask]', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask]', '///: BEGIN:ONLY_INCLUDE_IN[flask)', - '///: BEGIN:ONLY_INCLUDE_IN(flask.main)', - '///: BEGIN:ONLY_INCLUDE_IN(flask,@)', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask.main)', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask,@)', '///: BEGIN:ONLY_INCLUDE_IN(fla k)', // Stuff after the directive - '///: BEGIN:ONLY_INCLUDE_IN(flask) A', - '///: BEGIN:ONLY_INCLUDE_IN(flask) 9', - '///: BEGIN:ONLY_INCLUDE_IN(flask)A', - '///: BEGIN:ONLY_INCLUDE_IN(flask)9', - '///: BEGIN:ONLY_INCLUDE_IN(flask)_', - '///: BEGIN:ONLY_INCLUDE_IN(flask))', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask) A', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask) 9', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask)A', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask)9', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask)_', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask))', ]; replacements.forEach((replacement) => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().replace(directiveString, replacement), ), ).toThrow( @@ -474,7 +500,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().replace(directiveString, replacement), ), ).toThrow( @@ -488,14 +514,14 @@ describe('build/transforms/remove-fenced-code', () => { it('rejects files with uneven number of fence lines', () => { const additions = [ - '///: BEGIN:ONLY_INCLUDE_IN(flask)', + '///: BEGIN:ONLY_INCLUDE_IN(build-flask)', '///: END:ONLY_INCLUDE_IN', ]; additions.forEach((addition) => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().concat(addition), ), ).toThrow( @@ -515,7 +541,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().replace(validTerminus, replacement), ), ).toThrow( @@ -539,7 +565,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode().replace(validCommand, replacement), ), ).toThrow( @@ -557,10 +583,30 @@ describe('build/transforms/remove-fenced-code', () => { it('rejects invalid command parameters', () => { const testCases = [ - ['bar', ['bar', 'flask,bar', 'flask,beta,main,bar']], - ['Foo', ['Foo', 'flask,Foo', 'flask,beta,main,Foo']], - ['b3ta', ['b3ta', 'flask,b3ta', 'flask,beta,main,b3ta']], - ['bEta', ['bEta', 'flask,bEta', 'flask,beta,main,bEta']], + [ + 'bar', + ['bar', 'build-flask,bar', 'build-flask,build-beta,build-main,bar'], + ], + [ + 'Foo', + ['Foo', 'build-flask,Foo', 'build-flask,build-beta,build-main,Foo'], + ], + [ + 'b3ta', + [ + 'b3ta', + 'build-flask,b3ta', + 'build-flask,build-beta,build-main,b3ta', + ], + ], + [ + 'bEta', + [ + 'bEta', + 'build-flask,bEta', + 'build-flask,build-beta,build-main,bEta', + ], + ], ]; testCases.forEach(([invalidParam, replacements]) => { @@ -568,11 +614,17 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ + active: [FLASK_BUILD], + all: [FLASK_BUILD, MAIN_BUILD, 'build-beta'], + }), getMinimalFencedCode(replacement), ), ).toThrow( - new RegExp(`"${invalidParam}" is not a valid build type.$`, 'u'), + new RegExp( + `"${invalidParam}" is not a declared build feature.$`, + 'u', + ), ); }); }); @@ -581,7 +633,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), getMinimalFencedCode('').replace('()', ''), ), ).toThrow(/No params specified.$/u); @@ -589,7 +641,9 @@ describe('build/transforms/remove-fenced-code', () => { it('rejects directive pairs with wrong terminus order', () => { // We need more than one directive pair for this test - const input = getMinimalFencedCode().concat(getMinimalFencedCode('beta')); + const input = getMinimalFencedCode().concat( + getMinimalFencedCode('build-beta'), + ); const expectedBeginError = 'The first directive of a pair must be a "BEGIN" directive.'; @@ -597,17 +651,17 @@ describe('build/transforms/remove-fenced-code', () => { 'The second directive of a pair must be an "END" directive.'; const testCases = [ [ - 'BEGIN:ONLY_INCLUDE_IN(flask)', + 'BEGIN:ONLY_INCLUDE_IN(build-flask)', 'END:ONLY_INCLUDE_IN', expectedBeginError, ], [ /END:ONLY_INCLUDE_IN/mu, - 'BEGIN:ONLY_INCLUDE_IN(main)', + 'BEGIN:ONLY_INCLUDE_IN(build-main)', expectedEndError, ], [ - 'BEGIN:ONLY_INCLUDE_IN(beta)', + 'BEGIN:ONLY_INCLUDE_IN(build-beta)', 'END:ONLY_INCLUDE_IN', expectedBeginError, ], @@ -617,7 +671,7 @@ describe('build/transforms/remove-fenced-code', () => { expect(() => removeFencedCode( mockFileName, - BuildType.flask, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), input.replace(target, replacement), ), ).toThrow(expectedError); @@ -631,7 +685,11 @@ describe('build/transforms/remove-fenced-code', () => { '\n//# sourceMappingURL=as32e32wcwc2234f2ew32cnin4243f4nv9nsdoivnxzoivnd', ); expect( - removeFencedCode(mockFileName, BuildType.flask, input), + removeFencedCode( + mockFileName, + getFeatures({ active: [FLASK_BUILD], all: [FLASK_BUILD] }), + input, + ), ).toStrictEqual([input, false]); }); @@ -644,14 +702,14 @@ function getTestData() { const data = { validInputs: { withFences: ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -660,7 +718,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -678,7 +736,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -690,14 +748,14 @@ Conditionally_Included `, extraContentWithFences: ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -706,7 +764,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -723,7 +781,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -781,14 +839,14 @@ Always_Included validOutputs: { beta: [ ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -810,14 +868,14 @@ Always_Included ], flask: [ ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -826,7 +884,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -836,16 +894,25 @@ Always_Included Always_Included Always_Included Always_Included +///: BEGIN:ONLY_INCLUDE_IN(desktop) + +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included +///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(desktop) +Conditionally_Included +Conditionally_Included ///: END:ONLY_INCLUDE_IN `, - true, + false, ], mmi: [ ` @@ -872,14 +939,14 @@ Always_Included validOutputsWithExtraContent: { beta: [ ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -904,14 +971,14 @@ Always_Included ], flask: [ ` -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included ///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask,beta,desktop) +///: BEGIN:ONLY_INCLUDE_IN(build-flask,build-beta,desktop) Conditionally_Included Conditionally_Included @@ -920,7 +987,7 @@ Conditionally_Included Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) Conditionally_Included Conditionally_Included @@ -930,10 +997,19 @@ Always_Included Always_Included Always_Included Always_Included +///: BEGIN:ONLY_INCLUDE_IN(desktop) +Conditionally_Included +Conditionally_Included +///: END:ONLY_INCLUDE_IN Always_Included Always_Included Always_Included -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) +Conditionally_Included +Conditionally_Included + +///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(desktop) Conditionally_Included Conditionally_Included @@ -942,7 +1018,7 @@ Always_Included Always_Included Always_Included `, - true, + false, ], mmi: [ ` diff --git a/development/build/utils.js b/development/build/utils.js index ce88d1f09..9b5bd58e3 100644 --- a/development/build/utils.js +++ b/development/build/utils.js @@ -1,6 +1,6 @@ const path = require('path'); const semver = require('semver'); -const { BuildType } = require('../lib/build-type'); +const { loadBuildTypesConfig } = require('../lib/build-type'); const { BUILD_TARGETS, ENVIRONMENT } = require('./constants'); /** @@ -48,6 +48,8 @@ function getBrowserVersionMap(platforms, version) { let buildType, buildVersionSummary, buildVersion; if (prerelease) { [buildType, buildVersionSummary] = prerelease; + // TODO(ritave): Figure out why the version 10.25.0-beta.1-flask.0 in the below comment is even possible + // since those are two different build types // The version could be version: '10.25.0-beta.1-flask.0', // That results in buildVersionSummary becomes 1-flask // And we only want 1 from this string @@ -57,14 +59,7 @@ function getBrowserVersionMap(platforms, version) { : buildVersionSummary; if (!String(buildVersion).match(/^\d+$/u)) { throw new Error(`Invalid prerelease build version: '${buildVersion}'`); - } else if ( - ![ - BuildType.beta, - BuildType.flask, - BuildType.desktop, - BuildType.mmi, - ].includes(buildType) - ) { + } else if (!loadBuildTypesConfig().buildTypes[buildType].isPrerelease) { throw new Error(`Invalid prerelease build type: ${buildType}`); } } diff --git a/development/generate-lavamoat-policies.js b/development/generate-lavamoat-policies.js index 9266091b7..16a669f2c 100755 --- a/development/generate-lavamoat-policies.js +++ b/development/generate-lavamoat-policies.js @@ -2,11 +2,13 @@ const concurrently = require('concurrently'); const yargs = require('yargs/yargs'); const { hideBin } = require('yargs/helpers'); -const { BuildType } = require('./lib/build-type'); +const { loadBuildTypesConfig } = require('./lib/build-type'); -const stableBuildTypes = Object.values(BuildType).filter( +const buildTypesConfig = loadBuildTypesConfig(); + +const stableBuildTypes = Object.keys(buildTypesConfig.buildTypes).filter( // Skip generating policy for MMI until that build has stabilized - (buildType) => buildType !== BuildType.mmi, + (buildType) => buildType !== 'mmi', ); start().catch((error) => { @@ -24,7 +26,7 @@ async function start() { yargsInstance .option('build-types', { alias: ['t'], - choices: Object.values(BuildType), + choices: Object.keys(buildTypesConfig.buildTypes), default: stableBuildTypes, demandOption: true, description: 'The build type(s) to generate policy files for.', diff --git a/development/lib/build-type.d.ts b/development/lib/build-type.d.ts new file mode 100644 index 000000000..dafc9e904 --- /dev/null +++ b/development/lib/build-type.d.ts @@ -0,0 +1,6 @@ +import { Infer, Struct } from 'superstruct'; + +export type Unique> = ( + struct: Struct[], Infer>, + eq?: (a: Infer, b: Infer) => boolean, +) => Struct[], Infer>; diff --git a/development/lib/build-type.js b/development/lib/build-type.js index 762b9af45..afc5401fc 100644 --- a/development/lib/build-type.js +++ b/development/lib/build-type.js @@ -1,18 +1,169 @@ +const fs = require('fs'); +const { AssertionError } = require('assert'); +const path = require('path'); +const { + object, + string, + record, + optional, + array, + refine, + any, + boolean, + coerce, + union, + unknown, + validate, + nullable, + never, +} = require('superstruct'); +const yaml = require('js-yaml'); +const { uniqWith } = require('lodash'); + +const BUILDS_YML_PATH = path.resolve('./builds.yml'); + /** - * The distribution this build is intended for. - * - * This should be kept in-sync with the `BuildType` map in `shared/constants/app.js`. + * @type {import('superstruct').Infer | null} */ -const BuildType = { - beta: 'beta', - desktop: 'desktop', - flask: 'flask', - main: 'main', - mmi: 'mmi', -}; +let cachedBuildTypes = null; -const BuildTypeInheritance = { - [BuildType.desktop]: [BuildType.flask], -}; +/** + * Ensures that the array item contains only elements that are distinct from each other + * + * @template {Struct} Element + * @type {import('./build-type').Unique} + */ +const unique = (struct, eq) => + refine(struct, 'unique', (value) => { + if (uniqWith(value, eq).length === value.length) { + return true; + } + return 'Array contains duplicated values'; + }); -module.exports = { BuildType, BuildTypeInheritance }; +const EnvDefinitionStruct = coerce( + object({ key: string(), value: unknown() }), + refine(record(string(), any()), 'Env variable declaration', (value) => { + if (Object.keys(value).length !== 1) { + return 'Declaration should have only one property, the name'; + } + return true; + }), + (value) => ({ key: Object.keys(value)[0], value: Object.values(value)[0] }), +); + +const EnvArrayStruct = unique( + array(union([string(), EnvDefinitionStruct])), + (a, b) => { + const keyA = typeof a === 'string' ? a : a.key; + const keyB = typeof b === 'string' ? b : b.key; + return keyA === keyB; + }, +); + +const BuildTypeStruct = object({ + features: optional(unique(array(string()))), + env: optional(EnvArrayStruct), + isPrerelease: optional(boolean()), + manifestOverrides: optional(string()), +}); + +const CopyAssetStruct = object({ src: string(), dest: string() }); +const ExclusiveIncludeAssetStruct = coerce( + object({ exclusiveInclude: string() }), + string(), + (exclusiveInclude) => ({ exclusiveInclude }), +); +const AssetStruct = union([CopyAssetStruct, ExclusiveIncludeAssetStruct]); + +const FeatureStruct = object({ + env: optional(EnvArrayStruct), + // TODO(ritave): Check if the paths exist + assets: optional(array(AssetStruct)), +}); + +const FeaturesStruct = refine( + record( + string(), + coerce(FeatureStruct, nullable(never()), () => ({})), + ), + 'feature definitions', + function* (value) { + let isValid = true; + + const definitions = new Set(); + + for (const feature of Object.values(value)) { + for (const env of feature?.env ?? []) { + if (typeof env !== 'string') { + if (definitions.has(env.key)) { + isValid = false; + yield `Multiple defined features have a definition of "${env}" env variable, resulting in a conflict`; + } + definitions.add(env.key); + } + } + } + return isValid; + }, +); + +const BuildTypesStruct = refine( + object({ + default: string(), + buildTypes: record(string(), BuildTypeStruct), + features: FeaturesStruct, + env: EnvArrayStruct, + }), + 'BuildTypes', + (value) => { + if (!Object.keys(value.buildTypes).includes(value.default)) { + return `Default build type "${value.default}" does not exist in builds declarations`; + } + return true; + }, +); + +/** + * Loads definitions of build type and what they are composed of. + * + * @returns {import('superstruct').Infer} + */ +function loadBuildTypesConfig() { + if (cachedBuildTypes !== null) { + return cachedBuildTypes; + } + const buildsData = yaml.load(fs.readFileSync(BUILDS_YML_PATH, 'utf8'), { + json: true, + }); + const [err, result] = validate(buildsData, BuildTypesStruct, { + coerce: true, + }); + if (err !== undefined) { + throw new AssertionError({ + message: constructFailureMessage(err), + }); + } + cachedBuildTypes = result; + return buildsData; +} + +/** + * Creates a user readable error message about parse failure. + * + * @param {import('superstruct').StructError} structError + * @returns {string} + */ +function constructFailureMessage(structError) { + return `Failed to parse builds.yml + -> ${structError + .failures() + .map( + (failure) => + `${failure.message} (${BUILDS_YML_PATH}:.${failure.path.join('/')})`, + ) + .join('\n -> ')} +`; +} + +module.exports = { loadBuildTypesConfig }; diff --git a/development/lib/get-version.js b/development/lib/get-version.js index 9f787265f..ec40b40cb 100644 --- a/development/lib/get-version.js +++ b/development/lib/get-version.js @@ -1,5 +1,5 @@ const { version: manifestVersion } = require('../../package.json'); -const { BuildType } = require('./build-type'); +const { loadBuildTypesConfig } = require('./build-type'); /** * Get the current version of the MetaMask extension. The base manifest version @@ -8,14 +8,14 @@ const { BuildType } = require('./build-type'); * The build version is needed because certain build types (such as beta) may * be released multiple times during the release process. * - * @param {BuildType} buildType - The build type. + * @param {string} buildType - The build type. * @param {number} buildVersion - The build version. * @returns {string} The MetaMask extension version. */ function getVersion(buildType, buildVersion) { - return buildType === BuildType.main || buildType === BuildType.beta - ? manifestVersion - : `${manifestVersion}-${buildType}.${buildVersion}`; + return loadBuildTypesConfig().buildTypes[buildType].isPrerelease === true + ? `${manifestVersion}-${buildType}.${buildVersion}` + : manifestVersion; } module.exports = { getVersion }; diff --git a/development/lib/variables.js b/development/lib/variables.js new file mode 100644 index 000000000..b2fb61212 --- /dev/null +++ b/development/lib/variables.js @@ -0,0 +1,114 @@ +/* eslint-disable jsdoc/check-tag-names */ +const assert = require('assert'); + +const DeclaredOnly = Symbol( + 'This variable was declared only without being defined', +); + +class Variables { + /** + * @type {Map} + */ + #definitions = new Map(); + + /** + * @param {Iterable} declarations + */ + constructor(declarations) { + for (const declaration of declarations) { + this.#definitions.set(declaration, DeclaredOnly); + } + } + + /** + * @param {string} key - The name of the variable + * @throws {TypeError} If there is no definition of a variable. + */ + get(key) { + const value = this.getMaybe(key); + assert( + value !== DeclaredOnly, + new TypeError( + `Tried to access a declared, but not defined environmental variable "${key}"`, + ), + ); + return value; + } + + /** + * Returns a declared, but maybe not defined variable. + * + * @param {string} key - The name of the variable + * @throws {TypeError} If there was no declaration of the variable. + * @returns The value, or undefined if the variables wasn't defined. + */ + getMaybe(key) { + assert( + this.isDeclared(key), + new TypeError( + `Tried to access an environmental variable "${key}" that wasn't declared in builds.yml`, + ), + ); + return this.#definitions.get(key); + } + + /** + * Sets one key + * + * @overload + * @param {string} key + * @param {unknown} value + * @returns {void} + */ + /** + * @overload + * @param {Record} records - Key-Value object + * @returns {void} + */ + /** + * @param {string | Record} keyOrRecord + * @param {unknown} value + * @returns {void} + */ + set(keyOrRecord, value) { + if (typeof keyOrRecord === 'object') { + for (const [key, recordValue] of Object.entries(keyOrRecord)) { + this.set(key, recordValue); + } + return; + } + const key = keyOrRecord; + assert( + this.isDeclared(key), + `Tried to modify a variable "${key}" that wasn't declared in builds.yml`, + ); + assert(value !== DeclaredOnly, `Tried to un-define "${key}" variable`); + this.#definitions.set(key, value); + } + + isDeclared(key) { + return this.#definitions.has(key); + } + + isDefined(key) { + return ( + this.#definitions.has(key) && this.#definitions.get(key) !== DeclaredOnly + ); + } + + [Symbol.iterator] = this.declarations; + + *declarations() { + yield* this.#definitions.keys(); + } + + *definitions() { + for (const [key, value] of this.#definitions.entries()) { + if (value !== DeclaredOnly) { + yield [key, value]; + } + } + } +} + +module.exports = { Variables }; diff --git a/development/sentry-publish.js b/development/sentry-publish.js index 5a988c65b..3645e04b6 100755 --- a/development/sentry-publish.js +++ b/development/sentry-publish.js @@ -5,7 +5,7 @@ const { hideBin } = require('yargs/helpers'); const { runCommand, runInShell } = require('./lib/run-command'); const { getVersion } = require('./lib/get-version'); -const { BuildType } = require('./lib/build-type'); +const { loadBuildTypesConfig } = require('./lib/build-type'); start().catch((error) => { console.error(error); @@ -29,9 +29,9 @@ async function start() { type: 'string', }) .option('build-type', { - default: BuildType.main, + default: loadBuildTypesConfig().default, description: 'The MetaMask extension build type', - choices: Object.values(BuildType), + choices: Object.keys(loadBuildTypesConfig().buildTypes), }) .option('build-version', { default: 0, @@ -86,7 +86,7 @@ async function start() { } const additionalUploadArgs = []; - if (buildType !== BuildType.main) { + if (buildType !== loadBuildTypesConfig().default) { additionalUploadArgs.push('--dist-directory', `dist-${buildType}`); } // upload sentry source and sourcemaps diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 6b48762c4..8b8b6b334 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -716,7 +716,7 @@ "@metamask/assets-controllers>@metamask/abi-utils": { "packages": { "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": { @@ -725,10 +725,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/assets-controllers>abort-controller": { @@ -821,10 +821,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { @@ -869,10 +869,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-provider": { @@ -1192,10 +1192,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/key-tree>@noble/ed25519": { @@ -1317,7 +1317,7 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { @@ -1443,10 +1443,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/utils>@ethereumjs/tx>@chainsafe/ssz": { @@ -2659,10 +2659,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "eth-ens-namehash": { @@ -2780,7 +2780,6 @@ "@ethersproject/abi": true, "bn.js": true, "browserify>buffer": true, - "browserify>process": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>bech32": true, diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index f84728167..78d89d6b0 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -716,7 +716,7 @@ "@metamask/assets-controllers>@metamask/abi-utils": { "packages": { "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": { @@ -725,10 +725,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/assets-controllers>abort-controller": { @@ -827,7 +827,6 @@ "@metamask/desktop>otpauth": true, "browserify>buffer": true, "browserify>events": true, - "browserify>process": true, "browserify>stream-browserify": true, "end-of-stream": true, "extension-port-stream": true, @@ -893,10 +892,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { @@ -941,10 +940,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-provider": { @@ -1264,10 +1263,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/key-tree>@noble/ed25519": { @@ -1414,10 +1413,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/post-message-stream>readable-stream": { @@ -1479,8 +1478,8 @@ "@metamask/snaps-ui": true, "@metamask/snaps-utils": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { @@ -1771,7 +1770,7 @@ "@metamask/snaps-ui": { "packages": { "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/snaps-utils": { @@ -1792,15 +1791,15 @@ "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/snaps-utils>@metamask/snaps-registry": { "packages": { "@metamask/key-tree>@noble/secp256k1": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/snaps-utils>cron-parser": { @@ -1836,10 +1835,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/utils>@ethereumjs/tx>@chainsafe/ssz": { @@ -3052,10 +3051,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "eth-ens-namehash": { @@ -3173,7 +3172,6 @@ "@ethersproject/abi": true, "bn.js": true, "browserify>buffer": true, - "browserify>process": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>bech32": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index f84728167..78d89d6b0 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -716,7 +716,7 @@ "@metamask/assets-controllers>@metamask/abi-utils": { "packages": { "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": { @@ -725,10 +725,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/assets-controllers>abort-controller": { @@ -827,7 +827,6 @@ "@metamask/desktop>otpauth": true, "browserify>buffer": true, "browserify>events": true, - "browserify>process": true, "browserify>stream-browserify": true, "end-of-stream": true, "extension-port-stream": true, @@ -893,10 +892,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { @@ -941,10 +940,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-provider": { @@ -1264,10 +1263,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/key-tree>@noble/ed25519": { @@ -1414,10 +1413,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/post-message-stream>readable-stream": { @@ -1479,8 +1478,8 @@ "@metamask/snaps-ui": true, "@metamask/snaps-utils": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true, - "eth-rpc-errors": true + "eth-rpc-errors": true, + "superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { @@ -1771,7 +1770,7 @@ "@metamask/snaps-ui": { "packages": { "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/snaps-utils": { @@ -1792,15 +1791,15 @@ "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/snaps-utils>@metamask/snaps-registry": { "packages": { "@metamask/key-tree>@noble/secp256k1": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/snaps-utils>cron-parser": { @@ -1836,10 +1835,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/utils>@ethereumjs/tx>@chainsafe/ssz": { @@ -3052,10 +3051,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "eth-ens-namehash": { @@ -3173,7 +3172,6 @@ "@ethersproject/abi": true, "bn.js": true, "browserify>buffer": true, - "browserify>process": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>bech32": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 6b48762c4..8b8b6b334 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -716,7 +716,7 @@ "@metamask/assets-controllers>@metamask/abi-utils": { "packages": { "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/assets-controllers>@metamask/abi-utils>@metamask/utils": { @@ -725,10 +725,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/assets-controllers>abort-controller": { @@ -821,10 +821,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-infura>eth-json-rpc-middleware": { @@ -869,10 +869,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/eth-json-rpc-provider": { @@ -1192,10 +1192,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/key-tree>@noble/ed25519": { @@ -1317,7 +1317,7 @@ "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/utils": true, - "@metamask/utils>superstruct": true + "superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { @@ -1443,10 +1443,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "@metamask/utils>@ethereumjs/tx>@chainsafe/ssz": { @@ -2659,10 +2659,10 @@ "TextEncoder": true }, "packages": { - "@metamask/utils>superstruct": true, "browserify>buffer": true, "nock>debug": true, - "semver": true + "semver": true, + "superstruct": true } }, "eth-ens-namehash": { @@ -2780,7 +2780,6 @@ "@ethersproject/abi": true, "bn.js": true, "browserify>buffer": true, - "browserify>process": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/common": true, "eth-lattice-keyring>gridplus-sdk>@ethereumjs/tx": true, "eth-lattice-keyring>gridplus-sdk>bech32": true, diff --git a/package.json b/package.json index 01d1e9abc..5deb72096 100644 --- a/package.json +++ b/package.json @@ -531,6 +531,7 @@ "string.prototype.matchall": "^4.0.2", "style-loader": "^0.21.0", "stylelint": "^13.6.1", + "superstruct": "^1.0.3", "terser": "^5.7.0", "through2": "^4.0.2", "ts-node": "^10.5.0", diff --git a/shared/constants/app.ts b/shared/constants/app.ts index c8be0573e..3b99fa5e7 100644 --- a/shared/constants/app.ts +++ b/shared/constants/app.ts @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { DialogType } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN import { RestrictedMethods } from './permissions'; @@ -20,18 +20,6 @@ export const ENVIRONMENT_TYPE_NOTIFICATION = 'notification'; export const ENVIRONMENT_TYPE_FULLSCREEN = 'fullscreen'; export const ENVIRONMENT_TYPE_BACKGROUND = 'background'; -/** - * The distribution this build is intended for. - * - * This should be kept in-sync with the `BuildType` map in `development/build/utils.js`. - */ -export const BuildType = { - beta: 'beta', - desktop: 'desktop', - flask: 'flask', - main: 'main', -} as const; - export const PLATFORM_BRAVE = 'Brave'; export const PLATFORM_CHROME = 'Chrome'; export const PLATFORM_EDGE = 'Edge'; @@ -57,12 +45,12 @@ export const MESSAGE_TYPE = { WALLET_REQUEST_PERMISSIONS: 'wallet_requestPermissions', WATCH_ASSET: 'wallet_watchAsset', WATCH_ASSET_LEGACY: 'metamask_watchAsset', - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) SNAP_DIALOG_ALERT: `${RestrictedMethods.snap_dialog}:alert`, SNAP_DIALOG_CONFIRMATION: `${RestrictedMethods.snap_dialog}:confirmation`, SNAP_DIALOG_PROMPT: `${RestrictedMethods.snap_dialog}:prompt`, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) MMI_AUTHENTICATE: 'metamaskinstitutional_authenticate', MMI_REAUTHENTICATE: 'metamaskinstitutional_reauthenticate', MMI_REFRESH_TOKEN: 'metamaskinstitutional_refresh_token', @@ -75,7 +63,7 @@ export const MESSAGE_TYPE = { ///: END:ONLY_INCLUDE_IN } as const; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) export const SNAP_DIALOG_TYPES = { [DialogType.Alert]: MESSAGE_TYPE.SNAP_DIALOG_ALERT, [DialogType.Confirmation]: MESSAGE_TYPE.SNAP_DIALOG_CONFIRMATION, diff --git a/shared/constants/environment.js b/shared/constants/environment.js deleted file mode 100644 index ffc551ccd..000000000 --- a/shared/constants/environment.js +++ /dev/null @@ -1,2 +0,0 @@ -export const isMain = process.env.METAMASK_BUILD_TYPE === 'main'; -export const isFlask = process.env.METAMASK_BUILD_TYPE === 'flask'; diff --git a/shared/constants/metametrics.ts b/shared/constants/metametrics.ts index 04ac9be94..24af084f8 100644 --- a/shared/constants/metametrics.ts +++ b/shared/constants/metametrics.ts @@ -538,7 +538,7 @@ export enum MetaMetricsEventName { OnboardingWalletVideoPlay = 'SRP Intro Video Played', OnboardingTwitterClick = 'External Link Clicked', ServiceWorkerRestarted = 'Service Worker Restarted', - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) UserClickedDeepLink = 'User clicked deeplink', ///: END:ONLY_INCLUDE_IN } @@ -580,7 +580,7 @@ export enum MetaMetricsEventCategory { Wallet = 'Wallet', Desktop = 'Desktop', ServiceWorkers = 'service_workers', - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) MMI = 'Institutional', ///: END:ONLY_INCLUDE_IN } diff --git a/shared/constants/permissions.ts b/shared/constants/permissions.ts index 4de83b52f..97a72267d 100644 --- a/shared/constants/permissions.ts +++ b/shared/constants/permissions.ts @@ -4,7 +4,7 @@ export const CaveatTypes = Object.freeze({ export const RestrictedMethods = Object.freeze({ eth_accounts: 'eth_accounts', - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) snap_dialog: 'snap_dialog', snap_notify: 'snap_notify', snap_manageState: 'snap_manageState', @@ -16,7 +16,7 @@ export const RestrictedMethods = Object.freeze({ ///: END:ONLY_INCLUDE_IN } as const); -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * Exclude permissions by code fencing them to avoid any potential usage of excluded permissions at runtime. See: https://github.com/MetaMask/metamask-extension/pull/17321#pullrequestreview-1287014285. * This is a fix for https://github.com/MetaMask/snaps-monorepo/issues/1103 and https://github.com/MetaMask/snaps-monorepo/issues/990. diff --git a/shared/constants/snaps.ts b/shared/constants/snaps.ts index 6a272cbb8..f3f43e557 100644 --- a/shared/constants/snaps.ts +++ b/shared/constants/snaps.ts @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import type { SupportedCurve } from '@metamask/key-tree'; type SnapsMetadata = { diff --git a/shared/constants/transaction.ts b/shared/constants/transaction.ts index 5e136b814..dad1a72e1 100644 --- a/shared/constants/transaction.ts +++ b/shared/constants/transaction.ts @@ -308,7 +308,7 @@ interface DappSuggestedGasFees { * An object representing a transaction, in whatever state it is in. */ export interface TransactionMeta { - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) custodyStatus: string; custodyId?: string; ///: END:ONLY_INCLUDE_IN diff --git a/shared/lib/error-utils.js b/shared/lib/error-utils.js index 631fd04b0..d7a7d284d 100644 --- a/shared/lib/error-utils.js +++ b/shared/lib/error-utils.js @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import browser from 'webextension-polyfill'; ///: END:ONLY_INCLUDE_IN import { memoize } from 'lodash'; @@ -7,7 +7,7 @@ import { fetchLocale, loadRelativeTimeFormatLocaleData, } from '../../ui/helpers/utils/i18n-helper'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import { renderDesktopError } from '../../ui/pages/desktop-error/render-desktop-error'; import { EXTENSION_ERROR_PAGE_TYPES } from '../constants/desktop'; import { openCustomProtocol } from './deep-linking'; @@ -44,7 +44,7 @@ export async function getErrorHtml( errorKey, supportLink, metamaskState, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) err, ///: END:ONLY_INCLUDE_IN ) { @@ -65,7 +65,7 @@ export async function getErrorHtml( const { currentLocaleMessages, enLocaleMessages } = response; const t = getLocaleContext(currentLocaleMessages, enLocaleMessages); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) const isDesktopEnabled = metamaskState?.desktopEnabled === true; if (isDesktopEnabled) { @@ -120,7 +120,7 @@ export async function getErrorHtml( `; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) export const MMD_DOWNLOAD_LINK = 'https://github.com/MetaMask/metamask-desktop/releases'; diff --git a/shared/lib/ui-utils.js b/shared/lib/ui-utils.js index 5fbac0b74..4cbc5fddf 100644 --- a/shared/lib/ui-utils.js +++ b/shared/lib/ui-utils.js @@ -1,14 +1,6 @@ -let _supportLink = 'https://support.metamask.io'; - -///: BEGIN:ONLY_INCLUDE_IN(mmi) -_supportLink = 'https://mmi-support.zendesk.com/hc/en-us'; -///: END:ONLY_INCLUDE_IN - -///: BEGIN:ONLY_INCLUDE_IN(flask) -_supportLink = 'https://metamask-flask.zendesk.com/hc'; -///: END:ONLY_INCLUDE_IN - -export const SUPPORT_LINK = _supportLink; +// no destructuring as process.env detection stops working +// eslint-disable-next-line prefer-destructuring +export const SUPPORT_LINK = process.env.SUPPORT_LINK; export const COINGECKO_LINK = 'https://www.coingecko.com/'; export const CRYPTOCOMPARE_LINK = 'https://www.cryptocompare.com/'; diff --git a/test/env.js b/test/env.js index 38e4a6fed..fd055ee8a 100644 --- a/test/env.js +++ b/test/env.js @@ -1 +1,2 @@ -process.env.METAMASK_ENV = 'test'; +process.env.METAMASK_ENVIRONMENT = 'test'; +process.env.SUPPORT_LINK = 'https://support.metamask.io'; diff --git a/ui/components/app/account-menu/account-menu.component.js b/ui/components/app/account-menu/account-menu.component.js index 7c0b98bc3..37f5c5a6b 100644 --- a/ui/components/app/account-menu/account-menu.component.js +++ b/ui/components/app/account-menu/account-menu.component.js @@ -17,7 +17,7 @@ import SiteIcon from '../../ui/site-icon'; import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'; import { PRIMARY, - ///: BEGIN:ONLY_INCLUDE_IN(beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta,build-flask) SUPPORT_REQUEST_LINK, ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/common'; @@ -27,7 +27,7 @@ import { IMPORT_ACCOUNT_ROUTE, CONNECT_HARDWARE_ROUTE, DEFAULT_ROUTE, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) NOTIFICATIONS_ROUTE, ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/routes'; @@ -88,7 +88,7 @@ export default class AccountMenu extends Component { toggleAccountMenu: PropTypes.func, addressConnectedSubjectMap: PropTypes.object, originOfCurrentTab: PropTypes.string, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount: PropTypes.number, ///: END:ONLY_INCLUDE_IN }; @@ -310,7 +310,7 @@ export default class AccountMenu extends Component { toggleAccountMenu, lockMetamask, history, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount, ///: END:ONLY_INCLUDE_IN } = this.props; @@ -321,7 +321,7 @@ export default class AccountMenu extends Component { let supportText = t('support'); let supportLink = SUPPORT_LINK; - ///: BEGIN:ONLY_INCLUDE_IN(beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta,build-flask) supportText = t('needHelpSubmitTicket'); supportLink = SUPPORT_REQUEST_LINK; ///: END:ONLY_INCLUDE_IN @@ -415,7 +415,7 @@ export default class AccountMenu extends Component { />
{ - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) <> { diff --git a/ui/components/app/account-menu/account-menu.container.js b/ui/components/app/account-menu/account-menu.container.js index ce702f0be..72a012105 100644 --- a/ui/components/app/account-menu/account-menu.container.js +++ b/ui/components/app/account-menu/account-menu.container.js @@ -13,7 +13,7 @@ import { getMetaMaskKeyrings, getOriginOfCurrentTab, getSelectedAddress, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getUnreadNotificationsCount, ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; @@ -31,7 +31,7 @@ function mapStateToProps(state) { const accounts = getMetaMaskAccountsOrdered(state); const origin = getOriginOfCurrentTab(state); const selectedAddress = getSelectedAddress(state); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const unreadNotificationsCount = getUnreadNotificationsCount(state); ///: END:ONLY_INCLUDE_IN return { @@ -42,7 +42,7 @@ function mapStateToProps(state) { keyrings: getMetaMaskKeyrings(state), accounts, shouldShowAccountsSearch: accounts.length >= SHOW_SEARCH_ACCOUNTS_MIN_COUNT, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount, ///: END:ONLY_INCLUDE_IN }; diff --git a/ui/components/app/account-menu/keyring-label.js b/ui/components/app/account-menu/keyring-label.js index ea406541f..716ae566a 100644 --- a/ui/components/app/account-menu/keyring-label.js +++ b/ui/components/app/account-menu/keyring-label.js @@ -35,7 +35,7 @@ export default function KeyRingLabel({ keyring }) { label = null; } - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) if (type.startsWith('Custody') && /JSONRPC/u.test(type)) { label = type.split(' - ')[1]; return null; diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index d23946d94..b6422b632 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -34,15 +34,15 @@ @import 'edit-gas-fee-popover/network-statistics/status-slider/index'; @import 'edit-gas-fee-popover/edit-gas-tooltip/index'; @import 'flask/experimental-area/index'; -@import 'flask/snap-content-footer/index'; -@import 'flask/snap-install-warning/index'; -@import 'flask/snap-remove-warning/index'; -@import 'flask/snap-ui-renderer/index'; -@import 'flask/snap-ui-markdown/index'; -@import 'flask/snap-delineator/index'; -@import 'flask/snap-settings-card/index'; -@import 'flask/update-snap-permission-list/index'; -@import 'flask/copyable/index'; +@import 'snaps/snap-content-footer/index'; +@import 'snaps/snap-install-warning/index'; +@import 'snaps/snap-remove-warning/index'; +@import 'snaps/snap-ui-renderer/index'; +@import 'snaps/snap-ui-markdown/index'; +@import 'snaps/snap-delineator/index'; +@import 'snaps/snap-settings-card/index'; +@import 'snaps/update-snap-permission-list/index'; +@import 'snaps/copyable/index'; @import 'gas-details-item/index'; @import 'gas-details-item/gas-details-item-title/index'; @import 'gas-timing/index'; diff --git a/ui/components/app/app-header/app-header.component.js b/ui/components/app/app-header/app-header.component.js index 6ef03c773..d0ccab4a4 100644 --- a/ui/components/app/app-header/app-header.component.js +++ b/ui/components/app/app-header/app-header.component.js @@ -10,9 +10,9 @@ import { } from '../../../../shared/constants/metametrics'; import NetworkDisplay from '../network-display'; -///: BEGIN:ONLY_INCLUDE_IN(beta) +///: BEGIN:ONLY_INCLUDE_IN(build-beta) import BetaHeader from '../beta-header'; -///: END:ONLY_INCLUDE_IN(beta) +///: END:ONLY_INCLUDE_IN export default class AppHeader extends PureComponent { static propTypes = { @@ -27,11 +27,13 @@ export default class AppHeader extends PureComponent { disabled: PropTypes.bool, disableNetworkIndicator: PropTypes.bool, isAccountMenuOpen: PropTypes.bool, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount: PropTypes.number, + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled: PropTypes.bool, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) showBetaHeader: PropTypes.bool, ///: END:ONLY_INCLUDE_IN onClick: PropTypes.func, @@ -77,7 +79,7 @@ export default class AppHeader extends PureComponent { selectedAddress, disabled, isAccountMenuOpen, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount, ///: END:ONLY_INCLUDE_IN } = this.props; @@ -104,7 +106,7 @@ export default class AppHeader extends PureComponent { > { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount > 0 && (
{unreadNotificationsCount} @@ -124,10 +126,10 @@ export default class AppHeader extends PureComponent { disableNetworkIndicator, disabled, onClick, - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) showBetaHeader, - ///: END:ONLY_INCLUDE_IN(beta) - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN } = this.props; @@ -135,9 +137,9 @@ export default class AppHeader extends PureComponent { return ( <> { - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) showBetaHeader ? : null - ///: END:ONLY_INCLUDE_IN(beta) + ///: END:ONLY_INCLUDE_IN }
@@ -152,7 +154,7 @@ export default class AppHeader extends PureComponent { }} /> { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled && process.env.METAMASK_DEBUG && (
{ selectedAddress, isUnlocked, isAccountMenuOpen, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN } = metamask; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const unreadNotificationsCount = getUnreadNotificationsCount(state); ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) const showBetaHeader = getShowBetaHeader(state); ///: END:ONLY_INCLUDE_IN @@ -38,11 +38,13 @@ const mapStateToProps = (state) => { selectedAddress, isUnlocked, isAccountMenuOpen, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) unreadNotificationsCount, + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) showBetaHeader, ///: END:ONLY_INCLUDE_IN }; diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index c10bb8c06..75e766274 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -24,7 +24,7 @@ export default class ConfirmPageContainerContent extends Component { dataComponent: PropTypes.node, dataHexComponent: PropTypes.node, detailsComponent: PropTypes.node, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) insightComponent: PropTypes.node, ///: END:ONLY_INCLUDE_IN errorKey: PropTypes.string, @@ -59,7 +59,7 @@ export default class ConfirmPageContainerContent extends Component { renderContent() { const { detailsComponent, dataComponent } = this.props; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const { insightComponent } = this.props; if (insightComponent && (detailsComponent || dataComponent)) { @@ -73,7 +73,7 @@ export default class ConfirmPageContainerContent extends Component { return ( detailsComponent || - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) insightComponent || ///: END:ONLY_INCLUDE_IN dataComponent @@ -86,7 +86,7 @@ export default class ConfirmPageContainerContent extends Component { detailsComponent, dataComponent, dataHexComponent, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) insightComponent, ///: END:ONLY_INCLUDE_IN } = this.props; @@ -120,7 +120,7 @@ export default class ConfirmPageContainerContent extends Component { )} { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) insightComponent ///: END:ONLY_INCLUDE_IN } diff --git a/ui/components/app/confirm-page-container/confirm-page-container.component.js b/ui/components/app/confirm-page-container/confirm-page-container.component.js index 1c9b74d6a..205d9dd65 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.component.js @@ -30,9 +30,9 @@ import NetworkAccountBalanceHeader from '../network-account-balance-header/netwo import { fetchTokenBalance } from '../../../../shared/lib/token-util.ts'; import SetApproveForAllWarning from '../set-approval-for-all-warning'; import { useI18nContext } from '../../../hooks/useI18nContext'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import useTransactionInsights from '../../../hooks/useTransactionInsights'; -///: END:ONLY_INCLUDE_IN(flask) +///: END:ONLY_INCLUDE_IN import { getAccountName, getAddressBookEntry, @@ -140,7 +140,7 @@ const ConfirmPageContainer = (props) => { setCollectionBalance(tokenBalance?.balance?.words?.[0] || 0); }, [fromAddress, tokenAddress]); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) // As confirm-transction-base is converted to functional component // this code can bemoved to it. const insightComponent = useTransactionInsights({ @@ -206,7 +206,7 @@ const ConfirmPageContainer = (props) => { detailsComponent={detailsComponent} dataComponent={dataComponent} dataHexComponent={dataHexComponent} - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) insightComponent={insightComponent} ///: END:ONLY_INCLUDE_IN errorMessage={errorMessage} diff --git a/ui/components/app/confirm-page-container/index.js b/ui/components/app/confirm-page-container/index.js index 011248f2f..5d2ea8039 100644 --- a/ui/components/app/confirm-page-container/index.js +++ b/ui/components/app/confirm-page-container/index.js @@ -7,6 +7,6 @@ export { default as ConfirmPageContainerContent, ConfirmPageContainerSummary, } from './confirm-page-container-content'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -export { SnapInsight } from './flask/snap-insight'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +export { SnapInsight } from './snaps/snap-insight'; ///: END:ONLY_INCLUDE_IN diff --git a/ui/components/app/confirm-page-container/index.scss b/ui/components/app/confirm-page-container/index.scss index ca1ac9fb1..d3e8878f1 100644 --- a/ui/components/app/confirm-page-container/index.scss +++ b/ui/components/app/confirm-page-container/index.scss @@ -2,8 +2,8 @@ @import 'confirm-page-container-header/index'; @import 'confirm-detail-row/index'; @import 'confirm-page-container-navigation/index'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -@import 'flask/index'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +@import 'snaps/index'; ///: END:ONLY_INCLUDE_IN .confirm-page-container { diff --git a/ui/components/app/confirm-page-container/flask/index.js b/ui/components/app/confirm-page-container/snaps/index.js similarity index 100% rename from ui/components/app/confirm-page-container/flask/index.js rename to ui/components/app/confirm-page-container/snaps/index.js diff --git a/ui/components/app/confirm-page-container/flask/index.scss b/ui/components/app/confirm-page-container/snaps/index.scss similarity index 100% rename from ui/components/app/confirm-page-container/flask/index.scss rename to ui/components/app/confirm-page-container/snaps/index.scss diff --git a/ui/components/app/confirm-page-container/flask/snap-insight.js b/ui/components/app/confirm-page-container/snaps/snap-insight.js similarity index 92% rename from ui/components/app/confirm-page-container/flask/snap-insight.js rename to ui/components/app/confirm-page-container/snaps/snap-insight.js index 13d182736..fbfe07ca3 100644 --- a/ui/components/app/confirm-page-container/flask/snap-insight.js +++ b/ui/components/app/confirm-page-container/snaps/snap-insight.js @@ -13,13 +13,13 @@ import { TextVariant, } from '../../../../helpers/constants/design-system'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import { useTransactionInsightSnap } from '../../../../hooks/flask/useTransactionInsightSnap'; +import { useTransactionInsightSnap } from '../../../../hooks/snaps/useTransactionInsightSnap'; import Box from '../../../ui/box/box'; -import { SnapUIRenderer } from '../../flask/snap-ui-renderer'; -import { SnapDelineator } from '../../flask/snap-delineator'; +import { SnapUIRenderer } from '../../snaps/snap-ui-renderer'; +import { SnapDelineator } from '../../snaps/snap-delineator'; import { DelineatorType } from '../../../../helpers/constants/flask'; import { getSnapName } from '../../../../helpers/utils/util'; -import { Copyable } from '../../flask/copyable'; +import { Copyable } from '../../snaps/copyable'; import { getTargetSubjectMetadata } from '../../../../selectors'; export const SnapInsight = ({ transaction, origin, chainId, selectedSnap }) => { diff --git a/ui/components/app/metamask-template-renderer/safe-component-list.js b/ui/components/app/metamask-template-renderer/safe-component-list.js index accd11841..d76f7298a 100644 --- a/ui/components/app/metamask-template-renderer/safe-component-list.js +++ b/ui/components/app/metamask-template-renderer/safe-component-list.js @@ -12,11 +12,11 @@ import TextField from '../../ui/text-field'; import ConfirmationNetworkSwitch from '../../../pages/confirmation/components/confirmation-network-switch'; import UrlIcon from '../../ui/url-icon'; import Tooltip from '../../ui/tooltip/tooltip'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -import { SnapDelineator } from '../flask/snap-delineator'; -import { Copyable } from '../flask/copyable'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import { SnapDelineator } from '../snaps/snap-delineator'; +import { Copyable } from '../snaps/copyable'; import Spinner from '../../ui/spinner'; -import { SnapUIMarkdown } from '../flask/snap-ui-markdown'; +import { SnapUIMarkdown } from '../snaps/snap-ui-markdown'; ///: END:ONLY_INCLUDE_IN export const safeComponentList = { @@ -40,7 +40,7 @@ export const safeComponentList = { TruncatedDefinitionList, Typography, UrlIcon, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapDelineator, Copyable, Spinner, diff --git a/ui/components/app/permission-page-container/permission-page-container.component.js b/ui/components/app/permission-page-container/permission-page-container.component.js index 806b2c7e2..188290d71 100644 --- a/ui/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/components/app/permission-page-container/permission-page-container.component.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { isEqual } from 'lodash'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { isObject } from '@metamask/utils'; import { SnapCaveatType, @@ -11,7 +11,7 @@ import { import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics'; import { PageContainerFooter } from '../../ui/page-container'; import PermissionsConnectFooter from '../permissions-connect-footer'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { RestrictedMethods } from '../../../../shared/constants/permissions'; ///: END:ONLY_INCLUDE_IN import { PermissionPageContainerContent } from '.'; @@ -22,7 +22,7 @@ export default class PermissionPageContainer extends Component { rejectPermissionsRequest: PropTypes.func.isRequired, selectedIdentities: PropTypes.array, allIdentitiesSelected: PropTypes.bool, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions: PropTypes.object, ///: END:ONLY_INCLUDE_IN request: PropTypes.object, @@ -41,7 +41,7 @@ export default class PermissionPageContainer extends Component { requestMetadata: {}, selectedIdentities: [], allIdentitiesSelected: false, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions: {}, ///: END:ONLY_INCLUDE_IN }; @@ -70,7 +70,7 @@ export default class PermissionPageContainer extends Component { getRequestedMethodState(methodNames) { return methodNames.reduce((acc, methodName) => { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) if (methodName === RestrictedMethods.wallet_snap) { acc[methodName] = this.getDedupedSnapPermissions(); return acc; @@ -81,7 +81,7 @@ export default class PermissionPageContainer extends Component { }, {}); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getDedupedSnapPermissions() { const permission = this.props.request.permissions[WALLET_SNAP_PERMISSION_KEY]; diff --git a/ui/components/app/permission-page-container/permission-page-container.container.js b/ui/components/app/permission-page-container/permission-page-container.container.js index 47aaf070e..f84a7c254 100644 --- a/ui/components/app/permission-page-container/permission-page-container.container.js +++ b/ui/components/app/permission-page-container/permission-page-container.container.js @@ -1,7 +1,7 @@ import { connect } from 'react-redux'; import { getMetaMaskIdentities, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getPermissions, ///: END:ONLY_INCLUDE_IN } from '../../../selectors'; @@ -9,7 +9,7 @@ import PermissionPageContainer from './permission-page-container.component'; const mapStateToProps = (state, ownProps) => { const { selectedIdentities } = ownProps; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const currentPermissions = getPermissions( state, ownProps.request.metadata?.origin, @@ -22,7 +22,7 @@ const mapStateToProps = (state, ownProps) => { return { allIdentitiesSelected, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) currentPermissions, ///: END:ONLY_INCLUDE_IN }; diff --git a/ui/components/app/permissions-connect-header/permissions-connect-header.component.js b/ui/components/app/permissions-connect-header/permissions-connect-header.component.js index 9b7fa112e..92aea43b5 100644 --- a/ui/components/app/permissions-connect-header/permissions-connect-header.component.js +++ b/ui/components/app/permissions-connect-header/permissions-connect-header.component.js @@ -7,12 +7,12 @@ import { FLEX_DIRECTION, JustifyContent, } from '../../../helpers/constants/design-system'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -import SnapAuthorship from '../flask/snap-authorship'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import SnapAuthorship from '../snaps/snap-authorship'; ///: END:ONLY_INCLUDE_IN export default class PermissionsConnectHeader extends Component { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) static contextTypes = { t: PropTypes.func, }; @@ -28,7 +28,7 @@ export default class PermissionsConnectHeader extends Component { headerText: PropTypes.string, leftIcon: PropTypes.node, rightIcon: PropTypes.node, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapVersion: PropTypes.string, isSnapInstallOrUpdate: PropTypes.bool, ///: END:ONLY_INCLUDE_IN @@ -48,12 +48,12 @@ export default class PermissionsConnectHeader extends Component { siteOrigin, leftIcon, rightIcon, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) isSnapInstallOrUpdate, ///: END:ONLY_INCLUDE_IN } = this.props; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) if (isSnapInstallOrUpdate) { return null; } @@ -80,7 +80,7 @@ export default class PermissionsConnectHeader extends Component { className, headerTitle, headerText, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) siteOrigin, isSnapInstallOrUpdate, ///: END:ONLY_INCLUDE_IN @@ -95,7 +95,7 @@ export default class PermissionsConnectHeader extends Component { {this.renderHeaderIcon()}
{headerTitle}
{ - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) isSnapInstallOrUpdate && ///: END:ONLY_INCLUDE_IN } 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 d6b432035..c422553bf 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 @@ -8,7 +8,7 @@ import { MESSAGE_TYPE } from '../../../../shared/constants/app'; import { getURLHostName, sanitizeString, - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) shortenAddress, ///: END:ONLY_INCLUDE_IN } from '../../../helpers/utils/util'; @@ -23,7 +23,7 @@ import { FONT_WEIGHT, TEXT_ALIGN, TextColor, - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) IconColor, DISPLAY, BLOCK_SIZES, @@ -40,7 +40,7 @@ import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../security-provider-banne import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; import { getValueFromWeiHex } from '../../../../shared/modules/conversion.utils'; -///: BEGIN:ONLY_INCLUDE_IN(mmi) +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import { Icon, IconName, Text } from '../../component-library'; import Box from '../../ui/box/box'; ///: END:ONLY_INCLUDE_IN @@ -73,7 +73,7 @@ export default class SignatureRequestOriginal extends Component { showRejectTransactionsConfirmationModal: PropTypes.func.isRequired, cancelAll: PropTypes.func.isRequired, provider: PropTypes.object, - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) selectedAccount: PropTypes.object, ///: END:ONLY_INCLUDE_IN }; @@ -185,7 +185,7 @@ export default class SignatureRequestOriginal extends Component { ) : null} { - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) this.props.selectedAccount.address === this.props.fromAccount.address ? null : ( { const primaryTokenImage = useSelector(getNativeCurrencyImage); const defaultSwapsToken = useSelector(getSwapsDefaultToken); - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) const mmiPortfolioEnabled = useSelector(getMmiPortfolioEnabled); const mmiPortfolioUrl = useSelector(getMmiPortfolioUrl); @@ -156,7 +156,7 @@ const EthOverview = ({ className }) => { * ) : null} { - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) process.env.MULTICHAIN ? null : ( { buttons={ <> { - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) { } { - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) renderInstitutionalButtons() ///: END:ONLY_INCLUDE_IN } @@ -309,7 +309,7 @@ const EthOverview = ({ className }) => { } /> { - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) ( t('snaps'), sectionMessage: (t) => t('snaps'), diff --git a/ui/helpers/utils/build-types.js b/ui/helpers/utils/build-types.js index 9096e8217..68811e944 100644 --- a/ui/helpers/utils/build-types.js +++ b/ui/helpers/utils/build-types.js @@ -1,10 +1,7 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) import flaskJson from '../../../app/build-types/flask/images/flask-mascot.json'; ///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(desktop) -import desktopJson from '../../../app/build-types/desktop/images/desktop-mascot.json'; -///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(mmi) +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import mmiJson from '../../../app/build-types/mmi/images/mmi-mascot.json'; ///: END:ONLY_INCLUDE_IN @@ -13,22 +10,17 @@ const assetList = { // Will use default provided by the @metamask/logo library foxMeshJson: undefined, }, - ///: BEGIN:ONLY_INCLUDE_IN(beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-beta) beta: { foxMeshJson: undefined, }, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) flask: { foxMeshJson: flaskJson, }, ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(desktop) - desktop: { - foxMeshJson: desktopJson, - }, - ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) mmi: { foxMeshJson: mmiJson, }, diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index 982aca2ed..550ffd3af 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -1,7 +1,7 @@ import deepFreeze from 'deep-freeze-strict'; import React from 'react'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { getRpcCaveatOrigins } from '@metamask/snaps-controllers/dist/snaps/endowments/rpc'; import { SnapCaveatType } from '@metamask/snaps-utils'; import { isNonEmptyArray } from '@metamask/controller-utils'; @@ -9,21 +9,21 @@ import { isNonEmptyArray } from '@metamask/controller-utils'; import classnames from 'classnames'; import { RestrictedMethods, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) EndowmentPermissions, ///: END:ONLY_INCLUDE_IN } from '../../../shared/constants/permissions'; import Tooltip from '../../components/ui/tooltip'; import { AvatarIcon, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) Text, Icon, ///: END:ONLY_INCLUDE_IN IconName, IconSize, } from '../../components/component-library'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { Color, FONT_WEIGHT, @@ -39,7 +39,7 @@ import { const UNKNOWN_PERMISSION = Symbol('unknown'); -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) const RIGHT_INFO_ICON = ( ); @@ -64,7 +64,7 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ rightIcon: null, weight: 2, }), - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) [RestrictedMethods.snap_dialog]: ({ t }) => ({ label: t('permission_dialog'), description: t('permission_dialogDescription'), diff --git a/ui/helpers/utils/util.js b/ui/helpers/utils/util.js index 868ab46fb..5dda8a871 100644 --- a/ui/helpers/utils/util.js +++ b/ui/helpers/utils/util.js @@ -7,7 +7,7 @@ import { getFormattedIpfsUrl } from '@metamask/assets-controllers'; import slip44 from '@metamask/slip44'; import * as lodash from 'lodash'; import bowser from 'bowser'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { getSnapPrefix } from '@metamask/snaps-utils'; ///: END:ONLY_INCLUDE_IN import { CHAIN_IDS } from '../../../shared/constants/network'; @@ -22,7 +22,7 @@ import { } from '../../../shared/constants/labels'; import { Numeric } from '../../../shared/modules/Numeric'; import { OUTDATED_BROWSER_VERSIONS } from '../constants/common'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { SNAPS_DERIVATION_PATHS, SNAPS_METADATA, @@ -539,7 +539,7 @@ export function isNullish(value) { return value === null || value === undefined; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * @param {string[]} path * @param {string} curve diff --git a/ui/hooks/flask/useTransactionInsightSnap.js b/ui/hooks/snaps/useTransactionInsightSnap.js similarity index 100% rename from ui/hooks/flask/useTransactionInsightSnap.js rename to ui/hooks/snaps/useTransactionInsightSnap.js diff --git a/ui/hooks/useTransactionInsights.js b/ui/hooks/useTransactionInsights.js index d20dbfcc7..94557ab0a 100644 --- a/ui/hooks/useTransactionInsights.js +++ b/ui/hooks/useTransactionInsights.js @@ -6,8 +6,8 @@ import { stripHexPrefix } from '../../shared/modules/hexstring-utils'; import { TransactionType } from '../../shared/constants/transaction'; import { getInsightSnaps } from '../selectors'; import { Tab } from '../components/ui/tabs'; -import DropdownTab from '../components/ui/tabs/flask/dropdown-tab'; -import { SnapInsight } from '../components/app/confirm-page-container/flask/snap-insight'; +import DropdownTab from '../components/ui/tabs/snaps/dropdown-tab'; +import { SnapInsight } from '../components/app/confirm-page-container/snaps/snap-insight'; const isAllowedTransactionTypes = (transactionType) => transactionType === TransactionType.contractInteraction || diff --git a/ui/index.js b/ui/index.js index aa4520883..b2a1d936e 100644 --- a/ui/index.js +++ b/ui/index.js @@ -53,7 +53,7 @@ export const updateBackgroundConnection = (backgroundConnection) => { export default function launchMetamaskUi(opts, cb) { const { backgroundConnection } = opts; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) let desktopEnabled = false; backgroundConnection.getDesktopEnabled(function (err, result) { @@ -72,7 +72,7 @@ export default function launchMetamaskUi(opts, cb) { err, { ...metamaskState, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN }, @@ -85,7 +85,7 @@ export default function launchMetamaskUi(opts, cb) { cb( null, store, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) backgroundConnection, ///: END:ONLY_INCLUDE_IN ); diff --git a/ui/pages/confirm-signature-request/index.js b/ui/pages/confirm-signature-request/index.js index d93af8e94..84af604ba 100644 --- a/ui/pages/confirm-signature-request/index.js +++ b/ui/pages/confirm-signature-request/index.js @@ -12,7 +12,7 @@ import Loading from '../../components/ui/loading-screen'; import { useRouting } from '../../hooks/useRouting'; import { getTotalUnapprovedSignatureRequestCount, - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) getSelectedAccount, ///: END:ONLY_INCLUDE_IN } from '../../selectors'; @@ -74,7 +74,7 @@ const ConfirmTxScreen = ({ match }) => { } = useSelector((state) => state.metamask); const { txId: index } = useSelector((state) => state.appState); - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) const selectedAccount = useSelector(getSelectedAccount); ///: END:ONLY_INCLUDE_IN @@ -222,7 +222,7 @@ const ConfirmTxScreen = ({ match }) => { cancelMessage={cancelMessage(SIGN_MESSAGE_TYPE.MESSAGE)} cancelPersonalMessage={cancelMessage(SIGN_MESSAGE_TYPE.PERSONAL)} cancelTypedMessage={cancelMessage(SIGN_MESSAGE_TYPE.TYPED)} - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) selectedAccount={selectedAccount} ///: END:ONLY_INCLUDE_IN /> diff --git a/ui/pages/confirmation/confirmation.js b/ui/pages/confirmation/confirmation.js index 89c932631..83a5b1cba 100644 --- a/ui/pages/confirmation/confirmation.js +++ b/ui/pages/confirmation/confirmation.js @@ -25,7 +25,7 @@ import { import { useI18nContext } from '../../hooks/useI18nContext'; import { useOriginMetadata } from '../../hooks/useOriginMetadata'; import { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getTargetSubjectMetadata, ///: END:ONLY_INCLUDE_IN getUnapprovedTemplatedConfirmations, @@ -35,8 +35,8 @@ import NetworkDisplay from '../../components/app/network-display/network-display import Callout from '../../components/ui/callout'; import SiteOrigin from '../../components/ui/site-origin'; import { Icon, IconName } from '../../components/component-library'; -///: BEGIN:ONLY_INCLUDE_IN(flask) -import SnapAuthorship from '../../components/app/flask/snap-authorship/snap-authorship'; +///: BEGIN:ONLY_INCLUDE_IN(snaps) +import SnapAuthorship from '../../components/app/snaps/snap-authorship'; import { getSnapName } from '../../helpers/utils/util'; ///: END:ONLY_INCLUDE_IN import ConfirmationFooter from './components/confirmation-footer'; @@ -187,7 +187,7 @@ export default function ConfirmationPage({ const [submitAlerts, setSubmitAlerts] = useState([]); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const targetSubjectMetadata = useSelector((state) => getTargetSubjectMetadata(state, pendingConfirmation?.origin), ); @@ -207,7 +207,7 @@ export default function ConfirmationPage({ ///: END:ONLY_INCLUDE_IN const INPUT_STATE_CONFIRMATIONS = [ - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) MESSAGE_TYPE.SNAP_DIALOG_PROMPT, ///: END:ONLY_INCLUDE_IN ]; @@ -219,7 +219,7 @@ export default function ConfirmationPage({ return pendingConfirmation ? getTemplateValues( { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapName: isSnapDialog && snapName, ///: END:ONLY_INCLUDE_IN ...pendingConfirmation, @@ -235,7 +235,7 @@ export default function ConfirmationPage({ t, dispatch, history, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) isSnapDialog, snapName, ///: END:ONLY_INCLUDE_IN @@ -335,7 +335,7 @@ export default function ConfirmationPage({ ) : null} { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) !isSnapDialog && ///: END:ONLY_INCLUDE_IN pendingConfirmation.origin === 'metamask' && ( @@ -358,7 +358,7 @@ export default function ConfirmationPage({ ) } { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) isSnapDialog && ( { diff --git a/ui/pages/desktop-error/render-desktop-error.js b/ui/pages/desktop-error/render-desktop-error.js index 810a118e9..e863381c0 100644 --- a/ui/pages/desktop-error/render-desktop-error.js +++ b/ui/pages/desktop-error/render-desktop-error.js @@ -197,7 +197,7 @@ export function renderDesktopError({ ); break; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) // This route only exists on the Desktop App case EXTENSION_ERROR_PAGE_TYPES.ROUTE_NOT_FOUND: content = ( diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index 6fabafdf9..a8faadc76 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { Redirect, Route } from 'react-router-dom'; -///: BEGIN:ONLY_INCLUDE_IN(main) +///: BEGIN:ONLY_INCLUDE_IN(build-main) // eslint-disable-next-line import/no-duplicates import { MetaMetricsContextProp } from '../../../shared/constants/metametrics'; ///: END:ONLY_INCLUDE_IN @@ -57,13 +57,13 @@ import { ONBOARDING_SECURE_YOUR_WALLET_ROUTE, } from '../../helpers/constants/routes'; import ZENDESK_URLS from '../../helpers/constants/zendesk-url'; -///: BEGIN:ONLY_INCLUDE_IN(main) +///: BEGIN:ONLY_INCLUDE_IN(build-main) import { SUPPORT_LINK } from '../../../shared/lib/ui-utils'; ///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(beta) +///: BEGIN:ONLY_INCLUDE_IN(build-beta) import BetaHomeFooter from './beta/beta-home-footer.component'; ///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) import FlaskHomeFooter from './flask/flask-home-footer.component'; ///: END:ONLY_INCLUDE_IN @@ -116,7 +116,7 @@ export default class Home extends PureComponent { hideWhatsNewPopup: PropTypes.func.isRequired, showTermsOfUsePopup: PropTypes.bool.isRequired, announcementsToShow: PropTypes.bool.isRequired, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) errorsToShow: PropTypes.object.isRequired, shouldShowErrors: PropTypes.bool.isRequired, removeSnapError: PropTypes.func.isRequired, @@ -276,7 +276,7 @@ export default class Home extends PureComponent { setWeb3ShimUsageAlertDismissed, originOfCurrentTab, disableWeb3ShimUsageAlert, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) removeSnapError, errorsToShow, shouldShowErrors, @@ -305,7 +305,7 @@ export default class Home extends PureComponent { return ( { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) shouldShowErrors ? Object.entries(errorsToShow).map(([errorId, error]) => { return ( @@ -715,7 +715,7 @@ export default class Home extends PureComponent {
{ - ///: BEGIN:ONLY_INCLUDE_IN(main) + ///: BEGIN:ONLY_INCLUDE_IN(build-main) t('needHelp', [ ///: END:ONLY_INCLUDE_IN } { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) ///: END:ONLY_INCLUDE_IN } diff --git a/ui/pages/home/home.container.js b/ui/pages/home/home.container.js index 9ffaf1094..48e7bc026 100644 --- a/ui/pages/home/home.container.js +++ b/ui/pages/home/home.container.js @@ -5,7 +5,7 @@ import { ApprovalType } from '@metamask/controller-utils'; import { activeTabHasPermissions, getFirstPermissionRequest, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getFirstSnapInstallOrUpdateRequest, ///: END:ONLY_INCLUDE_IN getIsMainnet, @@ -45,7 +45,7 @@ import { setRemoveNftMessage, setNewTokensImported, setActiveNetwork, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) removeSnapError, ///: END:ONLY_INCLUDE_IN } from '../../store/actions'; @@ -90,7 +90,7 @@ const mapStateToProps = (state) => { // getFirstPermissionRequest should be updated with snap update logic once we hit main extension release - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) if (!firstPermissionsRequest) { firstPermissionsRequest = getFirstSnapInstallOrUpdateRequest(state); firstPermissionsRequestId = firstPermissionsRequest?.metadata.id || null; @@ -138,7 +138,7 @@ const mapStateToProps = (state) => { pendingConfirmations, infuraBlocked: getInfuraBlocked(state), announcementsToShow: getSortedAnnouncementsToShow(state).length > 0, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) errorsToShow: metamask.snapErrors, shouldShowErrors: Object.entries(metamask.snapErrors || []).length > 0, ///: END:ONLY_INCLUDE_IN @@ -160,7 +160,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = (dispatch) => ({ closeNotificationPopup: () => closeNotificationPopup(), - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) removeSnapError: async (id) => await removeSnapError(id), ///: END:ONLY_INCLUDE_IN setConnectedStatusPopoverHasBeenShown: () => diff --git a/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js b/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js index 33f684c6e..b5df47e8e 100644 --- a/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js +++ b/ui/pages/onboarding-flow/onboarding-flow-switch/onboarding-flow-switch.js @@ -6,10 +6,10 @@ import { ONBOARDING_COMPLETION_ROUTE, ONBOARDING_UNLOCK_ROUTE, LOCK_ROUTE, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) ONBOARDING_EXPERIMENTAL_AREA, // eslint-disable-line no-unused-vars ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-mmi) ONBOARDING_WELCOME_ROUTE, // eslint-disable-line no-unused-vars ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/routes'; @@ -39,16 +39,15 @@ export default function OnboardingFlowSwitch() { return ; } + // TODO(ritave): Remove allow-list and only leave experimental_area exception if (!isInitialized) { let redirect; - /* eslint-disable prefer-const */ - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) redirect = ; ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-mmi) redirect = ; ///: END:ONLY_INCLUDE_IN - /* eslint-enable prefer-const */ return redirect; } diff --git a/ui/pages/onboarding-flow/onboarding-flow.js b/ui/pages/onboarding-flow/onboarding-flow.js index 4ce73f933..12fe34b96 100644 --- a/ui/pages/onboarding-flow/onboarding-flow.js +++ b/ui/pages/onboarding-flow/onboarding-flow.js @@ -3,7 +3,7 @@ import { Switch, Route, useHistory, useLocation } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import Unlock from '../unlock-page'; import { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) ONBOARDING_EXPERIMENTAL_AREA, ///: END:ONLY_INCLUDE_IN ONBOARDING_CREATE_PASSWORD_ROUTE, @@ -34,7 +34,7 @@ import { MetaMetricsEventCategory, MetaMetricsEventName, } from '../../../shared/constants/metametrics'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(build-flask) import ExperimentalArea from '../../components/app/flask/experimental-area'; ///: END:ONLY_INCLUDE_IN import OnboardingFlowSwitch from './onboarding-flow-switch/onboarding-flow-switch'; @@ -170,7 +170,7 @@ export default function OnboardingFlow() { component={MetaMetricsComponent} /> { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-flask) } { const { confirmPermissionPath, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapInstallPath, snapUpdatePath, snapResultPath, @@ -186,10 +186,10 @@ export default class PermissionConnect extends Component { { selectedAccountAddresses: addresses, }, - ///: BEGIN:ONLY_INCLUDE_IN(main,beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta) () => this.props.history.push(confirmPermissionPath), ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) () => { switch (requestType) { case 'wallet_installSnap': @@ -212,12 +212,12 @@ export default class PermissionConnect extends Component { redirect(approved) { const { history, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) permissionsRequest, ///: END:ONLY_INCLUDE_IN } = this.props; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const isRequestingSnap = permissionsRequest?.permissions && Object.keys(permissionsRequest.permissions).includes('wallet_snap'); @@ -230,7 +230,7 @@ export default class PermissionConnect extends Component { }); ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(main,beta) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta) this.setState({ redirecting: true, permissionsApproved: approved, @@ -238,19 +238,19 @@ export default class PermissionConnect extends Component { ///: END:ONLY_INCLUDE_IN this.removeBeforeUnload(); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) if (shouldRedirect && approved) { setTimeout(() => history.push(DEFAULT_ROUTE), APPROVE_TIMEOUT); + return; } ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-mmi) if (approved) { setTimeout(() => history.push(DEFAULT_ROUTE), APPROVE_TIMEOUT); + return; } ///: END:ONLY_INCLUDE_IN - else { - history.push(DEFAULT_ROUTE); - } + history.push(DEFAULT_ROUTE); } cancelPermissionsRequest = async (requestId) => { @@ -307,7 +307,7 @@ export default class PermissionConnect extends Component { permissionsRequestId, connectPath, confirmPermissionPath, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) snapInstallPath, snapUpdatePath, snapResultPath, @@ -376,7 +376,7 @@ export default class PermissionConnect extends Component { )} /> { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) } { location: { pathname }, } = ownProps; let permissionsRequests = getPermissionsRequests(state); - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) permissionsRequests = [ ...permissionsRequests, ...getSnapInstallOrUpdateRequests(state), @@ -73,7 +73,7 @@ const mapStateToProps = (state, ownProps) => { subjectType: SubjectType.Unknown, }; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const isSnap = targetSubjectMetadata.subjectType === SubjectType.Snap; const requestType = getRequestType(state, permissionsRequestId); @@ -95,14 +95,14 @@ const mapStateToProps = (state, ownProps) => { const connectPath = `${CONNECT_ROUTE}/${permissionsRequestId}`; const confirmPermissionPath = `${CONNECT_ROUTE}/${permissionsRequestId}${CONNECT_CONFIRM_PERMISSIONS_ROUTE}`; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) const snapInstallPath = `${CONNECT_ROUTE}/${permissionsRequestId}${CONNECT_SNAP_INSTALL_ROUTE}`; const snapUpdatePath = `${CONNECT_ROUTE}/${permissionsRequestId}${CONNECT_SNAP_UPDATE_ROUTE}`; const snapResultPath = `${CONNECT_ROUTE}/${permissionsRequestId}${CONNECT_SNAP_RESULT_ROUTE}`; ///: END:ONLY_INCLUDE_IN let totalPages = 1 + isRequestingAccounts; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) totalPages += isSnap; ///: END:ONLY_INCLUDE_IN totalPages = totalPages.toString(); @@ -112,7 +112,7 @@ const mapStateToProps = (state, ownProps) => { page = '1'; } else if (pathname === confirmPermissionPath) { page = isRequestingAccounts ? '2' : '1'; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) } else if ( pathname === snapInstallPath || pathname === snapUpdatePath || @@ -126,7 +126,7 @@ const mapStateToProps = (state, ownProps) => { return { isRequestingAccounts, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) requestType, snapInstallPath, snapUpdatePath, @@ -157,7 +157,7 @@ const mapDispatchToProps = (dispatch) => { dispatch(approvePermissionsRequest(request)), rejectPermissionsRequest: (requestId) => dispatch(rejectPermissionsRequest(requestId)), - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) approvePendingApproval: (id, value) => dispatch(resolvePendingApproval(id, value)), rejectPendingApproval: (id, error) => diff --git a/ui/pages/permissions-connect/flask/snap-install/index.js b/ui/pages/permissions-connect/snaps/snap-install/index.js similarity index 100% rename from ui/pages/permissions-connect/flask/snap-install/index.js rename to ui/pages/permissions-connect/snaps/snap-install/index.js diff --git a/ui/pages/permissions-connect/flask/snap-install/index.scss b/ui/pages/permissions-connect/snaps/snap-install/index.scss similarity index 100% rename from ui/pages/permissions-connect/flask/snap-install/index.scss rename to ui/pages/permissions-connect/snaps/snap-install/index.scss diff --git a/ui/pages/permissions-connect/flask/snap-install/snap-install.js b/ui/pages/permissions-connect/snaps/snap-install/snap-install.js similarity index 95% rename from ui/pages/permissions-connect/flask/snap-install/snap-install.js rename to ui/pages/permissions-connect/snaps/snap-install/snap-install.js index d4b712623..8fc4fe2b4 100644 --- a/ui/pages/permissions-connect/flask/snap-install/snap-install.js +++ b/ui/pages/permissions-connect/snaps/snap-install/snap-install.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { useCallback, useState } from 'react'; import { PageContainerFooter } from '../../../../components/ui/page-container'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import SnapInstallWarning from '../../../../components/app/flask/snap-install-warning'; +import SnapInstallWarning from '../../../../components/app/snaps/snap-install-warning'; import Box from '../../../../components/ui/box/box'; import { AlignItems, @@ -15,12 +15,12 @@ import { } from '../../../../helpers/constants/design-system'; import { getSnapInstallWarnings } from '../util'; import PulseLoader from '../../../../components/ui/pulse-loader/pulse-loader'; -import InstallError from '../../../../components/app/flask/install-error/install-error'; -import SnapAuthorship from '../../../../components/app/flask/snap-authorship'; +import InstallError from '../../../../components/app/snaps/install-error/install-error'; +import SnapAuthorship from '../../../../components/app/snaps/snap-authorship'; import { Text } from '../../../../components/component-library'; import { useOriginMetadata } from '../../../../hooks/useOriginMetadata'; import { getSnapName } from '../../../../helpers/utils/util'; -import SnapPermissionsList from '../../../../components/app/flask/snap-permissions-list'; +import SnapPermissionsList from '../../../../components/app/snaps/snap-permissions-list'; export default function SnapInstall({ request, diff --git a/ui/pages/permissions-connect/flask/snap-result/index.js b/ui/pages/permissions-connect/snaps/snap-result/index.js similarity index 100% rename from ui/pages/permissions-connect/flask/snap-result/index.js rename to ui/pages/permissions-connect/snaps/snap-result/index.js diff --git a/ui/pages/permissions-connect/flask/snap-result/index.scss b/ui/pages/permissions-connect/snaps/snap-result/index.scss similarity index 100% rename from ui/pages/permissions-connect/flask/snap-result/index.scss rename to ui/pages/permissions-connect/snaps/snap-result/index.scss diff --git a/ui/pages/permissions-connect/flask/snap-result/snap-result.js b/ui/pages/permissions-connect/snaps/snap-result/snap-result.js similarity index 96% rename from ui/pages/permissions-connect/flask/snap-result/snap-result.js rename to ui/pages/permissions-connect/snaps/snap-result/snap-result.js index d821e63c3..a1f187d20 100644 --- a/ui/pages/permissions-connect/flask/snap-result/snap-result.js +++ b/ui/pages/permissions-connect/snaps/snap-result/snap-result.js @@ -16,8 +16,8 @@ import { } from '../../../../helpers/constants/design-system'; import { Text } from '../../../../components/component-library'; import PulseLoader from '../../../../components/ui/pulse-loader/pulse-loader'; -import InstallError from '../../../../components/app/flask/install-error/install-error'; -import SnapAuthorship from '../../../../components/app/flask/snap-authorship'; +import InstallError from '../../../../components/app/snaps/install-error/install-error'; +import SnapAuthorship from '../../../../components/app/snaps/snap-authorship'; import { getSnapName } from '../../../../helpers/utils/util'; export default function SnapResult({ diff --git a/ui/pages/permissions-connect/flask/snap-update/index.js b/ui/pages/permissions-connect/snaps/snap-update/index.js similarity index 100% rename from ui/pages/permissions-connect/flask/snap-update/index.js rename to ui/pages/permissions-connect/snaps/snap-update/index.js diff --git a/ui/pages/permissions-connect/flask/snap-update/index.scss b/ui/pages/permissions-connect/snaps/snap-update/index.scss similarity index 100% rename from ui/pages/permissions-connect/flask/snap-update/index.scss rename to ui/pages/permissions-connect/snaps/snap-update/index.scss diff --git a/ui/pages/permissions-connect/flask/snap-update/snap-update.js b/ui/pages/permissions-connect/snaps/snap-update/snap-update.js similarity index 96% rename from ui/pages/permissions-connect/flask/snap-update/snap-update.js rename to ui/pages/permissions-connect/snaps/snap-update/snap-update.js index f31aabf09..cec71ce96 100644 --- a/ui/pages/permissions-connect/flask/snap-update/snap-update.js +++ b/ui/pages/permissions-connect/snaps/snap-update/snap-update.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; import React, { useCallback, useState } from 'react'; import { PageContainerFooter } from '../../../../components/ui/page-container'; import { useI18nContext } from '../../../../hooks/useI18nContext'; -import SnapInstallWarning from '../../../../components/app/flask/snap-install-warning'; +import SnapInstallWarning from '../../../../components/app/snaps/snap-install-warning'; import Box from '../../../../components/ui/box/box'; import { AlignItems, @@ -14,11 +14,11 @@ import { TEXT_ALIGN, } from '../../../../helpers/constants/design-system'; -import UpdateSnapPermissionList from '../../../../components/app/flask/update-snap-permission-list'; +import UpdateSnapPermissionList from '../../../../components/app/snaps/update-snap-permission-list'; import { getSnapInstallWarnings } from '../util'; import PulseLoader from '../../../../components/ui/pulse-loader/pulse-loader'; -import InstallError from '../../../../components/app/flask/install-error/install-error'; -import SnapAuthorship from '../../../../components/app/flask/snap-authorship'; +import InstallError from '../../../../components/app/snaps/install-error/install-error'; +import SnapAuthorship from '../../../../components/app/snaps/snap-authorship'; import { Text } from '../../../../components/component-library'; import { useOriginMetadata } from '../../../../hooks/useOriginMetadata'; import { getSnapName } from '../../../../helpers/utils/util'; diff --git a/ui/pages/permissions-connect/flask/util.js b/ui/pages/permissions-connect/snaps/util.js similarity index 100% rename from ui/pages/permissions-connect/flask/util.js rename to ui/pages/permissions-connect/snaps/util.js diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js index a6d50b7e1..f4482f9bc 100644 --- a/ui/pages/routes/routes.component.js +++ b/ui/pages/routes/routes.component.js @@ -4,7 +4,7 @@ import React, { Component } from 'react'; import { matchPath, Route, Switch } from 'react-router-dom'; import IdleTimer from 'react-idle-timer'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import browserAPI from 'webextension-polyfill'; ///: END:ONLY_INCLUDE_IN import SendTransactionScreen from '../send'; @@ -40,8 +40,10 @@ import Alerts from '../../components/app/alerts'; import Asset from '../asset'; import OnboardingAppHeader from '../onboarding-flow/onboarding-app-header/onboarding-app-header'; import TokenDetailsPage from '../token-details'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import Notifications from '../notifications'; +///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(desktop) import { registerOnDesktopDisconnect } from '../../hooks/desktopHooks'; import DesktopErrorPage from '../desktop-error'; import DesktopPairingPage from '../desktop-pairing'; @@ -69,14 +71,16 @@ import { ADD_NFT_ROUTE, ONBOARDING_UNLOCK_ROUTE, TOKEN_DETAILS, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) NOTIFICATIONS_ROUTE, + ///: END:ONLY_INCLUDE_IN + ///: BEGIN:ONLY_INCLUDE_IN(desktop) DESKTOP_PAIRING_ROUTE, DESKTOP_ERROR_ROUTE, ///: END:ONLY_INCLUDE_IN } from '../../helpers/constants/routes'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import { EXTENSION_ERROR_PAGE_TYPES } from '../../../shared/constants/desktop'; ///: END:ONLY_INCLUDE_IN @@ -147,7 +151,7 @@ export default class Routes extends Component { document.documentElement.setAttribute('data-theme', osTheme); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) componentDidMount() { const { history } = this.props; browserAPI.runtime.onMessage.addListener( @@ -209,7 +213,7 @@ export default class Routes extends Component { { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) ///: END:ONLY_INCLUDE_IN } @@ -277,7 +281,7 @@ export default class Routes extends Component { { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) { useNonceField, ledgerTransportType, dismissSeedBackUpReminder, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN } = metamask; @@ -53,7 +53,7 @@ export const mapStateToProps = (state) => { dismissSeedBackUpReminder, userHasALedgerAccount, disabledRpcMethodPreferences, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) desktopEnabled, ///: END:ONLY_INCLUDE_IN }; diff --git a/ui/pages/settings/experimental-tab/experimental-tab.component.js b/ui/pages/settings/experimental-tab/experimental-tab.component.js index 52061def7..ad4d0e627 100644 --- a/ui/pages/settings/experimental-tab/experimental-tab.component.js +++ b/ui/pages/settings/experimental-tab/experimental-tab.component.js @@ -13,7 +13,7 @@ import { TextColor, TypographyVariant, } from '../../../helpers/constants/design-system'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) import DesktopEnableButton from '../../../components/app/desktop-enable-button'; ///: END:ONLY_INCLUDE_IN @@ -235,7 +235,7 @@ export default class ExperimentalTab extends PureComponent { ); } - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) renderDesktopEnableButton() { const { t } = this.context; @@ -264,7 +264,7 @@ export default class ExperimentalTab extends PureComponent { {this.renderTransactionSecurityCheckToggle()} {this.renderOpenSeaEnabledToggle()} { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(desktop) this.renderDesktopEnableButton() ///: END:ONLY_INCLUDE_IN } diff --git a/ui/pages/settings/index.scss b/ui/pages/settings/index.scss index 10d9b4d97..797a0fb2e 100644 --- a/ui/pages/settings/index.scss +++ b/ui/pages/settings/index.scss @@ -3,8 +3,8 @@ @import 'networks-tab/index'; @import 'settings-tab/index'; @import 'contact-list-tab/index'; -@import 'flask/snaps-list-tab/index'; -@import 'flask/view-snap/index'; +@import 'snaps/snaps-list-tab/index'; +@import 'snaps/view-snap/index'; .settings-page { position: relative; diff --git a/ui/pages/settings/info-tab/info-tab.component.js b/ui/pages/settings/info-tab/info-tab.component.js index 33c006d1e..2d57fb2eb 100644 --- a/ui/pages/settings/info-tab/info-tab.component.js +++ b/ui/pages/settings/info-tab/info-tab.component.js @@ -6,7 +6,7 @@ import { Tag } from '../../../components/component-library'; import { SUPPORT_REQUEST_LINK, - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) MMI_WEB_SITE, ///: END:ONLY_INCLUDE_IN } from '../../../helpers/constants/common'; @@ -54,12 +54,12 @@ export default class InfoTab extends PureComponent { const { t } = this.context; let privacyUrl, siteUrl; - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) privacyUrl = 'https://consensys.net/codefi/about/privacy-policy/'; siteUrl = MMI_WEB_SITE; ///: END:ONLY_INCLUDE_IN - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) privacyUrl = 'https://metamask.io/privacy.html'; siteUrl = 'https://metamask.io/'; ///: END:ONLY_INCLUDE_IN @@ -194,7 +194,7 @@ export default class InfoTab extends PureComponent {
{ - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
{ - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) t('builtAroundTheWorld') ///: END:ONLY_INCLUDE_IN } { - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) t('mmiBuiltAroundTheWorld') ///: END:ONLY_INCLUDE_IN } @@ -233,7 +233,7 @@ export default class InfoTab extends PureComponent { {this.renderInfoLinks()}
{ - ///: BEGIN:ONLY_INCLUDE_IN(main,beta,flask) + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
, key: CONTACT_LIST_ROUTE, }, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) { content: t('snaps'), icon: ( @@ -368,12 +368,12 @@ class SettingsPage extends PureComponent { component={ContactListTab} /> { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) ///: END:ONLY_INCLUDE_IN } { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) ///: END:ONLY_INCLUDE_IN } diff --git a/ui/pages/settings/flask/snaps-list-tab/index.js b/ui/pages/settings/snaps/snaps-list-tab/index.js similarity index 100% rename from ui/pages/settings/flask/snaps-list-tab/index.js rename to ui/pages/settings/snaps/snaps-list-tab/index.js diff --git a/ui/pages/settings/flask/snaps-list-tab/index.scss b/ui/pages/settings/snaps/snaps-list-tab/index.scss similarity index 100% rename from ui/pages/settings/flask/snaps-list-tab/index.scss rename to ui/pages/settings/snaps/snaps-list-tab/index.scss diff --git a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js b/ui/pages/settings/snaps/snaps-list-tab/snap-list-tab.js similarity index 98% rename from ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js rename to ui/pages/settings/snaps/snaps-list-tab/snap-list-tab.js index 6fcfbab2f..86c722425 100644 --- a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.js +++ b/ui/pages/settings/snaps/snaps-list-tab/snap-list-tab.js @@ -1,7 +1,7 @@ import React, { useRef, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { useHistory } from 'react-router-dom'; -import SnapSettingsCard from '../../../../components/app/flask/snap-settings-card'; +import SnapSettingsCard from '../../../../components/app/snaps/snap-settings-card'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { JustifyContent, diff --git a/ui/pages/settings/flask/snaps-list-tab/snap-list-tab.stories.js b/ui/pages/settings/snaps/snaps-list-tab/snap-list-tab.stories.js similarity index 100% rename from ui/pages/settings/flask/snaps-list-tab/snap-list-tab.stories.js rename to ui/pages/settings/snaps/snaps-list-tab/snap-list-tab.stories.js diff --git a/ui/pages/settings/flask/view-snap/index.js b/ui/pages/settings/snaps/view-snap/index.js similarity index 100% rename from ui/pages/settings/flask/view-snap/index.js rename to ui/pages/settings/snaps/view-snap/index.js diff --git a/ui/pages/settings/flask/view-snap/index.scss b/ui/pages/settings/snaps/view-snap/index.scss similarity index 100% rename from ui/pages/settings/flask/view-snap/index.scss rename to ui/pages/settings/snaps/view-snap/index.scss diff --git a/ui/pages/settings/flask/view-snap/view-snap.js b/ui/pages/settings/snaps/view-snap/view-snap.js similarity index 97% rename from ui/pages/settings/flask/view-snap/view-snap.js rename to ui/pages/settings/snaps/view-snap/view-snap.js index a002ad7b5..3d4bbf8a5 100644 --- a/ui/pages/settings/flask/view-snap/view-snap.js +++ b/ui/pages/settings/snaps/view-snap/view-snap.js @@ -13,9 +13,9 @@ import { TextColor, TextVariant, } from '../../../../helpers/constants/design-system'; -import SnapAuthorship from '../../../../components/app/flask/snap-authorship'; +import SnapAuthorship from '../../../../components/app/snaps/snap-authorship'; import Box from '../../../../components/ui/box'; -import SnapRemoveWarning from '../../../../components/app/flask/snap-remove-warning'; +import SnapRemoveWarning from '../../../../components/app/snaps/snap-remove-warning'; import ToggleButton from '../../../../components/ui/toggle-button'; import ConnectedSitesList from '../../../../components/app/connected-sites-list'; import Tooltip from '../../../../components/ui/tooltip'; @@ -40,7 +40,7 @@ import { removeSnapIdPrefix, } from '../../../../helpers/utils/util'; import { ButtonLink, Text } from '../../../../components/component-library'; -import SnapPermissionsList from '../../../../components/app/flask/snap-permissions-list'; +import SnapPermissionsList from '../../../../components/app/snaps/snap-permissions-list'; function ViewSnap() { const t = useI18nContext(); diff --git a/ui/pages/settings/flask/view-snap/view-snap.test.js b/ui/pages/settings/snaps/view-snap/view-snap.test.js similarity index 100% rename from ui/pages/settings/flask/view-snap/view-snap.test.js rename to ui/pages/settings/snaps/view-snap/view-snap.test.js diff --git a/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js b/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js index 90bd149d1..7a91b40a9 100644 --- a/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js +++ b/ui/pages/swaps/awaiting-swap/awaiting-swap.test.js @@ -97,7 +97,7 @@ describe('AwaitingSwap', () => { store, ); expect(getByText('Swap failed')).toBeInTheDocument(); - fireEvent.click(getByText('metamask-flask.zendesk.com')); + fireEvent.click(getByText('support.metamask.io')); expect(getByText('Try again')).toBeInTheDocument(); }); diff --git a/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap b/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap index a8ed6e41e..324c6d990 100644 --- a/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap +++ b/ui/pages/unlock-page/__snapshots__/unlock-page.test.js.snap @@ -85,7 +85,7 @@ exports[`Unlock Page should match snapshot 1`] = ` Need help? Contact diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index d4b3d90de..dfc2a83e7 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/rpc-methods'; ///: END:ONLY_INCLUDE_IN import { CaveatTypes } from '../../shared/constants/permissions'; @@ -139,7 +139,7 @@ export function getSubjectsWithPermission(state, permissionName) { return connectedSubjects; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) export function getSubjectsWithSnapPermission(state, snapId) { const subjects = getPermissionSubjects(state); @@ -323,7 +323,7 @@ export function getLastConnectedInfo(state) { }, {}); } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) export function getSnapInstallOrUpdateRequests(state) { return Object.values(state.metamask.pendingApprovals) .filter( diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index e5266293a..13a198bac 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -1,4 +1,4 @@ -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { SubjectType } from '@metamask/subject-metadata-controller'; ///: END:ONLY_INCLUDE_IN import { @@ -7,7 +7,7 @@ import { defaultMemoize, } from 'reselect'; import { - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) memoize, ///: END:ONLY_INCLUDE_IN isEqual, @@ -55,7 +55,7 @@ import { shortenAddress, getAccountByAddress, getURLHostName, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) removeSnapIdPrefix, getSnapName, ///: END:ONLY_INCLUDE_IN @@ -84,7 +84,7 @@ import { getValueFromWeiHex, hexToDecimal, } from '../../shared/modules/conversion.utils'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { SNAPS_VIEW_ROUTE } from '../helpers/constants/routes'; import { getPermissionSubjects } from './permissions'; ///: END:ONLY_INCLUDE_IN @@ -235,7 +235,7 @@ export function getAccountType(state) { const currentKeyring = getCurrentKeyring(state); const type = currentKeyring && currentKeyring.type; - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) if (type.startsWith('Custody')) { return 'custody'; } @@ -622,7 +622,7 @@ export function getSubjectMetadata(state) { return state.metamask.subjectMetadata; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * @param {string} svgString - The raw SVG string to make embeddable. * @returns {string} The embeddable SVG string. @@ -635,7 +635,7 @@ const getEmbeddableSvg = memoize( export function getTargetSubjectMetadata(state, origin) { const metadata = getSubjectMetadata(state)[origin]; - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) if (metadata?.subjectType === SubjectType.Snap) { const { svgIcon, ...remainingMetadata } = metadata; return { @@ -858,7 +858,7 @@ export const getFullTxData = createDeepEqualSelector( }, ); -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) export function getSnaps(state) { return state.metamask.snaps; } @@ -1452,7 +1452,7 @@ export function getUseCurrencyRateCheck(state) { return Boolean(state.metamask.useCurrencyRateCheck); } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) /** * To get the `desktopEnabled` value which determines whether we use the desktop app * @@ -1464,7 +1464,7 @@ export function getIsDesktopEnabled(state) { } ///: END:ONLY_INCLUDE_IN -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * To get all installed snaps with proper metadata * diff --git a/ui/store/actionConstants.ts b/ui/store/actionConstants.ts index 34e1e9dfc..8dbe40906 100644 --- a/ui/store/actionConstants.ts +++ b/ui/store/actionConstants.ts @@ -105,6 +105,6 @@ export const SET_NEW_TOKENS_IMPORTED = 'SET_NEW_TOKENS_IMPORTED'; // Token allowance export const SET_CUSTOM_TOKEN_AMOUNT = 'SET_CUSTOM_TOKEN_AMOUNT'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(desktop) export const FORCE_DISABLE_DESKTOP = 'FORCE_DISABLE_DESKTOP'; ///: END:ONLY_INCLUDE_IN diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 7db869921..c2e8156fa 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -29,7 +29,7 @@ import { getMetaMaskAccounts, getPermittedAccountsForCurrentTab, getSelectedAddress, - ///: BEGIN:ONLY_INCLUDE_IN(flask) + ///: BEGIN:ONLY_INCLUDE_IN(snaps) getNotifications, ///: END:ONLY_INCLUDE_IN } from '../selectors'; @@ -62,7 +62,7 @@ import { } from '../../shared/constants/metametrics'; import { parseSmartTransactionsError } from '../pages/swaps/swaps.util'; import { isEqualCaseInsensitive } from '../../shared/modules/string-utils'; -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) import { NOTIFICATIONS_EXPIRATION_DELAY } from '../helpers/constants/notifications'; ///: END:ONLY_INCLUDE_IN import { @@ -86,7 +86,7 @@ import { TxParams } from '../../app/scripts/controllers/transactions/tx-state-ma import { CustomGasSettings } from '../../app/scripts/controllers/transactions'; import { ThemeType } from '../../shared/constants/preferences'; import * as actionConstants from './actionConstants'; -///: BEGIN:ONLY_INCLUDE_IN(mmi) +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) import { checkForUnapprovedTypedMessages, updateCustodyState, @@ -696,7 +696,7 @@ export function signPersonalMsg( } dispatch(updateMetamaskState(newState)); - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) if (newState.unapprovedTypedMessages) { return checkForUnapprovedTypedMessages(msgData, newState); } @@ -828,7 +828,7 @@ export function signTypedMsg( } dispatch(updateMetamaskState(newState)); - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) if (newState.unapprovedTypedMessages) { return checkForUnapprovedTypedMessages(msgData, newState); } @@ -1249,7 +1249,7 @@ export function updateTransactionParams(txId: number, txParams: TxParams) { }; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) export function disableSnap( snapId: string, ): ThunkAction { @@ -1343,6 +1343,9 @@ export function markNotificationsAsRead( }; } +///: END:ONLY_INCLUDE_IN +///: BEGIN:ONLY_INCLUDE_IN(desktop) + export function setDesktopEnabled(desktopEnabled: boolean) { return async () => { try { @@ -1842,7 +1845,7 @@ export function updateMetamaskState( dispatch(initializeSendState({ chainHasChanged: true })); } - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) updateCustodyState(dispatch, newState, getState()); ///: END:ONLY_INCLUDE_IN }; @@ -3723,7 +3726,7 @@ export function removePermissionsFor( }; } -///: BEGIN:ONLY_INCLUDE_IN(flask) +///: BEGIN:ONLY_INCLUDE_IN(snaps) /** * Updates the caveat value for the specified origin, permission and caveat type. * diff --git a/ui/store/store.ts b/ui/store/store.ts index a4e9aa9d6..ad3f3e714 100644 --- a/ui/store/store.ts +++ b/ui/store/store.ts @@ -23,7 +23,7 @@ export interface TemporaryMessageDataType { metamaskId: number; data: string; }; - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) custodyId?: string; status?: string; ///: END:ONLY_INCLUDE_IN @@ -74,7 +74,7 @@ interface TemporaryBackgroundState { }; gasFeeEstimates: GasFeeEstimates; gasEstimateType: GasEstimateType; - ///: BEGIN:ONLY_INCLUDE_IN(mmi) + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) custodyAccountDetails?: { [key: string]: any }; ///: END:ONLY_INCLUDE_IN } diff --git a/yarn.lock b/yarn.lock index ee7c95592..17f17f5da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24342,6 +24342,7 @@ __metadata: string.prototype.matchall: ^4.0.2 style-loader: ^0.21.0 stylelint: ^13.6.1 + superstruct: ^1.0.3 terser: ^5.7.0 through2: ^4.0.2 ts-node: ^10.5.0 From 2c1ed4e8f0337b7c5a3123b19b0ef7d5047446cd Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Tue, 25 Apr 2023 14:37:30 +0000 Subject: [PATCH 31/60] deps: replace gulp-dart-sass with gulp-sass. (#16302) Co-authored-by: Brad Decker --- development/build/styles.js | 4 +- .../scripts/build-app.ts | 5 +- lavamoat/build-system/policy.json | 142 ++++++------------ package.json | 5 +- yarn.lock | 70 +++++---- 5 files changed, 99 insertions(+), 127 deletions(-) diff --git a/development/build/styles.js b/development/build/styles.js index 8b5ccf29e..d6be078ab 100644 --- a/development/build/styles.js +++ b/development/build/styles.js @@ -66,12 +66,10 @@ function createStyleTasks({ livereload }) { async function buildScssPipeline(src, dest, devMode, rtl) { if (!sass) { - // eslint-disable-next-line node/global-require - sass = require('gulp-dart-sass'); // use our own compiler which runs sass in its own process // in order to not pollute the intrinsics // eslint-disable-next-line node/global-require - sass.compiler = require('./sass-compiler'); + sass = require('gulp-sass')(require('./sass-compiler')); } await pump( ...[ diff --git a/development/ts-migration-dashboard/scripts/build-app.ts b/development/ts-migration-dashboard/scripts/build-app.ts index 95a74221c..1e1d6fcd3 100644 --- a/development/ts-migration-dashboard/scripts/build-app.ts +++ b/development/ts-migration-dashboard/scripts/build-app.ts @@ -8,7 +8,8 @@ import pify from 'pify'; import endOfStream from 'end-of-stream'; import pump from 'pump'; import gulp from 'gulp'; -import gulpDartSass from 'gulp-dart-sass'; +import gulpSass from 'gulp-sass'; +import sass from 'sass'; import sourcemaps from 'gulp-sourcemaps'; import autoprefixer from 'gulp-autoprefixer'; import fg from 'fast-glob'; @@ -94,7 +95,7 @@ async function compileStylesheets(src: string, dest: string): Promise { await promisifiedPump( gulp.src(src), sourcemaps.init(), - gulpDartSass().on('error', (error: unknown) => { + gulpSass(sass)().on('error', (error: unknown) => { console.error(`Couldn't compile stylesheets: ${error}`); }), autoprefixer(), diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index efbd0f05a..f4b6dfdbd 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -1272,16 +1272,6 @@ "typescript": true } }, - "addons-linter>postcss>picocolors": { - "builtin": { - "tty.isatty": true - }, - "globals": { - "process.argv.includes": true, - "process.env": true, - "process.platform": true - } - }, "babelify": { "builtin": { "path.extname": true, @@ -3269,9 +3259,9 @@ "process.env.AUTOPREFIXER_GRID": true }, "packages": { - "addons-linter>postcss>picocolors": true, "gulp-autoprefixer>autoprefixer>fraction.js": true, "gulp-autoprefixer>postcss": true, + "gulp-sass>picocolors": true, "stylelint>autoprefixer>normalize-range": true, "stylelint>postcss-value-parser": true, "webpack>browserslist": true, @@ -3306,85 +3296,9 @@ "process.env.NODE_ENV": true }, "packages": { - "addons-linter>postcss>picocolors": true, "addons-linter>postcss>source-map-js": true, - "gulp-autoprefixer>postcss>nanoid": true - } - }, - "gulp-dart-sass": { - "builtin": { - "path.basename": true, - "path.dirname": true, - "path.extname": true, - "path.join": true, - "path.relative": true - }, - "globals": { - "process.cwd": true, - "process.stderr.write": true - }, - "packages": { - "gulp-dart-sass>chalk": true, - "gulp-dart-sass>lodash.clonedeep": true, - "gulp-dart-sass>strip-ansi": true, - "gulp-dart-sass>through2": true, - "gulp-zip>plugin-error": true, - "sass": true, - "vinyl-sourcemaps-apply": true, - "vinyl>replace-ext": true - } - }, - "gulp-dart-sass>chalk": { - "globals": { - "process.env.TERM": true, - "process.platform": true - }, - "packages": { - "gulp-dart-sass>chalk>ansi-styles": true, - "gulp-dart-sass>chalk>escape-string-regexp": true, - "gulp-dart-sass>chalk>supports-color": true - } - }, - "gulp-dart-sass>chalk>ansi-styles": { - "packages": { - "@metamask/jazzicon>color>color-convert": true - } - }, - "gulp-dart-sass>chalk>supports-color": { - "builtin": { - "os.release": true - }, - "globals": { - "process.env": true, - "process.platform": true, - "process.stderr": true, - "process.stdout": true, - "process.versions.node.split": true - }, - "packages": { - "gulp-dart-sass>chalk>supports-color>has-flag": true - } - }, - "gulp-dart-sass>chalk>supports-color>has-flag": { - "globals": { - "process.argv": true - } - }, - "gulp-dart-sass>strip-ansi": { - "packages": { - "gulp-dart-sass>strip-ansi>ansi-regex": true - } - }, - "gulp-dart-sass>through2": { - "builtin": { - "util.inherits": true - }, - "globals": { - "process.nextTick": true - }, - "packages": { - "readable-stream": true, - "watchify>xtend": true + "gulp-autoprefixer>postcss>nanoid": true, + "gulp-sass>picocolors": true } }, "gulp-livereload": { @@ -3406,8 +3320,8 @@ "process.platform": true }, "packages": { - "gulp-dart-sass>chalk>escape-string-regexp": true, "gulp-livereload>chalk>ansi-styles": true, + "gulp-livereload>chalk>escape-string-regexp": true, "gulp-livereload>chalk>supports-color": true } }, @@ -3680,7 +3594,7 @@ "process.platform": true }, "packages": { - "gulp-dart-sass>chalk>escape-string-regexp": true, + "gulp-livereload>chalk>escape-string-regexp": true, "gulp-rtlcss>rtlcss>chalk>ansi-styles": true, "gulp-rtlcss>rtlcss>chalk>supports-color": true } @@ -3739,6 +3653,48 @@ "watchify>xtend": true } }, + "gulp-sass": { + "builtin": { + "path.basename": true, + "path.dirname": true, + "path.extname": true, + "path.join": true, + "path.relative": true, + "stream.Transform": true + }, + "globals": { + "process.cwd": true, + "process.exit": true, + "process.stderr.write": true + }, + "packages": { + "eslint>strip-ansi": true, + "gulp-sass>lodash.clonedeep": true, + "gulp-sass>picocolors": true, + "gulp-sass>replace-ext": true, + "gulp-zip>plugin-error": true, + "vinyl-sourcemaps-apply": true + } + }, + "gulp-sass>picocolors": { + "builtin": { + "tty.isatty": true + }, + "globals": { + "process.argv.includes": true, + "process.env": true, + "process.platform": true + } + }, + "gulp-sass>replace-ext": { + "builtin": { + "path.basename": true, + "path.dirname": true, + "path.extname": true, + "path.join": true, + "path.sep": true + } + }, "gulp-sort": { "packages": { "gulp-sort>through2": true @@ -6017,7 +5973,7 @@ "process.platform": true }, "packages": { - "gulp-dart-sass>chalk>escape-string-regexp": true, + "gulp-livereload>chalk>escape-string-regexp": true, "lavamoat>@babel/highlight>chalk>ansi-styles": true, "lavamoat>@babel/highlight>chalk>supports-color": true } @@ -8010,4 +7966,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 5deb72096..d89c7421a 100644 --- a/package.json +++ b/package.json @@ -408,7 +408,7 @@ "@types/fs-extra": "^9.0.13", "@types/gulp": "^4.0.9", "@types/gulp-autoprefixer": "^0.0.33", - "@types/gulp-dart-sass": "^1.0.1", + "@types/gulp-sass": "^5.0.0", "@types/gulp-sourcemaps": "^0.0.35", "@types/jest": "^29.1.2", "@types/jest-when": "^3.5.2", @@ -420,6 +420,7 @@ "@types/react-dom": "^17.0.11", "@types/react-redux": "^7.1.25", "@types/remote-redux-devtools": "^0.5.5", + "@types/sass": "^1.43.1", "@types/sinon": "^10.0.13", "@types/w3c-web-hid": "^1.0.3", "@types/watchify": "^3.11.1", @@ -468,10 +469,10 @@ "globby": "^11.0.4", "gulp": "^4.0.2", "gulp-autoprefixer": "^8.0.0", - "gulp-dart-sass": "^1.0.2", "gulp-livereload": "4.0.0", "gulp-rename": "^2.0.0", "gulp-rtlcss": "^1.4.0", + "gulp-sass": "^5.1.0", "gulp-sort": "^2.0.0", "gulp-sourcemaps": "^3.0.0", "gulp-stylelint": "^13.0.0", diff --git a/yarn.lock b/yarn.lock index 17f17f5da..7eb218304 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7309,12 +7309,13 @@ __metadata: languageName: node linkType: hard -"@types/gulp-dart-sass@npm:^1.0.1": - version: 1.0.1 - resolution: "@types/gulp-dart-sass@npm:1.0.1" +"@types/gulp-sass@npm:^5.0.0": + version: 5.0.0 + resolution: "@types/gulp-sass@npm:5.0.0" dependencies: - "@types/sass": "*" - checksum: 32a8398912d10f78e9915b58a26d0fa84a092da9ab4fb2eb46f6d3449266d54136636df828ad31f5435f29c1ed7b267055b46b410d9c1b429670edb0c0a89a62 + "@types/node": "*" + "@types/node-sass": "*" + checksum: bea3995c4a37b3d9c81eb30f1544698469d11e12948ce1b73e6d7ec1e225c4a383ec5add05c5393931a7c51a45cf91a34d76afb7f2b9453b309b7c0a1bdf3bc9 languageName: node linkType: hard @@ -7578,6 +7579,15 @@ __metadata: languageName: node linkType: hard +"@types/node-sass@npm:*": + version: 4.11.3 + resolution: "@types/node-sass@npm:4.11.3" + dependencies: + "@types/node": "*" + checksum: 6205b95d6c2a215fefcdfba283f4f237bbe95b088119bd00503171b84762d15f6b9b11fe424407f38ac7b8174b20bb4cd137466550f4a49961f3ac54e6ed4812 + languageName: node + linkType: hard + "@types/node@npm:*, @types/node@npm:>=13.7.0": version: 18.7.18 resolution: "@types/node@npm:18.7.18" @@ -7752,7 +7762,7 @@ __metadata: languageName: node linkType: hard -"@types/sass@npm:*": +"@types/sass@npm:^1.43.1": version: 1.43.1 resolution: "@types/sass@npm:1.43.1" dependencies: @@ -11727,7 +11737,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.3.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.4.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -18456,22 +18466,6 @@ __metadata: languageName: node linkType: hard -"gulp-dart-sass@npm:^1.0.2": - version: 1.0.2 - resolution: "gulp-dart-sass@npm:1.0.2" - dependencies: - chalk: ^2.3.0 - lodash.clonedeep: ^4.3.2 - plugin-error: ^1.0.1 - replace-ext: ^1.0.0 - sass: ^1.26.3 - strip-ansi: ^4.0.0 - through2: ^2.0.0 - vinyl-sourcemaps-apply: ^0.2.0 - checksum: 77ad8a6588e8710748c694b1b1d7ad558eca168c82cebe2579dd887abfdc3a912b44997a75776bdd14aa5dc3749aff1def7911871a7ef6f6ba54991162de288b - languageName: node - linkType: hard - "gulp-livereload@npm:4.0.0": version: 4.0.0 resolution: "gulp-livereload@npm:4.0.0" @@ -18506,6 +18500,20 @@ __metadata: languageName: node linkType: hard +"gulp-sass@npm:^5.1.0": + version: 5.1.0 + resolution: "gulp-sass@npm:5.1.0" + dependencies: + lodash.clonedeep: ^4.5.0 + picocolors: ^1.0.0 + plugin-error: ^1.0.1 + replace-ext: ^2.0.0 + strip-ansi: ^6.0.1 + vinyl-sourcemaps-apply: ^0.2.1 + checksum: 9aba052c76e808321f9ecf70885806a389e73b87005c3c4f47beba7050ef280d06402f1ac19105b32407170b6fdef5c9e26ed0560074dd5a949197b50e82604d + languageName: node + linkType: hard + "gulp-sort@npm:^2.0.0": version: 2.0.0 resolution: "gulp-sort@npm:2.0.0" @@ -23246,7 +23254,7 @@ __metadata: languageName: node linkType: hard -"lodash.clonedeep@npm:^4.3.2": +"lodash.clonedeep@npm:^4.5.0": version: 4.5.0 resolution: "lodash.clonedeep@npm:4.5.0" checksum: 92c46f094b064e876a23c97f57f81fbffd5d760bf2d8a1c61d85db6d1e488c66b0384c943abee4f6af7debf5ad4e4282e74ff83177c9e63d8ff081a4837c3489 @@ -24144,7 +24152,7 @@ __metadata: "@types/fs-extra": ^9.0.13 "@types/gulp": ^4.0.9 "@types/gulp-autoprefixer": ^0.0.33 - "@types/gulp-dart-sass": ^1.0.1 + "@types/gulp-sass": ^5.0.0 "@types/gulp-sourcemaps": ^0.0.35 "@types/jest": ^29.1.2 "@types/jest-when": ^3.5.2 @@ -24156,6 +24164,7 @@ __metadata: "@types/react-dom": ^17.0.11 "@types/react-redux": ^7.1.25 "@types/remote-redux-devtools": ^0.5.5 + "@types/sass": ^1.43.1 "@types/sinon": ^10.0.13 "@types/w3c-web-hid": ^1.0.3 "@types/watchify": ^3.11.1 @@ -24238,10 +24247,10 @@ __metadata: globby: ^11.0.4 gulp: ^4.0.2 gulp-autoprefixer: ^8.0.0 - gulp-dart-sass: ^1.0.2 gulp-livereload: 4.0.0 gulp-rename: ^2.0.0 gulp-rtlcss: ^1.4.0 + gulp-sass: ^5.1.0 gulp-sort: ^2.0.0 gulp-sourcemaps: ^3.0.0 gulp-stylelint: ^13.0.0 @@ -29477,6 +29486,13 @@ __metadata: languageName: node linkType: hard +"replace-ext@npm:^2.0.0": + version: 2.0.0 + resolution: "replace-ext@npm:2.0.0" + checksum: ed640ac90d24cce4be977642847d138908d430049cc097633be33b072143515cc7d29699675a0c35f6dc3c3c73cb529ed352d59649cf15931740eb31ae083c1e + languageName: node + linkType: hard + "replace-homedir@npm:^1.0.0": version: 1.0.0 resolution: "replace-homedir@npm:1.0.0" @@ -34220,7 +34236,7 @@ __metadata: languageName: node linkType: hard -"vinyl-sourcemaps-apply@npm:^0.2.0, vinyl-sourcemaps-apply@npm:^0.2.1": +"vinyl-sourcemaps-apply@npm:^0.2.1": version: 0.2.1 resolution: "vinyl-sourcemaps-apply@npm:0.2.1" dependencies: From a4a5b28f2e66497bcf5d1a139320322e5c44e075 Mon Sep 17 00:00:00 2001 From: Pedro Figueiredo Date: Tue, 25 Apr 2023 16:21:14 +0100 Subject: [PATCH 32/60] Fix diff generation for fitness functions (#18508) --- .github/workflows/fitness-functions.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/fitness-functions.yml b/.github/workflows/fitness-functions.yml index 1b55fb461..4b87151d4 100644 --- a/.github/workflows/fitness-functions.yml +++ b/.github/workflows/fitness-functions.yml @@ -17,12 +17,13 @@ jobs: with: node-version: '16' + - name: Install dependencies + run: yarn + - name: Run fitness functions env: - HEAD_REF: ${{ github.event.pull_request.head.ref }} BASE_REF: ${{ github.event.pull_request.base.ref }} run: | - # git fetch origin $HEAD_REF - # git fetch origin $BASE_REF - # git diff origin/$BASE_REF origin/$HEAD_REF -- . > diff - # npm run fitness-functions -- "ci" "./diff" + git fetch origin $BASE_REF + git diff origin/$BASE_REF HEAD -- . > diff + npm run fitness-functions -- "ci" "./diff" \ No newline at end of file From 6126c156ea25cddd2d3ef116f02cb36c62d3c632 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Tue, 25 Apr 2023 19:20:37 +0200 Subject: [PATCH 33/60] [FLASK] Expanded Snap authorship (#18775) --- app/_locales/en/messages.json | 31 ++- ui/components/app/app-components.scss | 1 + .../snaps/snap-authorship/snap-authorship.js | 167 ++++++++++++---- .../app/snaps/snap-avatar/snap-avatar.js | 4 +- ui/components/app/snaps/snap-version/index.js | 1 + .../app/snaps/snap-version/index.scss | 15 ++ .../app/snaps/snap-version/snap-version.js | 72 +++++++ .../snap-version/snap-version.stories.js | 20 ++ .../snaps/snap-version/snap-version.test.js | 27 +++ ui/helpers/constants/flask/delineator.ts | 3 + .../snaps/snap-install/index.scss | 2 +- .../snaps/snap-install/snap-install.js | 12 +- .../snaps/snap-update/index.scss | 2 +- .../snaps/snap-update/snap-update.js | 8 +- ui/pages/settings/snaps/view-snap/index.scss | 33 ++- .../settings/snaps/view-snap/view-snap.js | 188 ++++++------------ .../snaps/view-snap/view-snap.test.js | 7 +- 17 files changed, 396 insertions(+), 197 deletions(-) create mode 100644 ui/components/app/snaps/snap-version/index.js create mode 100644 ui/components/app/snaps/snap-version/index.scss create mode 100644 ui/components/app/snaps/snap-version/snap-version.js create mode 100644 ui/components/app/snaps/snap-version/snap-version.stories.js create mode 100644 ui/components/app/snaps/snap-version/snap-version.test.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 8ad86eebb..545acc4f4 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1066,6 +1066,10 @@ "description": { "message": "Description" }, + "descriptionFromSnap": { + "message": "Description from $1", + "description": "$1 represents the name of the snap" + }, "desktopConnectionCriticalErrorDescription": { "message": "This error could be intermittent, so try restarting the extension or disable MetaMask Desktop." }, @@ -1331,10 +1335,7 @@ "message": "Enable smart transactions" }, "enableSnap": { - "message": "Enable snap" - }, - "enableSnapDescription": { - "message": "Your installed snap will only have access to its permissions and run if it’s enabled." + "message": "Enable" }, "enableToken": { "message": "enable $1", @@ -1851,6 +1852,13 @@ "install": { "message": "Install" }, + "installOrigin": { + "message": "Install origin" + }, + "installedOn": { + "message": "Installed on $1", + "description": "$1 is the date when the snap has been installed" + }, "institutionalFeatures": { "message": "Institutional Features" }, @@ -2192,6 +2200,9 @@ "mmiAuthenticate": { "message": "The page at $1 would like to authorise the following project’s compliance settings in MetaMask Institutional" }, + "more": { + "message": "more" + }, "moreComingSoon": { "message": "More coming soon..." }, @@ -3576,6 +3587,10 @@ "settingsSearchMatchingNotFound": { "message": "No matching results found." }, + "shortVersion": { + "message": "v$1", + "description": "$1 is the version number to show" + }, "show": { "message": "Show" }, @@ -4510,7 +4525,6 @@ "transactionFailed": { "message": "Transaction Failed" }, - "transactionFee": { "message": "Transaction fee" }, @@ -4737,6 +4751,9 @@ "message": "Verify this token on $1 and make sure this is the token you want to trade.", "description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\"" }, + "version": { + "message": "Version" + }, "view": { "message": "View" }, @@ -4870,10 +4887,6 @@ "message": "You've added all the popular networks. You can discover more networks $1 Or you can $2", "description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'" }, - "youInstalled": { - "message": "You installed", - "description": "Part of version description for installed snap" - }, "youNeedToAllowCameraAccess": { "message": "You need to allow camera access to use this feature." }, diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index b6422b632..81ab85809 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -43,6 +43,7 @@ @import 'snaps/snap-settings-card/index'; @import 'snaps/update-snap-permission-list/index'; @import 'snaps/copyable/index'; +@import 'snaps/snap-version/index'; @import 'gas-details-item/index'; @import 'gas-details-item/gas-details-item-title/index'; @import 'gas-timing/index'; diff --git a/ui/components/app/snaps/snap-authorship/snap-authorship.js b/ui/components/app/snaps/snap-authorship/snap-authorship.js index 66f3fa59b..14842afaa 100644 --- a/ui/components/app/snaps/snap-authorship/snap-authorship.js +++ b/ui/components/app/snaps/snap-authorship/snap-authorship.js @@ -2,30 +2,42 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { getSnapPrefix } from '@metamask/snaps-utils'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import Box from '../../../ui/box'; import { BackgroundColor, TextColor, - IconColor, FLEX_DIRECTION, TextVariant, BorderColor, AlignItems, DISPLAY, - BorderRadius, BLOCK_SIZES, + JustifyContent, + BorderStyle, + Color, + BorderRadius, } from '../../../../helpers/constants/design-system'; import { + formatDate, getSnapName, removeSnapIdPrefix, } from '../../../../helpers/utils/util'; -import { ButtonIcon, IconName, Text } from '../../../component-library'; +import { Text, ButtonLink } from '../../../component-library'; import { getTargetSubjectMetadata } from '../../../../selectors'; import SnapAvatar from '../snap-avatar'; +import { useI18nContext } from '../../../../hooks/useI18nContext'; +import Tooltip from '../../../ui/tooltip/tooltip'; +import ToggleButton from '../../../ui/toggle-button'; +import { disableSnap, enableSnap } from '../../../../store/actions'; +import { useOriginMetadata } from '../../../../hooks/useOriginMetadata'; +import SnapVersion from '../snap-version/snap-version'; + +const SnapAuthorship = ({ snapId, className, expanded = false, snap }) => { + const t = useI18nContext(); + const dispatch = useDispatch(); -const SnapAuthorship = ({ snapId, className }) => { // We're using optional chaining with snapId, because with the current implementation // of snap update in the snap controller, we do not have reference to snapId when an // update request is rejected because the reference comes from the request itself and not subject metadata @@ -43,48 +55,127 @@ const SnapAuthorship = ({ snapId, className }) => { const friendlyName = snapId && getSnapName(snapId, subjectMetadata); + // Expanded data + const versionHistory = snap?.versionHistory ?? []; + const installInfo = versionHistory.length + ? versionHistory[versionHistory.length - 1] + : undefined; + const installOrigin = useOriginMetadata(installInfo?.origin); + + const onToggle = () => { + if (snap?.enabled) { + dispatch(disableSnap(snap?.id)); + } else { + dispatch(enableSnap(snap?.id)); + } + }; + return ( - - - - {friendlyName} - + + + - {packageName} - + {friendlyName} + + {packageName} + + + {!expanded && ( + + + + )} - + {expanded && ( + + + {t('enableSnap')} + + + + + + + + {installOrigin && installInfo && ( + + + {t('installOrigin')} + + + + {installOrigin.host} + + + {t('installedOn', [ + formatDate(installInfo.date, 'dd MMM yyyy'), + ])} + + + + )} + + {t('version')} + + + + + )} ); }; @@ -98,6 +189,14 @@ SnapAuthorship.propTypes = { * The className of the SnapAuthorship */ className: PropTypes.string, + /** + * If the authorship component should be expanded + */ + expanded: PropTypes.bool, + /** + * The snap object. Can be undefined if the component is not expanded + */ + snap: PropTypes.object, }; export default SnapAuthorship; diff --git a/ui/components/app/snaps/snap-avatar/snap-avatar.js b/ui/components/app/snaps/snap-avatar/snap-avatar.js index cdf85e117..2cd3d1ec6 100644 --- a/ui/components/app/snaps/snap-avatar/snap-avatar.js +++ b/ui/components/app/snaps/snap-avatar/snap-avatar.js @@ -50,10 +50,10 @@ const SnapAvatar = ({ snapId, className }) => { position={BadgeWrapperPosition.bottomRight} > {iconUrl ? ( - + ) : ( { + const t = useI18nContext(); + return ( + + ); +}; + +SnapVersion.propTypes = { + /** + * The version of the snap + */ + version: PropTypes.string, + /** + * The url to the snap package + */ + url: PropTypes.string, +}; + +export default SnapVersion; diff --git a/ui/components/app/snaps/snap-version/snap-version.stories.js b/ui/components/app/snaps/snap-version/snap-version.stories.js new file mode 100644 index 000000000..90f179d87 --- /dev/null +++ b/ui/components/app/snaps/snap-version/snap-version.stories.js @@ -0,0 +1,20 @@ +import React from 'react'; +import SnapVersion from '.'; + +export default { + title: 'Components/App/Snaps/SnapVersion', + component: SnapVersion, +}; +export const DefaultStory = (args) => ; + +DefaultStory.args = { + version: '1.4.2', + url: 'https://www.npmjs.com/package/@metamask/test-snap-error', +}; + +export const LoadingStory = (args) => ; + +LoadingStory.args = { + version: undefined, + url: 'https://www.npmjs.com/package/@metamask/test-snap-error', +}; diff --git a/ui/components/app/snaps/snap-version/snap-version.test.js b/ui/components/app/snaps/snap-version/snap-version.test.js new file mode 100644 index 000000000..447a95931 --- /dev/null +++ b/ui/components/app/snaps/snap-version/snap-version.test.js @@ -0,0 +1,27 @@ +import * as React from 'react'; +import { renderWithLocalization } from '../../../../../test/lib/render-helpers'; +import SnapVersion from './snap-version'; + +describe('SnapVersion', () => { + const args = { + version: '1.4.2', + url: 'https://www.npmjs.com/package/@metamask/test-snap-error', + }; + + it('should render the SnapVersion without crashing and display a version', () => { + const { getByText, container } = renderWithLocalization( + , + ); + expect(getByText(`v${args.version}`)).toBeDefined(); + expect(container.firstChild).toHaveAttribute('href', args.url); + }); + + it('should have a loading state if no version is passed', () => { + args.version = undefined; + + const { container } = renderWithLocalization(); + + expect(container.getElementsByClassName('preloader__icon')).toHaveLength(1); + expect(container.firstChild).toHaveAttribute('href', args.url); + }); +}); diff --git a/ui/helpers/constants/flask/delineator.ts b/ui/helpers/constants/flask/delineator.ts index ce5d5002b..7e3fd9f32 100644 --- a/ui/helpers/constants/flask/delineator.ts +++ b/ui/helpers/constants/flask/delineator.ts @@ -3,6 +3,7 @@ export enum DelineatorType { // eslint-disable-next-line @typescript-eslint/no-shadow Error = 'error', Insights = 'insights', + Description = 'description', } export const getDelineatorTitle = (type: DelineatorType) => { @@ -11,6 +12,8 @@ export const getDelineatorTitle = (type: DelineatorType) => { return 'errorWithSnap'; case DelineatorType.Insights: return 'insightsFromSnap'; + case DelineatorType.Description: + return 'descriptionFromSnap'; default: return 'contentFromSnap'; } diff --git a/ui/pages/permissions-connect/snaps/snap-install/index.scss b/ui/pages/permissions-connect/snaps/snap-install/index.scss index 654653ab9..4b52d3037 100644 --- a/ui/pages/permissions-connect/snaps/snap-install/index.scss +++ b/ui/pages/permissions-connect/snaps/snap-install/index.scss @@ -1,7 +1,7 @@ .snap-install { box-shadow: none; - .headers { + .content { flex: 1; .loader-container { diff --git a/ui/pages/permissions-connect/snaps/snap-install/snap-install.js b/ui/pages/permissions-connect/snaps/snap-install/snap-install.js index 8fc4fe2b4..077971e57 100644 --- a/ui/pages/permissions-connect/snaps/snap-install/snap-install.js +++ b/ui/pages/permissions-connect/snaps/snap-install/snap-install.js @@ -84,13 +84,13 @@ export default function SnapInstall({ flexDirection={FLEX_DIRECTION.COLUMN} > - - - + {!hasError && ( )} + + {isLoading && ( )} + + {isLoading && ( {t('snapUpdateRequestsPermission', [ diff --git a/ui/pages/settings/snaps/view-snap/index.scss b/ui/pages/settings/snaps/view-snap/index.scss index 6d6395cf6..745bda669 100644 --- a/ui/pages/settings/snaps/view-snap/index.scss +++ b/ui/pages/settings/snaps/view-snap/index.scss @@ -1,19 +1,36 @@ .view-snap { max-width: 475px; - &__version_info { - &__version-number { - font-weight: bold; + &__description { + &__wrapper { + position: relative; + overflow: hidden; + max-height: 5.5rem; + + @include screen-md-min { + max-height: 6rem; + } + + &.open { + max-height: none; + } } - &__link { - vertical-align: top; + &__more-button { + position: absolute; + bottom: 0; + right: 0; + width: unset; + padding: 0; + padding-left: 32px; + background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--color-background-default) 33%); } } - &__enable { - &__tooltip_wrapper { - max-width: 52px; + + &__permissions { + .permission-cell { + margin: 0; } } diff --git a/ui/pages/settings/snaps/view-snap/view-snap.js b/ui/pages/settings/snaps/view-snap/view-snap.js index 3d4bbf8a5..b7ea31df5 100644 --- a/ui/pages/settings/snaps/view-snap/view-snap.js +++ b/ui/pages/settings/snaps/view-snap/view-snap.js @@ -1,28 +1,26 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; import { SnapCaveatType, WALLET_SNAP_PERMISSION_KEY, } from '@metamask/rpc-methods'; -import { getSnapPrefix } from '@metamask/snaps-utils'; +import classnames from 'classnames'; import Button from '../../../../components/ui/button'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import { - Size, + Color, + FLEX_WRAP, TextColor, TextVariant, } from '../../../../helpers/constants/design-system'; import SnapAuthorship from '../../../../components/app/snaps/snap-authorship'; import Box from '../../../../components/ui/box'; import SnapRemoveWarning from '../../../../components/app/snaps/snap-remove-warning'; -import ToggleButton from '../../../../components/ui/toggle-button'; import ConnectedSitesList from '../../../../components/app/connected-sites-list'; -import Tooltip from '../../../../components/ui/tooltip'; + import { SNAPS_LIST_ROUTE } from '../../../../helpers/constants/routes'; import { - disableSnap, - enableSnap, removeSnap, removePermissionsFor, updateCaveat, @@ -34,18 +32,17 @@ import { getPermissionSubjects, getTargetSubjectMetadata, } from '../../../../selectors'; -import { - formatDate, - getSnapName, - removeSnapIdPrefix, -} from '../../../../helpers/utils/util'; -import { ButtonLink, Text } from '../../../../components/component-library'; +import { getSnapName } from '../../../../helpers/utils/util'; +import { Text, BUTTON_TYPES } from '../../../../components/component-library'; import SnapPermissionsList from '../../../../components/app/snaps/snap-permissions-list'; +import { SnapDelineator } from '../../../../components/app/snaps/snap-delineator'; +import { DelineatorType } from '../../../../helpers/constants/flask'; function ViewSnap() { const t = useI18nContext(); const history = useHistory(); const location = useLocation(); + const descriptionRef = useRef(null); const { pathname } = location; // The snap ID is in URI-encoded form in the last path segment of the URL. const decodedSnapId = decodeURIComponent(pathname.match(/[^/]+$/u)[0]); @@ -55,6 +52,8 @@ function ViewSnap() { .find((snapState) => snapState.id === decodedSnapId); const [isShowingRemoveWarning, setIsShowingRemoveWarning] = useState(false); + const [isDescriptionOpen, setIsDescriptionOpen] = useState(false); + const [isOverflowing, setIsOverflowing] = useState(false); useEffect(() => { if (!snap) { @@ -62,6 +61,14 @@ function ViewSnap() { } }, [history, snap]); + useEffect(() => { + setIsOverflowing( + descriptionRef.current && + descriptionRef.current.offsetHeight < + descriptionRef.current.scrollHeight, + ); + }, [descriptionRef]); + const connectedSubjects = useSelector((state) => getSubjectsWithSnapPermission(state, snap?.id), ); @@ -74,14 +81,6 @@ function ViewSnap() { ); const dispatch = useDispatch(); - const onToggle = () => { - if (snap.enabled) { - dispatch(disableSnap(snap.id)); - } else { - dispatch(enableSnap(snap.id)); - } - }; - const onDisconnect = (connectedOrigin, snapId) => { const caveatValue = subjects[connectedOrigin].permissions[WALLET_SNAP_PERMISSION_KEY] @@ -110,121 +109,51 @@ function ViewSnap() { return null; } - const versionHistory = snap.versionHistory ?? []; - const installInfo = versionHistory.length - ? versionHistory[versionHistory.length - 1] - : undefined; - const packageName = snap.id && removeSnapIdPrefix(snap.id); - const snapPrefix = snap.id && getSnapPrefix(snap.id); - const isNPM = snapPrefix === 'npm:'; - const url = isNPM - ? `https://www.npmjs.com/package/${packageName}` - : packageName; const snapName = getSnapName(snap.id, targetSubjectMetadata); + const shouldDisplayMoreButton = isOverflowing && !isDescriptionOpen; + const handleMoreClick = () => { + setIsDescriptionOpen(true); + }; + return ( - - - - - - {snap.manifest.description} - - - - - {`${t('youInstalled')} `} - - v{snap.version} - - {` ${t('ofTextNofM')} `} - + + + - {packageName} - - {installInfo && ` ${t('from').toLowerCase()} `} - {installInfo && ( - - {installInfo.origin} - - )} - {installInfo && - ` ${t('on').toLowerCase()} ${formatDate( - installInfo.date, - 'dd MMM yyyy', - )}`} - . - - - - {t('enableSnap')} - - {t('enableSnapDescription')} - - - - - - + {snap?.manifest.description} + {shouldDisplayMoreButton && ( + + )} + + - - {t('permissions')} - + {t('permissions')} - + {t('connectedSites')} @@ -235,12 +164,7 @@ function ViewSnap() { }} /> - + {t('removeSnap')} @@ -253,7 +177,13 @@ function ViewSnap() { type="danger" onClick={() => setIsShowingRemoveWarning(true)} > - + {`${t('remove')} ${snapName}`} diff --git a/ui/pages/settings/snaps/view-snap/view-snap.test.js b/ui/pages/settings/snaps/view-snap/view-snap.test.js index 320077cf6..3ce293094 100644 --- a/ui/pages/settings/snaps/view-snap/view-snap.test.js +++ b/ui/pages/settings/snaps/view-snap/view-snap.test.js @@ -48,12 +48,7 @@ describe('ViewSnap', () => { // Snap version info expect(getByText('v5.1.2')).toBeDefined(); // Enable Snap - expect(getByText('Enable snap')).toBeDefined(); - expect( - getByText( - 'Your installed snap will only have access to its permissions and run if it’s enabled.', - ), - ).toBeDefined(); + expect(getByText('Enable')).toBeDefined(); expect(container.getElementsByClassName('toggle-button')?.length).toBe(1); // Permissions expect(getByText('Permissions')).toBeDefined(); From ab3e3976e6831edf5b1f6bfb4c35e8855978ef7e Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Tue, 25 Apr 2023 23:19:02 +0530 Subject: [PATCH 34/60] Part of #17670: Replace Typography with Text component for networks-list.js (#18754) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../networks-tab/networks-list/networks-list.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ui/pages/settings/networks-tab/networks-list/networks-list.js b/ui/pages/settings/networks-tab/networks-list/networks-list.js index 6af17185d..7cb42959a 100644 --- a/ui/pages/settings/networks-tab/networks-list/networks-list.js +++ b/ui/pages/settings/networks-tab/networks-list/networks-list.js @@ -3,12 +3,12 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useI18nContext } from '../../../../hooks/useI18nContext'; import CustomContentSearch from '../custom-content-search'; -import Typography from '../../../../components/ui/typography'; import { Color, - TypographyVariant, + TextVariant, } from '../../../../helpers/constants/design-system'; import NetworksListItem from '../networks-list-item'; +import { Text } from '../../../../components/component-library'; const NetworksList = ({ networkIsSelected, @@ -62,14 +62,15 @@ const NetworksList = ({ /> ))} {searchQuery === '' && ( - {t('testNetworks')} - + )} {searchedNetworksToRenderThatAreTestNetworks.map((network, _) => ( Date: Tue, 25 Apr 2023 15:01:56 -0500 Subject: [PATCH 35/60] UX: Multichain: Use correct blockie or jazzicon in the account menu (#18782) --- .../multichain/account-list-item/account-list-item.js | 8 ++++++++ 1 file changed, 8 insertions(+) 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 05a33ea0a..5f94ddd5a 100644 --- a/ui/components/multichain/account-list-item/account-list-item.js +++ b/ui/components/multichain/account-list-item/account-list-item.js @@ -18,6 +18,7 @@ import { ButtonIcon, IconName, IconSize, + AvatarAccountVariant, } from '../../component-library'; import { Color, @@ -70,6 +71,8 @@ export const AccountListItem = ({ const t = useI18nContext(); const [accountOptionsMenuOpen, setAccountOptionsMenuOpen] = useState(false); const ref = useRef(false); + const useBlockie = useSelector((state) => state.metamask.useBlockie); + const keyring = useSelector((state) => findKeyringForAddress(state, identity.address), ); @@ -107,6 +110,11 @@ export const AccountListItem = ({ borderColor={BorderColor.transparent} size={Size.SM} address={identity.address} + variant={ + useBlockie + ? AvatarAccountVariant.Blockies + : AvatarAccountVariant.Jazzicon + } > Date: Tue, 25 Apr 2023 15:39:54 -0500 Subject: [PATCH 36/60] UX: Multichain: App header cleanups (#18627) * UX: Multichain: App header cleanups * Fix snapshot --------- Co-authored-by: David Walsh --- .../__snapshots__/app-header.test.js.snap | 2 +- .../multichain/app-header/app-header.js | 22 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap index d4d1cc8da..7592d9461 100644 --- a/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap +++ b/ui/components/multichain/app-header/__snapshots__/app-header.test.js.snap @@ -6,7 +6,7 @@ exports[`App Header should match snapshot 1`] = ` class="box multichain-app-header multichain-app-header-shadow box--display-flex box--flex-direction-row box--align-items-center box--width-full box--background-color-background-default" >
}> + StartAccessory +; +``` + +### endAccessory + +Use the `endAccessory` prop to render a component in the endAccessory position. This will override the default close `ButtonIcon`. + + + + + +```jsx +import { ModalHeader, Button, BUTTON_SIZES } from '../../component-library'; + +Demo}> + EndAccessory +; +``` 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 new file mode 100644 index 000000000..d5c717bcf --- /dev/null +++ b/ui/components/component-library/modal-header/__snapshots__/modal-header.test.tsx.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ModalHeader should render ModalHeader correctly 1`] = ` +
+
+
+

+ Modal header +

+
+
+
+`; diff --git a/ui/components/component-library/modal-header/index.ts b/ui/components/component-library/modal-header/index.ts new file mode 100644 index 000000000..54a9313c0 --- /dev/null +++ b/ui/components/component-library/modal-header/index.ts @@ -0,0 +1,2 @@ +export { ModalHeader } from './modal-header'; +export type { ModalHeaderProps } from './modal-header.types'; diff --git a/ui/components/component-library/modal-header/modal-header.stories.tsx b/ui/components/component-library/modal-header/modal-header.stories.tsx new file mode 100644 index 000000000..525379dc9 --- /dev/null +++ b/ui/components/component-library/modal-header/modal-header.stories.tsx @@ -0,0 +1,86 @@ +import React from 'react'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; + +import { + TextVariant, + TextAlign, + DISPLAY, + FLEX_DIRECTION, + AlignItems, + JustifyContent, +} from '../../../helpers/constants/design-system'; + +import { AvatarAccount, BUTTON_SIZES, Button, Text } from '..'; + +import { ModalHeader } from './modal-header'; +import README from './README.mdx'; + +export default { + title: 'Components/ComponentLibrary/ModalHeader', + component: ModalHeader, + parameters: { + docs: { + page: README, + }, + }, + argTypes: { + children: { control: 'text' }, + className: { control: 'text' }, + onBack: { action: 'onBack' }, + onClose: { action: 'onClose' }, + }, + args: { + children: 'ModalHeader', + }, +} as ComponentMeta; + +const Template: ComponentStory = (args) => { + return ; +}; + +export const DefaultStory = Template.bind({}); +DefaultStory.storyName = 'Default'; + +export const Children: ComponentStory = (args) => ( + <> + + Children as string + + + + + Custom header using multiple components + + + +); + +export const OnBack = Template.bind({}); +OnBack.args = { + children: 'OnBack demo', +}; + +export const OnClose = Template.bind({}); +OnClose.args = { + children: 'OnClose demo', +}; + +export const StartAccessory = Template.bind({}); +StartAccessory.args = { + children: 'StartAccessory demo', + startAccessory: , +}; + +export const EndAccessory = Template.bind({}); +EndAccessory.args = { + children: 'EndAccessory demo', + endAccessory: , +}; diff --git a/ui/components/component-library/modal-header/modal-header.test.tsx b/ui/components/component-library/modal-header/modal-header.test.tsx new file mode 100644 index 000000000..00fb648b9 --- /dev/null +++ b/ui/components/component-library/modal-header/modal-header.test.tsx @@ -0,0 +1,67 @@ +/* eslint-disable jest/require-top-level-describe */ +import { render, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { ModalHeader } from './modal-header'; + +describe('ModalHeader', () => { + it('should render ModalHeader correctly', () => { + const { getByTestId, container } = render( + Modal header, + ); + expect(getByTestId('modal-header')).toHaveClass('mm-modal-header'); + expect(container).toMatchSnapshot(); + }); + + it('should render modal header children as a string', () => { + const { getByText } = render( + Modal header test, + ); + expect(getByText('Modal header test')).toBeDefined(); + }); + + it('should render modal header children as a node', () => { + const { getByText, getByTestId } = render( + +
Modal header test
+
, + ); + expect(getByText('Modal header test')).toBeDefined(); + expect(getByTestId('div')).toBeDefined(); + }); + + it('should render modal header back button', () => { + const onBackTest = jest.fn(); + const { getByTestId } = render( + + ModalHeader + , + ); + + const backButton = getByTestId('back'); + fireEvent.click(backButton); + + expect(onBackTest).toHaveBeenCalled(); + }); + + it('should render modal header close button', () => { + const onCloseTest = jest.fn(); + const { getByTestId } = render( + + Modal header + , + ); + + const closeButton = getByTestId('close'); + fireEvent.click(closeButton); + + expect(onCloseTest).toHaveBeenCalled(); + }); +}); diff --git a/ui/components/component-library/modal-header/modal-header.tsx b/ui/components/component-library/modal-header/modal-header.tsx new file mode 100644 index 000000000..9cd4ca5d3 --- /dev/null +++ b/ui/components/component-library/modal-header/modal-header.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import classnames from 'classnames'; +import { HeaderBase, Text, ButtonIcon, ButtonIconSize, IconName } from '..'; +import { + TextVariant, + TextAlign, +} from '../../../helpers/constants/design-system'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { ModalHeaderProps } from '.'; + +export const ModalHeader: React.FC = ({ + children, + className = '', + startAccessory, + endAccessory, + onClose, + closeButtonProps, + onBack, + backButtonProps, + ...props +}) => { + const t = useI18nContext(); + return ( + + )) + } + endAccessory={ + endAccessory || + (onClose && ( + + )) + } + {...props} + > + {typeof children === 'string' ? ( + + {children} + + ) : ( + children + )} + + ); +}; diff --git a/ui/components/component-library/modal-header/modal-header.types.ts b/ui/components/component-library/modal-header/modal-header.types.ts new file mode 100644 index 000000000..47bb752a0 --- /dev/null +++ b/ui/components/component-library/modal-header/modal-header.types.ts @@ -0,0 +1,42 @@ +import React from 'react'; +import type { ButtonIconProps } from '../button-icon/button-icon.types'; +import type { HeaderBaseProps } from '../header-base'; + +export interface ModalHeaderProps extends HeaderBaseProps { + /** + * The contents within the ModalHeader positioned middle (popular for title use case) + */ + children?: React.ReactNode; + /** + * Additional classNames to be added to the ModalHeader component + */ + className?: string; + /** + * The onClick handler for the back `ButtonIcon` + * When passed this will allow for the back `ButtonIcon` to show + */ + onBack?: () => void; + /** + * The props to pass to the back `ButtonIcon` + */ + backButtonProps?: ButtonIconProps; + /** + * The start (left) content area of ModalHeader + * Default to have the back `ButtonIcon` when `onBack` is passed, but passing a `startAccessory` will override this + */ + startAccessory?: React.ReactNode; + /** + * The onClick handler for the close `ButtonIcon` + * When passed this will allow for the close `ButtonIcon` to show + */ + onClose?: () => void; + /** + * The props to pass to the close `ButtonIcon` + */ + closeButtonProps?: ButtonIconProps; + /** + * The end (right) content area of ModalHeader + * Default to have the close `ButtonIcon` when `onClose` is passed, but passing a `endAccessory` will override this + */ + endAccessory?: React.ReactNode; +} diff --git a/ui/components/component-library/popover-header/README.mdx b/ui/components/component-library/popover-header/README.mdx index 6910ec10c..0680c2b6a 100644 --- a/ui/components/component-library/popover-header/README.mdx +++ b/ui/components/component-library/popover-header/README.mdx @@ -3,7 +3,7 @@ import { PopoverHeader } from './popover-header'; # PopoverHeader -PopoverHeader is built on top of [HeaderBase](/docs/components-componentlibrary-headerbase--default-story) component with the most common use case of a back button in the startAccessory position, title, and close button in the endAccessory position. +`PopoverHeader` handles the title, close button and back button for all `Popover` components. It is built on top of the [HeaderBase](/docs/components-componentlibrary-headerbase--default-story) component @@ -17,16 +17,41 @@ The `PopoverHeader` accepts all props below as well as all [Box](/docs/ui-compon ### Children -Wrapping string content in the `PopoverHeader` component will be rendered in the center of the header with the default title `Text` component. +The title of the `PopoverHeader` component. Passing a `string` will render the content inside of a `Text` component. Passing any other type will render the content as is. ```jsx -import { PopoverHeader } from '../../component-library'; +import { + TextVariant, + TextAlign, + DISPLAY, + FLEX_DIRECTION, + AlignItems, + JustifyContent, +} from '../../../helpers/constants/design-system'; -Title is sentence case no period; +import { PopoverHeader, AvatarAccount, Text } from '../../component-library'; + + + Children as string + + + + + Custom header using multiple components + + ``` ### onBack diff --git a/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap b/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap index ff2a28597..d6bd840f2 100644 --- a/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap +++ b/ui/components/component-library/popover-header/__snapshots__/popover-header.test.tsx.snap @@ -7,12 +7,12 @@ exports[`PopoverHeader should render PopoverHeader correctly 1`] = ` data-testid="popover-header" >

- Popover Header + PopoverHeader

diff --git a/ui/components/component-library/popover-header/popover-header.stories.tsx b/ui/components/component-library/popover-header/popover-header.stories.tsx index a5f5d175d..92c188d81 100644 --- a/ui/components/component-library/popover-header/popover-header.stories.tsx +++ b/ui/components/component-library/popover-header/popover-header.stories.tsx @@ -1,6 +1,17 @@ import React from 'react'; import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { BUTTON_SIZES, Button } from '..'; + +import { + TextVariant, + TextAlign, + DISPLAY, + FLEX_DIRECTION, + AlignItems, + JustifyContent, +} from '../../../helpers/constants/design-system'; + +import { AvatarAccount, BUTTON_SIZES, Button, Text } from '..'; + import { PopoverHeader } from './popover-header'; import README from './README.mdx'; @@ -24,42 +35,52 @@ export default { } as ComponentMeta; const Template: ComponentStory = (args) => { - return PopoverHeader; + return ; }; export const DefaultStory = Template.bind({}); DefaultStory.storyName = 'Default'; export const Children: ComponentStory = (args) => ( - + <> + + Children as string + + + + + Custom header using multiple components + + + ); -Children.args = { - children: 'PopoverHeader Title', +export const OnBack = Template.bind({}); +OnBack.args = { + children: 'OnBack demo', }; -export const OnBack: ComponentStory = (args) => ( - OnBack Demo -); +export const OnClose = Template.bind({}); +OnClose.args = { + children: 'OnClose demo', +}; -export const OnClose: ComponentStory = (args) => ( - OnClose Demo -); +export const StartAccessory = Template.bind({}); +StartAccessory.args = { + children: 'StartAccessory demo', + startAccessory: , +}; -export const StartAccessory: ComponentStory = (args) => ( - Demo} - {...args} - > - StartAccessory - -); - -export const EndAccessory: ComponentStory = (args) => ( - Demo} - {...args} - > - EndAccessory - -); +export const EndAccessory = Template.bind({}); +EndAccessory.args = { + children: 'EndAccessory demo', + endAccessory: , +}; diff --git a/ui/components/component-library/popover-header/popover-header.test.tsx b/ui/components/component-library/popover-header/popover-header.test.tsx index ec5e4e203..8918ed6f0 100644 --- a/ui/components/component-library/popover-header/popover-header.test.tsx +++ b/ui/components/component-library/popover-header/popover-header.test.tsx @@ -6,32 +6,39 @@ import { PopoverHeader } from './popover-header'; describe('PopoverHeader', () => { it('should render PopoverHeader correctly', () => { const { getByTestId, container } = render( - - Popover Header - , + PopoverHeader, ); expect(getByTestId('popover-header')).toHaveClass('mm-popover-header'); expect(container).toMatchSnapshot(); }); - it('should render popover header title', () => { + it('should render popover header children as a string', () => { const { getByText } = render( - Popover Header Test + PopoverHeader test , ); - expect(getByText('Popover Header Test')).toBeDefined(); + expect(getByText('PopoverHeader test')).toBeDefined(); + }); + + it('should render popover header children as a node', () => { + const { getByText, getByTestId } = render( + +
PopoverHeader test
+
, + ); + expect(getByText('PopoverHeader test')).toBeDefined(); + expect(getByTestId('div')).toBeDefined(); }); it('should render popover header back button', () => { const onBackTest = jest.fn(); const { getByTestId } = render( - Popover + PopoverHeader , ); @@ -45,11 +52,10 @@ describe('PopoverHeader', () => { const onCloseTest = jest.fn(); const { getByTestId } = render( - Popover + PopoverHeader , ); diff --git a/ui/components/component-library/popover-header/popover-header.types.ts b/ui/components/component-library/popover-header/popover-header.types.ts index 66f8c7379..a965dbd54 100644 --- a/ui/components/component-library/popover-header/popover-header.types.ts +++ b/ui/components/component-library/popover-header/popover-header.types.ts @@ -8,7 +8,7 @@ export interface PopoverHeaderProps extends HeaderBaseProps { */ children?: React.ReactNode; /** - * Additional classNames to be added to the Popover component + * Additional classNames to be added to the PopoverHeader component */ className?: string; /** From 82a64195a254b39fe3573221d639138b5176db4d Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Wed, 26 Apr 2023 05:43:38 +0530 Subject: [PATCH 39/60] Enable editing L2 gas on optimism (#18217) --- app/_locales/de/messages.json | 3 - app/_locales/el/messages.json | 3 - app/_locales/en/messages.json | 6 +- app/_locales/es/messages.json | 3 - app/_locales/fr/messages.json | 3 - app/_locales/hi/messages.json | 3 - app/_locales/id/messages.json | 3 - app/_locales/ja/messages.json | 3 - app/_locales/ko/messages.json | 3 - app/_locales/pt/messages.json | 3 - app/_locales/ru/messages.json | 3 - app/_locales/tl/messages.json | 3 - app/_locales/tr/messages.json | 3 - app/_locales/vi/messages.json | 3 - app/_locales/zh_CN/messages.json | 3 - .../advanced-gas-controls.component.js | 8 -- .../advanced-gas-inputs.component.js | 9 -- .../advanced-gas-inputs.container.js | 9 +- .../approve-content-card.js | 47 +++++--- .../confirm-legacy-gas-display.js | 37 ++++++ .../confirm-legacy-gas-display.test.js | 112 ++++++++++++------ .../multi-layer-fee-message.test.js.snap | 98 +++++++++++++++ .../multi-layer-fee-message.js | 74 +++++++----- .../multi-layer-fee-message.test.js | 46 +++++++ .../confirm-approve-content.component.js | 32 ++++- ui/pages/confirm-approve/confirm-approve.js | 9 ++ .../confirm-transaction-base.component.js | 16 +-- .../confirm-transaction-base.container.js | 2 - .../confirm-transaction-base.test.js | 14 ++- .../confirm-token-transaction-switch.js | 3 + .../send-content/send-content.component.js | 4 +- .../send-content/send-content.container.js | 2 + ui/pages/token-allowance/token-allowance.js | 7 ++ ui/selectors/selectors.js | 6 +- 34 files changed, 407 insertions(+), 176 deletions(-) create mode 100644 ui/components/app/multilayer-fee-message/__snapshots__/multi-layer-fee-message.test.js.snap create mode 100644 ui/components/app/multilayer-fee-message/multi-layer-fee-message.test.js diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index d56c2fe06..4c554e0c6 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -1416,9 +1416,6 @@ "message": "Diese Gasgebühr wurde von $1 vorgeschlagen. Dies kann ein Problem mit Ihrer Transaktion verursachen. Bei Fragen wenden Sie sich bitte an $1.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Gasgebühr" - }, "gasLimit": { "message": "Gaslimit" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 11a5bdf85..e31f46d2b 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -1416,9 +1416,6 @@ "message": "Αυτό το τέλος συναλλαγής έχει προταθεί από το $1. Η παράκαμψη μπορεί να προκαλέσει πρόβλημα με τη συναλλαγή σας. Εάν έχετε απορίες, επικοινωνήστε με $1.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Τέλη Συναλλαγής" - }, "gasLimit": { "message": "Όριο τέλους συναλλαγής" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 545acc4f4..2eba88ef0 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1552,9 +1552,6 @@ "message": "This gas fee has been suggested by $1. Overriding this may cause a problem with your transaction. Please reach out to $1 if you have questions.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Gas fee" - }, "gasLimit": { "message": "Gas limit" }, @@ -1973,6 +1970,9 @@ "lastSold": { "message": "Last sold" }, + "layer1Fees": { + "message": "Layer 1 fees" + }, "learnCancelSpeeedup": { "message": "Learn how to $1", "description": "$1 is link to cancel or speed up transactions" diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 6d0036fa4..34a984b51 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -1416,9 +1416,6 @@ "message": "Esta tarifa de gas ha sido sugerida por $1. Anularla puede causar un problema con su transacción. Comuníquese con $1 si tiene preguntas.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Cuota de gas" - }, "gasLimit": { "message": "Límite de gas" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 42b38286c..d0ea3e1fb 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -1416,9 +1416,6 @@ "message": "Ce prix de carburant a été suggéré par $1. Si vous n’en tenez pas compte, vous risquez de rencontrer des difficultés lors de votre transaction. Veuillez contacter $1 pour toute question.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Frais de transaction" - }, "gasLimit": { "message": "Montant maximal des frais de transaction" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index a868af14d..c845b2fa9 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -1416,9 +1416,6 @@ "message": "यह गैस शुल्क $1 द्वारा सुझाया गया है। इसे ओवरराइड करने से आपके लेन-देन में समस्या हो सकती है। यदि आपके पास कोई सवाल हैं तो कृपया $1 तक पहुंचें।", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "गैस शुल्क" - }, "gasLimit": { "message": "गैस की सीमा" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 81e8d6d71..4895a2f11 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -1416,9 +1416,6 @@ "message": "Biaya gas ini telah disarankan oleh $1. Pengabaian dapat menyebabkan masalah pada transaksi Anda. Hubungi $1 jika ada pertanyaan.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Biaya gas" - }, "gasLimit": { "message": "Batas gas" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 632b32d10..023a1a417 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -1416,9 +1416,6 @@ "message": "このガス代は$1により提案されています。これを上書きすると、トランザクションに問題が発生する可能性があります。ご質問がございましたら、$1までお問い合わせください。", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "ガス代" - }, "gasLimit": { "message": "ガスリミット" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 76a8f0b22..2f69acff1 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -1416,9 +1416,6 @@ "message": "$1에서 이 가스 요금을 제안했습니다. 이를 무시하면 거래에 문제가 발생할 수 있습니다. 질문이 있는 경우 $1에 문의하세요.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "가스 수수료" - }, "gasLimit": { "message": "가스 한도" }, diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 0d06c5bcb..2f2352b27 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -1416,9 +1416,6 @@ "message": "Essa taxa de gás foi sugerida por $1. Sua substituição pode causar um problema com a sua transação. Entre em contato com $1 se tiver perguntas.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Taxa de gás" - }, "gasLimit": { "message": "Limite de gás" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 04fe18e52..b1a5efb92 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -1416,9 +1416,6 @@ "message": "Эта плата за газ была предложена $1. Ее переопредление может вызвать проблемы с вашей транзакцией. При наличии вопросов обратитесь к $1.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Плата за газ" - }, "gasLimit": { "message": "Лимит газа" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index 847e1d3eb..f5f608133 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -1416,9 +1416,6 @@ "message": "Ang gas fee na ito ay iminungkahi ng $1. Ang pag-override dito ay maaaring magdulot ng problema sa iyong transaksyon. Mangyaring makipag-ugnayan sa $1 kung mayroon kang mga tanong.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Bayarin sa Gas" - }, "gasLimit": { "message": "Limitasyon sa Gas" }, diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index b6be9fdce..d957149c2 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -1416,9 +1416,6 @@ "message": "Bu gaz ücreti $1 tarafından önerilmiştir. Bu değerin başka bir değerle değiştirilmesi işleminizle ilgili bir soruna neden olabilir. Sorularınız olursa lütfen $1 ile iletişime geçin.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Gaz ücreti" - }, "gasLimit": { "message": "Gaz limiti" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 226fbed51..54687ced6 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -1416,9 +1416,6 @@ "message": "Phí gas này đã được gợi ý bởi $1. Việc sửa đổi có thể khiến giao dịch của bạn gặp sự cố. Vui lòng liên hệ với $1 nếu bạn có câu hỏi.", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "Phí gas" - }, "gasLimit": { "message": "Giới hạn gas" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index ce0020821..8a05db500 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -1416,9 +1416,6 @@ "message": "这笔燃料费是由 $1 建议的。忽略它可能会导致您的交易出现问题。如果您有疑问,请联系 $1。", "description": "$1 represents the Dapp's origin" }, - "gasFee": { - "message": "燃料费" - }, "gasLimit": { "message": "燃料上限" }, diff --git a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js index 547d0dced..8068a41e9 100644 --- a/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js +++ b/ui/components/app/advanced-gas-controls/advanced-gas-controls.component.js @@ -1,11 +1,9 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; import { I18nContext } from '../../../contexts/i18n'; import FormField from '../../ui/form-field'; import { getGasFormErrorText } from '../../../helpers/constants/gas'; -import { getNetworkSupportsSettingGasFees } from '../../../selectors'; export default function AdvancedGasControls({ onManualChange, @@ -18,10 +16,6 @@ export default function AdvancedGasControls({ }) { const t = useContext(I18nContext); - const networkSupportsSettingGasFees = useSelector( - getNetworkSupportsSettingGasFees, - ); - return (
<> @@ -58,7 +51,6 @@ export default function AdvancedGasControls({ ? getGasFormErrorText(gasErrors.gasPrice, t) : null } - disabled={!networkSupportsSettingGasFees} />
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 a6841767a..cda7f4d73 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 @@ -20,12 +20,10 @@ export default class AdvancedGasInputs extends Component { customGasLimitMessage: PropTypes.string, minimumGasLimit: PropTypes.number, customPriceIsExcessive: PropTypes.bool, - networkSupportsSettingGasFees: PropTypes.bool, }; static defaultProps = { customPriceIsExcessive: false, - networkSupportsSettingGasFees: true, }; constructor(props) { @@ -203,14 +201,9 @@ export default class AdvancedGasInputs extends Component { customGasLimitMessage, minimumGasLimit, customPriceIsExcessive, - networkSupportsSettingGasFees, } = this.props; const { gasPrice, gasLimit } = this.state; - if (!networkSupportsSettingGasFees) { - return null; - } - const { errorText: gasPriceErrorText, errorType: gasPriceErrorType } = this.gasPriceError({ insufficientBalance, @@ -253,7 +246,6 @@ export default class AdvancedGasInputs extends Component { onChange: this.onChangeGasPrice, errorComponent: gasPriceErrorComponent, errorType: gasPriceErrorType, - disabled: !networkSupportsSettingGasFees, })} {this.renderGasInput({ label: this.context.t('gasLimit'), @@ -264,7 +256,6 @@ export default class AdvancedGasInputs extends Component { errorComponent: gasLimitErrorComponent, customMessageComponent: gasLimitCustomMessageComponent, errorType: gasLimitErrorType, - disabled: !networkSupportsSettingGasFees, })}
); diff --git a/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.container.js b/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.container.js index dc2b09a17..4736de011 100644 --- a/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.container.js +++ b/ui/components/app/advanced-gas-inputs/advanced-gas-inputs.container.js @@ -1,5 +1,4 @@ import { connect } from 'react-redux'; -import { getNetworkSupportsSettingGasFees } from '../../../selectors/selectors'; import { MIN_GAS_LIMIT_DEC } from '../../../pages/send/send.constants'; import { decGWEIToHexWEI, @@ -20,12 +19,6 @@ function convertMinimumGasLimitForInputs(minimumGasLimit = MIN_GAS_LIMIT_DEC) { return parseInt(minimumGasLimit, 10); } -function mapStateToProps(state) { - return { - networkSupportsSettingGasFees: getNetworkSupportsSettingGasFees(state), - }; -} - function mergeProps(stateProps, dispatchProps, ownProps) { const { customGasPrice, @@ -47,4 +40,4 @@ function mergeProps(stateProps, dispatchProps, ownProps) { }; } -export default connect(mapStateToProps, null, mergeProps)(AdvancedGasInputs); +export default connect(undefined, null, mergeProps)(AdvancedGasInputs); diff --git a/ui/components/app/approve-content-card/approve-content-card.js b/ui/components/app/approve-content-card/approve-content-card.js index bc5665209..8f188b9ba 100644 --- a/ui/components/app/approve-content-card/approve-content-card.js +++ b/ui/components/app/approve-content-card/approve-content-card.js @@ -1,6 +1,8 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; +import { useSelector } from 'react-redux'; + import Box from '../../ui/box/box'; import Button from '../../ui/button'; import EditGasFeeButton from '../edit-gas-fee-button/edit-gas-fee-button'; @@ -16,10 +18,14 @@ import { TextColor, TextVariant, } from '../../../helpers/constants/design-system'; +import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import { I18nContext } from '../../../contexts/i18n'; +import { getPreferences } from '../../../selectors'; import { ConfirmGasDisplay } from '../confirm-gas-display'; import MultiLayerFeeMessage from '../multilayer-fee-message/multi-layer-fee-message'; import { formatCurrency } from '../../../helpers/utils/confirm-tx.util'; +import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component'; +import UserPreferencedCurrencyDisplay from '../user-preferenced-currency-display'; export default function ApproveContentCard({ showHeader = true, @@ -37,6 +43,7 @@ export default function ApproveContentCard({ ethTransactionTotal, nativeCurrency, fullTxData, + hexMinimumTransactionFee, hexTransactionTotal, fiatTransactionTotal, currentCurrency, @@ -48,6 +55,7 @@ export default function ApproveContentCard({ useCurrencyRateCheck, }) { const t = useContext(I18nContext); + const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); return ( - - - {t('transactionDetailLayer2GasHeading')} - {`${ethTransactionTotal} ${nativeCurrency}`} - - + + } + detailText={ + + } + noBold + flexWidthValues + /> process.env.IN_TEST ? null : ; @@ -32,8 +35,10 @@ const ConfirmLegacyGasDisplay = () => { // state selectors const isMainnet = useSelector(getIsMainnet); + const isMultiLayerFeeNetwork = useSelector(getIsMultiLayerFeeNetwork); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); const { useNativeCurrencyAsPrimaryCurrency } = useSelector(getPreferences); + const nativeCurrency = useSelector(getNativeCurrency); const unapprovedTxs = useSelector(getUnapprovedTransactions); const { transactionData } = useDraftTransactionGasValues(); const txData = useSelector((state) => txDataSelector(state)); @@ -45,6 +50,38 @@ const ConfirmLegacyGasDisplay = () => { (state) => transactionFeeSelector(state, transaction), ); + if (isMultiLayerFeeNetwork) { + return [ + + } + detailText={ + + } + noBold + flexWidthValues + />, + , + ]; + } + return ( { - const store = configureStore({ - ...mockState, - ...contextProps, - metamask: { - ...mockState.metamask, - accounts: { - [mockState.metamask.selectedAddress]: { - address: mockState.metamask.selectedAddress, - balance: '0x1F4', - }, - }, - unapprovedTxs: { - 8393540981007587: { - ...mockState.metamask.unapprovedTxs[8393540981007587], - txParams: { - from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', - value: '0x0', - gas: '0x5208', - gasPrice: '0x3b9aca00', - type: '0x0', - }, - }, - }, - preferences: { - useNativeCurrencyAsPrimaryCurrency: true, +const mmState = { + ...mockState, + metamask: { + ...mockState.metamask, + accounts: { + [mockState.metamask.selectedAddress]: { + address: mockState.metamask.selectedAddress, + balance: '0x1F4', }, }, - confirmTransaction: { - txData: { - id: 8393540981007587, - status: 'unapproved', - chainId: '0x5', + unapprovedTxs: { + 8393540981007587: { + ...mockState.metamask.unapprovedTxs[8393540981007587], txParams: { from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', @@ -51,7 +31,29 @@ const render = ({ contextProps } = {}) => { }, }, }, - }); + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + }, + confirmTransaction: { + txData: { + id: 8393540981007587, + status: 'unapproved', + chainId: '0x5', + txParams: { + from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + value: '0x0', + gas: '0x5208', + gasPrice: '0x3b9aca00', + type: '0x0', + }, + }, + }, +}; + +const render = ({ contextProps, state = mmState } = {}) => { + const store = configureStore({ ...state, ...contextProps }); return renderWithProvider(, store); }; @@ -107,4 +109,48 @@ describe('ConfirmLegacyGasDisplay', () => { expect(screen.queryAllByTitle('0.000021 ETH').length).toBeGreaterThan(0); }); }); + + it('should contain L1 L2 fee details for optimism', async () => { + mmState.metamask.provider.chainId = CHAIN_IDS.OPTIMISM; + mmState.confirmTransaction.txData.chainId = CHAIN_IDS.OPTIMISM; + const state = { + metamask: { + ...mmState.metamask, + provider: { + ...mmState.metamask.provider, + chainId: CHAIN_IDS.OPTIMISM, + }, + }, + confirmTransaction: { + ...mmState.confirmTransaction, + txData: { + ...mmState.confirmTransaction.txData, + chainId: CHAIN_IDS.OPTIMISM, + }, + }, + }; + render( + { + send: { + currentTransactionUUID: '1d40b578-6184-4607-8513-762c24d0a19b', + draftTransactions: { + '1d40b578-6184-4607-8513-762c24d0a19b': { + gas: { + error: null, + gasLimit: '0x5208', + gasPrice: '0x3b9aca00', + gasTotal: '0x157c9fbb9a000', + wasManuallyEdited: false, + }, + }, + }, + }, + }, + state, + ); + await waitFor(() => { + expect(screen.queryByText('Layer 1 fees')).toBeInTheDocument(); + expect(screen.queryByText('Layer 2 gas fee')).toBeInTheDocument(); + }); + }); }); diff --git a/ui/components/app/multilayer-fee-message/__snapshots__/multi-layer-fee-message.test.js.snap b/ui/components/app/multilayer-fee-message/__snapshots__/multi-layer-fee-message.test.js.snap new file mode 100644 index 000000000..523ee6cdb --- /dev/null +++ b/ui/components/app/multilayer-fee-message/__snapshots__/multi-layer-fee-message.test.js.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Multi layer fee message should match snapshot 1`] = ` +
+
+
+
+
+ Layer 1 fees +
+
+
+ Unknown +
+
+ Unknown +
+
+
+
+
+
+
+
+
+
+
+ Total +
+
+
+
+ + + $0.56 + +
+
+
+ 0.001000021000 ETH +
+
+
+
+
+ Amount + fees +
+
+
+
+
+
+`; diff --git a/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js b/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js index 60eb8c3c3..d14507215 100644 --- a/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js +++ b/ui/components/app/multilayer-fee-message/multi-layer-fee-message.js @@ -17,36 +17,17 @@ export default function MultilayerFeeMessage({ plainStyle, }) { const t = useContext(I18nContext); - const [fetchedLayer1Total, setLayer1Total] = useState(null); - let layer1Total = 'unknown'; - let layer1TotalBN; - - if (fetchedLayer1Total !== null) { - layer1TotalBN = new Numeric(fetchedLayer1Total, 16, EtherDenomination.WEI); - layer1Total = `${layer1TotalBN - .toDenomination(EtherDenomination.ETH) - .toFixed(12)} ${nativeCurrency}`; - } - - const feeTotal = sumHexes(layer2fee || '0x0', fetchedLayer1Total || '0x0'); - - const totalInWeiHex = sumHexes( - feeTotal || '0x0', - transaction.txParams.value || '0x0', - ); - - const totalBN = new Numeric(totalInWeiHex, 16, EtherDenomination.WEI); - const totalInEth = `${totalBN - .toDenomination(EtherDenomination.ETH) - .toFixed(12)} ${nativeCurrency}`; useEffect(() => { + if (!transaction?.txParams) { + return; + } const getEstimatedL1Fee = async () => { try { const result = await fetchEstimatedL1Fee( - transaction.chainId, - transaction.txParams, + transaction?.chainId, + transaction, ); setLayer1Total(result); } catch (e) { @@ -57,15 +38,44 @@ export default function MultilayerFeeMessage({ getEstimatedL1Fee(); }, [transaction]); - const feeTotalInFiat = ( - + if (!transaction?.txParams) { + return null; + } + + let layer1Total = t('unknown'); + let feeTotalInFiat = t('unknown'); + + if (fetchedLayer1Total !== null) { + const layer1TotalBN = new Numeric( + fetchedLayer1Total, + 16, + EtherDenomination.WEI, + ); + layer1Total = `${layer1TotalBN + .toDenomination(EtherDenomination.ETH) + .toFixed(12)} ${nativeCurrency}`; + + feeTotalInFiat = ( + + ); + } + + const totalInWeiHex = sumHexes( + layer2fee || '0x0', + fetchedLayer1Total || '0x0', + transaction?.txParams?.value || '0x0', ); + const totalBN = new Numeric(totalInWeiHex, 16, EtherDenomination.WEI); + const totalInEth = `${totalBN + .toDenomination(EtherDenomination.ETH) + .toFixed(12)} ${nativeCurrency}`; + const totalInFiat = ( '0x5'); + +describe('Multi layer fee message', () => { + const store = configureStore(mockState); + + it('should match snapshot', () => { + const { container } = renderWithProvider( + , + store, + ); + expect(container).toMatchSnapshot(); + }); + + it('should containe fee values', () => { + const { getByText } = renderWithProvider( + , + store, + ); + expect(getByText('Layer 1 fees')).toBeInTheDocument(); + expect(getByText('Amount + fees')).toBeInTheDocument(); + expect(getByText('0.001000021000 ETH')).toBeInTheDocument(); + }); +}); diff --git a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js index a3586aa32..b9046209d 100644 --- a/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js +++ b/ui/pages/confirm-approve/confirm-approve-content/confirm-approve-content.component.js @@ -33,6 +33,9 @@ import { IconName, Text, } from '../../../components/component-library'; +import TransactionDetailItem from '../../../components/app/transaction-detail-item/transaction-detail-item.component'; +import UserPreferencedCurrencyDisplay from '../../../components/app/user-preferenced-currency-display'; +import { PRIMARY, SECONDARY } from '../../../helpers/constants/common'; import { ConfirmGasDisplay } from '../../../components/app/confirm-gas-display'; export default class ConfirmApproveContent extends Component { @@ -65,6 +68,7 @@ export default class ConfirmApproveContent extends Component { rpcPrefs: PropTypes.object, isContract: PropTypes.bool, hexTransactionTotal: PropTypes.string, + hexMinimumTransactionFee: PropTypes.string, isMultiLayerFeeNetwork: PropTypes.bool, supportsEIP1559: PropTypes.bool, assetName: PropTypes.string, @@ -77,6 +81,7 @@ export default class ConfirmApproveContent extends Component { setUserAcknowledgedGasMissing: PropTypes.func, renderSimulationFailureWarning: PropTypes.bool, useCurrencyRateCheck: PropTypes.bool, + useNativeCurrencyAsPrimaryCurrency: PropTypes.bool, }; state = { @@ -157,12 +162,14 @@ export default class ConfirmApproveContent extends Component { ethTransactionTotal, fiatTransactionTotal, hexTransactionTotal, + hexMinimumTransactionFee, txData, isMultiLayerFeeNetwork, supportsEIP1559, userAcknowledgedGasMissing, renderSimulationFailureWarning, useCurrencyRateCheck, + useNativeCurrencyAsPrimaryCurrency, } = this.props; if ( !isMultiLayerFeeNetwork && @@ -179,10 +186,27 @@ export default class ConfirmApproveContent extends Component {
{isMultiLayerFeeNetwork ? (
-
- {t('transactionDetailLayer2GasHeading')} - {`${ethTransactionTotal} ${nativeCurrency}`} -
+ + } + detailText={ + + } + noBold + flexWidthValues + /> {showCustomizeGasPopover && !supportsEIP1559 && ( this.handleEditGas() + renderSimulationFailureWarning ? null : () => this.handleEditGas() } rows={[ renderSimulationFailureWarning && simulationFailureWarning(), - !renderSimulationFailureWarning && !isMultiLayerFeeNetwork && ( + !renderSimulationFailureWarning && ( ), - !renderSimulationFailureWarning && isMultiLayerFeeNetwork && ( - - ), !isMultiLayerFeeNetwork && ( { const { hexTransactionAmount, - hexMinimumTransactionFee, hexMaximumTransactionFee, hexTransactionTotal, gasEstimationObject, @@ -206,7 +205,6 @@ const mapStateToProps = (state, ownProps) => { toName, toNickname, hexTransactionAmount, - hexMinimumTransactionFee, hexMaximumTransactionFee, hexTransactionTotal, txData: fullTxData, diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js index ae33ad632..30d699486 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.test.js @@ -146,12 +146,24 @@ const baseStore = { }; describe('Confirm Transaction Base', () => { - const store = configureMockStore(middleware)(baseStore); it('should match snapshot', () => { + const store = configureMockStore(middleware)(baseStore); const { container } = renderWithProvider( , store, ); expect(container).toMatchSnapshot(); }); + + it('should contain L1 L2 fee details for optimism', () => { + baseStore.metamask.provider.chainId = CHAIN_IDS.OPTIMISM; + baseStore.confirmTransaction.txData.chainId = CHAIN_IDS.OPTIMISM; + const store = configureMockStore(middleware)(baseStore); + const { getByText } = renderWithProvider( + , + store, + ); + expect(getByText('Layer 1 fees')).toBeInTheDocument(); + expect(getByText('Layer 2 gas fee')).toBeInTheDocument(); + }); }); diff --git a/ui/pages/confirm-transaction/confirm-token-transaction-switch.js b/ui/pages/confirm-transaction/confirm-token-transaction-switch.js index 8b0bd17e1..e04b7c404 100644 --- a/ui/pages/confirm-transaction/confirm-token-transaction-switch.js +++ b/ui/pages/confirm-transaction/confirm-token-transaction-switch.js @@ -46,6 +46,7 @@ export default function ConfirmTokenTransactionSwitch({ transaction }) { fiatTransactionTotal, hexTransactionTotal, hexMaximumTransactionFee, + hexMinimumTransactionFee, } = useSelector((state) => transactionFeeSelector(state, transaction)); return ( @@ -70,6 +71,7 @@ export default function ConfirmTokenTransactionSwitch({ transaction }) { ethTransactionTotal={ethTransactionTotal} fiatTransactionTotal={fiatTransactionTotal} hexTransactionTotal={hexTransactionTotal} + hexMinimumTransactionFee={hexMinimumTransactionFee} /> )} /> @@ -94,6 +96,7 @@ export default function ConfirmTokenTransactionSwitch({ transaction }) { ethTransactionTotal={ethTransactionTotal} fiatTransactionTotal={fiatTransactionTotal} hexTransactionTotal={hexTransactionTotal} + hexMinimumTransactionFee={hexMinimumTransactionFee} /> )} /> diff --git a/ui/pages/send/send-content/send-content.component.js b/ui/pages/send/send-content/send-content.component.js index b57b59a51..d358a6c87 100644 --- a/ui/pages/send/send-content/send-content.component.js +++ b/ui/pages/send/send-content/send-content.component.js @@ -34,6 +34,7 @@ export default class SendContent extends Component { recipient: PropTypes.object, acknowledgeRecipientWarning: PropTypes.func, recipientWarningAcknowledged: PropTypes.bool, + isMultiLayerFeeNetwork: PropTypes.bool, }; render() { @@ -48,6 +49,7 @@ export default class SendContent extends Component { assetError, recipient, recipientWarningAcknowledged, + isMultiLayerFeeNetwork, } = this.props; let gasError; @@ -80,7 +82,7 @@ export default class SendContent extends Component { {networkOrAccountNotSupports1559 ? : null} {showHexData ? : null} - + {!isMultiLayerFeeNetwork && }
); diff --git a/ui/pages/send/send-content/send-content.container.js b/ui/pages/send/send-content/send-content.container.js index e9d3f6f02..6bf19dea3 100644 --- a/ui/pages/send/send-content/send-content.container.js +++ b/ui/pages/send/send-content/send-content.container.js @@ -3,6 +3,7 @@ import { getIsEthGasPriceFetched, getNoGasPriceFetched, checkNetworkOrAccountNotSupports1559, + getIsMultiLayerFeeNetwork, } from '../../../selectors'; import { getIsBalanceInsufficient, @@ -29,6 +30,7 @@ function mapStateToProps(state) { assetError: getAssetError(state), recipient, recipientWarningAcknowledged, + isMultiLayerFeeNetwork: getIsMultiLayerFeeNetwork(state), }; } diff --git a/ui/pages/token-allowance/token-allowance.js b/ui/pages/token-allowance/token-allowance.js index 9fe4244ef..57453a838 100644 --- a/ui/pages/token-allowance/token-allowance.js +++ b/ui/pages/token-allowance/token-allowance.js @@ -78,6 +78,7 @@ export default function TokenAllowance({ ethTransactionTotal, fiatTransactionTotal, hexTransactionTotal, + hexMinimumTransactionFee, txData, isMultiLayerFeeNetwork, supportsEIP1559, @@ -460,6 +461,7 @@ export default function TokenAllowance({ userAcknowledgedGasMissing={userAcknowledgedGasMissing} renderSimulationFailureWarning={renderSimulationFailureWarning} hexTransactionTotal={hexTransactionTotal} + hexMinimumTransactionFee={hexMinimumTransactionFee} fiatTransactionTotal={fiatTransactionTotal} currentCurrency={currentCurrency} useCurrencyRateCheck={useCurrencyRateCheck} @@ -511,6 +513,7 @@ export default function TokenAllowance({ isApprovalOrRejection={isApprovalOrRejection} data={customTxParamsData || data} useCurrencyRateCheck={useCurrencyRateCheck} + hexMinimumTransactionFee={hexMinimumTransactionFee} /> @@ -592,6 +595,10 @@ TokenAllowance.propTypes = { * Total sum of the transaction converted to hex value */ hexTransactionTotal: PropTypes.string, + /** + * Minimum transaction fee converted to hex value + */ + hexMinimumTransactionFee: PropTypes.string, /** * Current transaction */ diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 13a198bac..538fa7f35 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -843,7 +843,7 @@ export const getFullTxData = createDeepEqualSelector( (txData, transaction, customTxParamsData) => { let fullTxData = { ...txData, ...transaction }; if (transaction && transaction.simulationFails) { - txData.simulationFails = transaction.simulationFails; + fullTxData.simulationFails = { ...transaction.simulationFails }; } if (customTxParamsData) { fullTxData = { @@ -1222,10 +1222,6 @@ export function getIsOptimism(state) { ); } -export function getNetworkSupportsSettingGasFees(state) { - return !getIsOptimism(state); -} - export function getIsMultiLayerFeeNetwork(state) { return getIsOptimism(state); } From 086b7dade5f024b52cb36fab72fcc08d0a30946f Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 26 Apr 2023 08:33:36 +0200 Subject: [PATCH 40/60] Improve logging at build-time (#18780) * Improve logging at build-time * Fix lint --- development/build/scripts.js | 5 +++++ development/build/task.js | 9 +++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/development/build/scripts.js b/development/build/scripts.js index 2ac455878..a462a14d8 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -1110,6 +1110,11 @@ async function createBundle(buildConfiguration, { reloadOnChange }) { logError(error); process.exit(1); }); + pipeline.on('error', (error) => { + console.error('Pipeline failed! See details below.'); + logError(error); + process.exit(1); + }); } // trigger build pipeline instrumentations events.emit('configurePipeline', { pipeline, bundleStream }); diff --git a/development/build/task.js b/development/build/task.js index 328f65e64..1b28a15f6 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -80,12 +80,9 @@ function runInChildProcess( ); // forward logs to main process - // skip the first stdout event (announcing the process command) - childProcess.stdout.once('data', () => { - childProcess.stdout.on('data', (data) => - process.stdout.write(`${taskName}: ${data}`), - ); - }); + childProcess.stdout.on('data', (data) => + process.stdout.write(`${taskName}: ${data}`), + ); childProcess.stderr.on('data', (data) => process.stderr.write(`${taskName}: ${data}`), From ef01dc1391612aee26f2cc8bf134c85154864442 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Wed, 26 Apr 2023 11:14:33 +0000 Subject: [PATCH 41/60] Unbreak CI checks (#18813) * Fix builds from forks * bump coverage targets --------- Co-authored-by: Frederik Bolding --- coverage-targets.js | 8 ++++---- development/build/scripts.js | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/coverage-targets.js b/coverage-targets.js index c78857661..b472d5fdc 100644 --- a/coverage-targets.js +++ b/coverage-targets.js @@ -6,10 +6,10 @@ // subset of files to check against these targets. module.exports = { global: { - lines: 69.3, - branches: 57, - statements: 68.5, - functions: 61.5, + lines: 69.92, + branches: 57.63, + statements: 69.24, + functions: 62.51, }, transforms: { branches: 100, diff --git a/development/build/scripts.js b/development/build/scripts.js index a462a14d8..a598e83a9 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -110,10 +110,18 @@ const standardScuttlingConfig = { * @returns {string} The Infura project ID. */ function getInfuraProjectId({ buildType, variables, environment, testing }) { + const EMPTY_PROJECT_ID = '00000000000000000000000000000000'; if (testing) { - return '00000000000000000000000000000000'; + return EMPTY_PROJECT_ID; } else if (environment !== ENVIRONMENT.PRODUCTION) { // Skip validation because this is unset on PRs from forks. + // For forks, return empty project ID if we don't have one. + if ( + !variables.isDefined('INFURA_PROJECT_ID') && + environment === ENVIRONMENT.PULL_REQUEST + ) { + return EMPTY_PROJECT_ID; + } return variables.get('INFURA_PROJECT_ID'); } /** @type {string|undefined} */ From bc3baaed3192128f1e22bc0e852b038adc743d10 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Wed, 26 Apr 2023 12:13:59 +0000 Subject: [PATCH 42/60] deps: bump json5, loader-utils, minimist (#18733) * deps: json5@1.0.1->1.0.2; minimist@1.2.7->1.2.8 - CVE-2022-46175 / GHSA-9c47-m6qq-7p4h * deps: loader-utils@1.4.0->1.4.2 - CVE-2022-37599 / GHSA-hhq3-ff78-jv3g - CVE-2022-37603 / GHSA-3rfm-jhwj-7488 - CVE-2022-37601 / GHSA-76p3-8jx3-jpfq --- yarn.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7eb218304..56e38c69d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7556,9 +7556,9 @@ __metadata: linkType: hard "@types/minimist@npm:^1.2.0": - version: 1.2.0 - resolution: "@types/minimist@npm:1.2.0" - checksum: 30cbd9acd7ddb60bc3729adcc43a9da4940c90180fa0f08228f1da95ec6c00db2e3fd3af5280fc5345e3fa2637253bb5cf6625f30d571ef9bc3820a531febb7e + version: 1.2.2 + resolution: "@types/minimist@npm:1.2.2" + checksum: b8da83c66eb4aac0440e64674b19564d9d86c80ae273144db9681e5eeff66f238ade9515f5006ffbfa955ceff8b89ad2bd8ec577d7caee74ba101431fb07045d languageName: node linkType: hard @@ -22297,13 +22297,13 @@ __metadata: linkType: hard "json5@npm:^1.0.1": - version: 1.0.1 - resolution: "json5@npm:1.0.1" + version: 1.0.2 + resolution: "json5@npm:1.0.2" dependencies: minimist: ^1.2.0 bin: json5: lib/cli.js - checksum: e76ea23dbb8fc1348c143da628134a98adf4c5a4e8ea2adaa74a80c455fc2cdf0e2e13e6398ef819bfe92306b610ebb2002668ed9fc1af386d593691ef346fc3 + checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 languageName: node linkType: hard @@ -23131,13 +23131,13 @@ __metadata: linkType: hard "loader-utils@npm:^1.1.0, loader-utils@npm:^1.2.3": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" + version: 1.4.2 + resolution: "loader-utils@npm:1.4.2" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 + checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 languageName: node linkType: hard @@ -24623,9 +24623,9 @@ __metadata: linkType: hard "minimist@npm:^1.1.0, minimist@npm:^1.1.1, minimist@npm:^1.1.3, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.7": - version: 1.2.7 - resolution: "minimist@npm:1.2.7" - checksum: 7346574a1038ca23c32e02252f603801f09384dd1d78b69a943a4e8c2c28730b80e96193882d3d3b22a063445f460e48316b29b8a25addca2d7e5e8f75478bec + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 languageName: node linkType: hard From 15d64b64675e0ee1255de2c30c5c35f4e01e53dd Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 26 Apr 2023 08:18:48 -0500 Subject: [PATCH 43/60] UX: Multichain: Focus on account search when menu appears (#18705) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- .../account-list-menu/account-list-menu.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ui/components/multichain/account-list-menu/account-list-menu.js b/ui/components/multichain/account-list-menu/account-list-menu.js index aea2e81c6..2e867fa91 100644 --- a/ui/components/multichain/account-list-menu/account-list-menu.js +++ b/ui/components/multichain/account-list-menu/account-list-menu.js @@ -1,4 +1,4 @@ -import React, { useState, useContext } from 'react'; +import React, { useState, useContext, useRef, useEffect } from 'react'; import PropTypes from 'prop-types'; import { useHistory } from 'react-router-dom'; import Fuse from 'fuse.js'; @@ -45,6 +45,7 @@ export const AccountListMenu = ({ onClose }) => { const currentTabOrigin = useSelector(getOriginOfCurrentTab); const history = useHistory(); const dispatch = useDispatch(); + const inputRef = useRef(); const [searchQuery, setSearchQuery] = useState(''); @@ -62,8 +63,20 @@ export const AccountListMenu = ({ onClose }) => { searchResults = fuse.search(searchQuery); } + // Focus on the search box when the popover is opened + useEffect(() => { + if (inputRef.current) { + inputRef.current.rootNode.querySelector('input[type=search]').focus(); + } + }, [inputRef]); + return ( - + {/* Search box */} From 062a8b376f706914f00b98fee93a8b62a2d6d206 Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 26 Apr 2023 08:22:18 -0500 Subject: [PATCH 44/60] UX: Multichain: Fix Network Picker when Test Networks Disabled (#18694) --- .../network-list-menu/network-list-menu.js | 4 +- ui/selectors/selectors.js | 66 +++++++++++-------- ui/selectors/selectors.test.js | 50 +++++++------- 3 files changed, 63 insertions(+), 57 deletions(-) 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 64a84f9da..ef0f873fe 100644 --- a/ui/components/multichain/network-list-menu/network-list-menu.js +++ b/ui/components/multichain/network-list-menu/network-list-menu.js @@ -15,7 +15,7 @@ import { import { CHAIN_IDS, TEST_CHAINS } from '../../../../shared/constants/network'; import { getShowTestNetworks, - getAllNetworks, + getAllEnabledNetworks, getCurrentChainId, } from '../../../selectors'; import Box from '../../ui/box/box'; @@ -33,7 +33,7 @@ const UNREMOVABLE_CHAIN_IDS = [CHAIN_IDS.MAINNET, ...TEST_CHAINS]; export const NetworkListMenu = ({ onClose }) => { const t = useI18nContext(); - const networks = useSelector(getAllNetworks); + const networks = useSelector(getAllEnabledNetworks); const showTestNetworks = useSelector(getShowTestNetworks); const currentChainId = useSelector(getCurrentChainId); const dispatch = useDispatch(); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 538fa7f35..41f7b6da7 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -1158,9 +1158,19 @@ export function getCurrentNetwork(state) { return allNetworks.find((network) => network.chainId === currentChainId); } +export function getAllEnabledNetworks(state) { + const allNetworks = getAllNetworks(state); + const showTestnetNetworks = getShowTestNetworks(state); + + return showTestnetNetworks + ? allNetworks + : allNetworks.filter( + (network) => TEST_CHAINS.includes(network.chainId) === false, + ); +} + export function getAllNetworks(state) { const networkConfigurations = getNetworkConfigurations(state) || {}; - const showTestnetNetworks = getShowTestNetworks(state); const localhostFilter = (network) => network.chainId === CHAIN_IDS.LOCALHOST; const networks = []; @@ -1183,34 +1193,32 @@ export function getAllNetworks(state) { ) .map(([, network]) => network), ); - // Test networks if flag is on - if (showTestnetNetworks) { - networks.push( - ...[ - { - chainId: CHAIN_IDS.GOERLI, - nickname: GOERLI_DISPLAY_NAME, - rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.GOERLI], - providerType: NETWORK_TYPES.GOERLI, - }, - { - chainId: CHAIN_IDS.SEPOLIA, - nickname: SEPOLIA_DISPLAY_NAME, - rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.SEPOLIA], - providerType: NETWORK_TYPES.SEPOLIA, - }, - { - chainId: CHAIN_IDS.LINEA_TESTNET, - nickname: LINEA_TESTNET_DISPLAY_NAME, - rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_TESTNET], - provderType: NETWORK_TYPES.LINEA_TESTNET, - }, - ], // Localhosts - ...Object.entries(networkConfigurations) - .filter(([, network]) => localhostFilter(network)) - .map(([, network]) => network), - ); - } + // Test networks + networks.push( + ...[ + { + chainId: CHAIN_IDS.GOERLI, + nickname: GOERLI_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.GOERLI], + providerType: NETWORK_TYPES.GOERLI, + }, + { + chainId: CHAIN_IDS.SEPOLIA, + nickname: SEPOLIA_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.SEPOLIA], + providerType: NETWORK_TYPES.SEPOLIA, + }, + { + chainId: CHAIN_IDS.LINEA_TESTNET, + nickname: LINEA_TESTNET_DISPLAY_NAME, + rpcUrl: CHAIN_ID_TO_RPC_URL_MAP[CHAIN_IDS.LINEA_TESTNET], + provderType: NETWORK_TYPES.LINEA_TESTNET, + }, + ], // Localhosts + ...Object.entries(networkConfigurations) + .filter(([, network]) => localhostFilter(network)) + .map(([, network]) => network), + ); return networks; } diff --git a/ui/selectors/selectors.test.js b/ui/selectors/selectors.test.js index af59b8931..a16bec7ec 100644 --- a/ui/selectors/selectors.test.js +++ b/ui/selectors/selectors.test.js @@ -3,7 +3,6 @@ import { KeyringType } from '../../shared/constants/keyring'; import { CHAIN_IDS, LOCALHOST_DISPLAY_NAME, - MAINNET_DISPLAY_NAME, } from '../../shared/constants/network'; import * as selectors from './selectors'; @@ -109,31 +108,6 @@ describe('Selectors', () => { }); describe('#getAllNetworks', () => { - it('returns an array even if there are no custom networks', () => { - const networks = selectors.getAllNetworks({ - metamask: { - preferences: { - showTestNetworks: false, - }, - }, - }); - expect(networks instanceof Array).toBe(true); - // The only returning item should be Ethereum Mainnet - expect(networks).toHaveLength(1); - expect(networks[0].nickname).toStrictEqual(MAINNET_DISPLAY_NAME); - }); - - it('returns more test networks with showTestNetworks on', () => { - const networks = selectors.getAllNetworks({ - metamask: { - preferences: { - showTestNetworks: true, - }, - }, - }); - expect(networks.length).toBeGreaterThan(1); - }); - it('sorts Localhost to the bottom of the test lists', () => { const networks = selectors.getAllNetworks({ metamask: { @@ -153,6 +127,30 @@ describe('Selectors', () => { }); }); + describe('#getAllEnabledNetworks', () => { + it('returns only MainNet with showTestNetworks off', () => { + const networks = selectors.getAllEnabledNetworks({ + metamask: { + preferences: { + showTestNetworks: false, + }, + }, + }); + expect(networks).toHaveLength(1); + }); + + it('returns networks with showTestNetworks on', () => { + const networks = selectors.getAllEnabledNetworks({ + metamask: { + preferences: { + showTestNetworks: true, + }, + }, + }); + expect(networks.length).toBeGreaterThan(1); + }); + }); + describe('#isHardwareWallet', () => { it('returns false if it is not a HW wallet', () => { mockState.metamask.keyrings[0].type = KeyringType.imported; From 755b6b5667a164798d1bfbcbbadcc930d34db37b Mon Sep 17 00:00:00 2001 From: David Walsh Date: Wed, 26 Apr 2023 08:35:28 -0500 Subject: [PATCH 45/60] UX: Remove Goerli buy link and disable button (#18137) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- shared/constants/network.ts | 5 +---- ui/hooks/experiences/useRamps.test.js | 18 ------------------ ui/hooks/experiences/useRamps.ts | 2 -- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/shared/constants/network.ts b/shared/constants/network.ts index 5227efe2e..bd3bec0fa 100644 --- a/shared/constants/network.ts +++ b/shared/constants/network.ts @@ -540,16 +540,13 @@ export const BUYABLE_CHAINS_MAP: { | typeof CHAIN_IDS.MOONRIVER | typeof CHAIN_IDS.AURORA | typeof CHAIN_IDS.LINEA_TESTNET + | typeof CHAIN_IDS.GOERLI >]: BuyableChainSettings; } = { [CHAIN_IDS.MAINNET]: { nativeCurrency: CURRENCY_SYMBOLS.ETH, network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME, }, - [CHAIN_IDS.GOERLI]: { - nativeCurrency: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.GOERLI], - network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME, - }, [CHAIN_IDS.SEPOLIA]: { nativeCurrency: TEST_NETWORK_TICKER_MAP[NETWORK_TYPES.SEPOLIA], network: BUYABLE_CHAIN_ETHEREUM_NETWORK_NAME, diff --git a/ui/hooks/experiences/useRamps.test.js b/ui/hooks/experiences/useRamps.test.js index f104094e8..5f23a4e3b 100644 --- a/ui/hooks/experiences/useRamps.test.js +++ b/ui/hooks/experiences/useRamps.test.js @@ -26,24 +26,6 @@ describe('useRamps', () => { }); }); - it('should open the buy crypto URL for GOERLI chain ID', () => { - const mockChainId = '5'; - const mockBuyURI = 'https://goerli-faucet.slock.it/'; - - useSelector.mockReturnValue(mockChainId); - const openTabSpy = jest.spyOn(global.platform, 'openTab'); - - const { result } = renderHook(() => useRamps()); - - expect(typeof result.current.openBuyCryptoInPdapp).toBe('function'); - - result.current.openBuyCryptoInPdapp(); - - expect(openTabSpy).toHaveBeenCalledWith({ - url: mockBuyURI, - }); - }); - it('should open the buy crypto URL for SEPOLIA chain ID', () => { const mockChainId = '10'; const mockBuyURI = 'https://faucet.sepolia.dev/'; diff --git a/ui/hooks/experiences/useRamps.ts b/ui/hooks/experiences/useRamps.ts index 3b8947486..93ea6d47b 100644 --- a/ui/hooks/experiences/useRamps.ts +++ b/ui/hooks/experiences/useRamps.ts @@ -15,8 +15,6 @@ const useRamps = (): IUseRamps => { const getBuyURI = useCallback((_chainId: ChainId) => { switch (_chainId) { - case CHAIN_IDS.GOERLI: - return 'https://goerli-faucet.slock.it/'; case CHAIN_IDS.SEPOLIA: return 'https://faucet.sepolia.dev/'; default: From 660ae4c156aeba09da25f8fb54ec5cf3364384d3 Mon Sep 17 00:00:00 2001 From: Dan J Miller Date: Wed, 26 Apr 2023 12:26:33 -0230 Subject: [PATCH 46/60] Fix mv3 beta build (#18690) * Build beta with mv3 enabled * Ensure firefox manifest is an mv2 version * Revert "Ensure firefox manifest is an mv2 version" This reverts commit fed74792b0fec33c3a85f2229eb560559d37afe5. * Only create beta builds for the chrome platform * Stop linting firefox for beta --- .circleci/config.yml | 17 ---------------- .circleci/scripts/mozilla-lint-beta.sh | 27 ------------------------- .circleci/scripts/trigger-beta-build.sh | 5 +++-- development/build/index.js | 12 ++++++++++- 4 files changed, 14 insertions(+), 47 deletions(-) delete mode 100755 .circleci/scripts/mozilla-lint-beta.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 68a1c199a..467aabc59 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -143,11 +143,6 @@ workflows: requires: - prep-deps - prep-build - - test-mozilla-lint-beta: - <<: *rc_branch_only - requires: - - prep-deps - - trigger-beta-build - test-mozilla-lint-desktop: filters: branches: @@ -176,7 +171,6 @@ workflows: - validate-source-maps-desktop - validate-source-maps-flask - test-mozilla-lint - - test-mozilla-lint-beta - test-mozilla-lint-desktop - test-mozilla-lint-flask - test-e2e-chrome @@ -1144,17 +1138,6 @@ jobs: name: test:mozilla-lint command: NODE_OPTIONS=--max_old_space_size=3072 yarn mozilla-lint - test-mozilla-lint-beta: - executor: node-browsers - steps: - - checkout - - attach_workspace: - at: . - - run: - name: Lint beta for firefox - command: | - .circleci/scripts/mozilla-lint-beta.sh - test-mozilla-lint-desktop: executor: node-browsers steps: diff --git a/.circleci/scripts/mozilla-lint-beta.sh b/.circleci/scripts/mozilla-lint-beta.sh deleted file mode 100755 index 1096526b7..000000000 --- a/.circleci/scripts/mozilla-lint-beta.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -set -e -set -u -set -o pipefail - -current_commit_msg=$(git show -s --format='%s' HEAD) - -if [[ $current_commit_msg =~ Version[[:space:]](v[[:digit:]]+.[[:digit:]]+.[[:digit:]]+[-]beta.[[:digit:]]) ]] -then - # filter the commit message like Version v10.24.1-beta.1 - printf '%s\n' "Linting beta builds for firefox" - # Move beta build to dist - mv ./dist-beta ./dist - # Move beta zips to builds - mv ./builds-beta ./builds - # test:mozilla-lint - export NODE_OPTIONS='--max_old_space_size=3072' - yarn mozilla-lint -else - printf '%s\n' 'Commit message does not match commit message for beta pattern; skipping linting for firefox' - mkdir dist - mkdir builds - exit 0 -fi - -exit 0 diff --git a/.circleci/scripts/trigger-beta-build.sh b/.circleci/scripts/trigger-beta-build.sh index 77cc8f1c8..34801a476 100755 --- a/.circleci/scripts/trigger-beta-build.sh +++ b/.circleci/scripts/trigger-beta-build.sh @@ -12,8 +12,9 @@ if [[ $current_commit_msg =~ Version[[:space:]](v[[:digit:]]+.[[:digit:]]+.[[:di then # filter the commit message like Version v10.24.1-beta.1 printf '%s\n' "Create a build for $version with beta version $current_commit_msg" - yarn build --build-type beta dist - yarn build --build-type beta prod + export ENABLE_MV3=true + yarn build --build-type beta --platform='chrome' dist + yarn build --build-type beta --platform='chrome' prod else printf '%s\n' 'Commit message does not match commit message for beta pattern; skipping beta automation build' mkdir dist diff --git a/development/build/index.js b/development/build/index.js index 91d12815d..153da2de0 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -73,6 +73,7 @@ async function defineAndRunBuildTasks() { shouldLintFenceFiles, skipStats, version, + platform, } = await parseArgv(); const isRootTask = ['dist', 'prod', 'test', 'dev'].includes(entryTask); @@ -135,7 +136,7 @@ async function defineAndRunBuildTasks() { }); } - const browserPlatforms = ['firefox', 'chrome']; + const browserPlatforms = platform ? [platform] : ['firefox', 'chrome']; const browserVersionMap = getBrowserVersionMap(browserPlatforms, version); @@ -317,6 +318,13 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, hidden: true, type: 'boolean', }) + .option('platform', { + default: '', + description: + 'Specify a single browser platform to build for. Either `chrome` or `firefox`', + hidden: true, + type: 'string', + }) .check((args) => { if (!Number.isInteger(args.buildVersion)) { throw new Error( @@ -341,6 +349,7 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, policyOnly, skipStats, task, + platform, } = argv; // Manually default this to `false` for dev builds only. @@ -371,6 +380,7 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, shouldLintFenceFiles, skipStats, version, + platform, }; } From 6d0f3a0b26e49a7be9c2f1e3b02bf26d091e44ca Mon Sep 17 00:00:00 2001 From: OGPoyraz Date: Wed, 26 Apr 2023 17:02:33 +0200 Subject: [PATCH 47/60] Consume Decrypt Message Manager from @metamask/message-manager (#18379) --- app/scripts/background.js | 18 +- .../controllers/decrypt-message.test.ts | 222 ++++++++++ app/scripts/controllers/decrypt-message.ts | 394 ++++++++++++++++++ .../controllers/encryption-public-key.ts | 29 +- app/scripts/lib/decrypt-message-manager.js | 351 ---------------- app/scripts/metamask-controller.js | 133 ++---- .../files-to-convert.json | 1 - jest.config.js | 2 + package.json | 2 +- types/eth-keyring-controller.d.ts | 2 + .../confirm-decrypt-message.component.js | 2 +- ui/selectors/selectors.js | 9 +- yarn.lock | 20 +- 13 files changed, 684 insertions(+), 501 deletions(-) create mode 100644 app/scripts/controllers/decrypt-message.test.ts create mode 100644 app/scripts/controllers/decrypt-message.ts delete mode 100644 app/scripts/lib/decrypt-message-manager.js diff --git a/app/scripts/background.js b/app/scripts/background.js index dceea1b5e..cce8b1585 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -682,7 +682,7 @@ export function setupController( METAMASK_CONTROLLER_EVENTS.UPDATE_BADGE, updateBadge, ); - controller.decryptMessageManager.on( + controller.decryptMessageController.hub.on( METAMASK_CONTROLLER_EVENTS.UPDATE_BADGE, updateBadge, ); @@ -725,14 +725,11 @@ export function setupController( } function getUnapprovedTransactionCount() { - const { unapprovedDecryptMsgCount } = controller.decryptMessageManager; const pendingApprovalCount = controller.approvalController.getTotalApprovalCount(); const waitingForUnlockCount = controller.appStateController.waitingForUnlock.length; - return ( - unapprovedDecryptMsgCount + pendingApprovalCount + waitingForUnlockCount - ); + return pendingApprovalCount + waitingForUnlockCount; } notificationManager.on( @@ -753,14 +750,9 @@ export function setupController( controller.txController.txStateManager.setTxStatusRejected(txId), ); controller.signController.rejectUnapproved(REJECT_NOTIFICATION_CLOSE_SIG); - controller.decryptMessageManager.messages - .filter((msg) => msg.status === 'unapproved') - .forEach((tx) => - controller.decryptMessageManager.rejectMsg( - tx.id, - REJECT_NOTIFICATION_CLOSE, - ), - ); + controller.decryptMessageController.rejectUnapproved( + REJECT_NOTIFICATION_CLOSE, + ); controller.encryptionPublicKeyController.rejectUnapproved( REJECT_NOTIFICATION_CLOSE, ); diff --git a/app/scripts/controllers/decrypt-message.test.ts b/app/scripts/controllers/decrypt-message.test.ts new file mode 100644 index 000000000..032a15289 --- /dev/null +++ b/app/scripts/controllers/decrypt-message.test.ts @@ -0,0 +1,222 @@ +import { DecryptMessageManager } from '@metamask/message-manager'; +import { AbstractMessage } from '@metamask/message-manager/dist/AbstractMessageManager'; +import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics'; +import DecryptMessageController, { + DecryptMessageControllerMessenger, + DecryptMessageControllerOptions, + getDefaultState, +} from './decrypt-message'; + +const messageIdMock = '12345'; +const messageMock = { + metamaskId: messageIdMock, + time: 123, + status: 'unapproved', + type: 'testType', + rawSig: undefined, +} as any as AbstractMessage; + +const mockExtState = {}; + +jest.mock('@metamask/message-manager', () => ({ + DecryptMessageManager: jest.fn(), +})); + +const createKeyringControllerMock = () => ({ + decryptMessage: jest.fn(), +}); + +const createMessengerMock = () => + ({ + registerActionHandler: jest.fn(), + publish: jest.fn(), + call: jest.fn(), + } as any as jest.Mocked); + +const createDecryptMessageManagerMock = () => + ({ + getUnapprovedMessages: jest.fn(), + getUnapprovedMessagesCount: jest.fn(), + getMessage: jest.fn(), + addUnapprovedMessageAsync: jest.fn(), + approveMessage: jest.fn(), + setMessageStatusAndResult: jest.fn(), + rejectMessage: jest.fn(), + update: jest.fn(), + subscribe: jest.fn(), + updateMessage: jest.fn(), + updateMessageErrorInline: jest.fn(), + setResult: jest.fn(), + hub: { + on: jest.fn(), + }, + } as any as jest.Mocked); + +describe('EncryptionPublicKeyController', () => { + let decryptMessageController: DecryptMessageController; + + const decryptMessageManagerConstructorMock = + DecryptMessageManager as jest.MockedClass; + const getStateMock = jest.fn(); + const keyringControllerMock = createKeyringControllerMock(); + const messengerMock = createMessengerMock(); + const metricsEventMock = jest.fn(); + + const decryptMessageManagerMock = + createDecryptMessageManagerMock(); + + beforeEach(() => { + jest.resetAllMocks(); + + decryptMessageManagerConstructorMock.mockReturnValue( + decryptMessageManagerMock, + ); + + decryptMessageController = new DecryptMessageController({ + getState: getStateMock as any, + keyringController: keyringControllerMock as any, + messenger: messengerMock as any, + metricsEvent: metricsEventMock as any, + } as DecryptMessageControllerOptions); + }); + + it('should return unapprovedMsgCount', () => { + decryptMessageManagerMock.getUnapprovedMessagesCount.mockReturnValue(5); + expect(decryptMessageController.unapprovedDecryptMsgCount).toBe(5); + }); + + it('should reset state', () => { + decryptMessageController.update(() => ({ + unapprovedDecryptMsgs: { + [messageIdMock]: messageMock, + } as any, + unapprovedDecryptMsgCount: 1, + })); + decryptMessageController.resetState(); + expect(decryptMessageController.state).toStrictEqual(getDefaultState()); + }); + + it('should clear unapproved messages', () => { + decryptMessageController.clearUnapproved(); + expect(decryptMessageController.state).toStrictEqual(getDefaultState()); + expect(decryptMessageManagerMock.update).toBeCalledTimes(1); + }); + it('should add unapproved messages', async () => { + await decryptMessageController.newRequestDecryptMessage(messageMock); + + expect(decryptMessageManagerMock.addUnapprovedMessageAsync).toBeCalledTimes( + 1, + ); + expect(decryptMessageManagerMock.addUnapprovedMessageAsync).toBeCalledWith( + messageMock, + undefined, + ); + }); + + it('should decrypt message', async () => { + const messageToDecrypt = { + ...messageMock, + data: '0x7b22666f6f223a22626172227d', + }; + decryptMessageManagerMock.approveMessage.mockResolvedValue( + messageToDecrypt, + ); + keyringControllerMock.decryptMessage.mockResolvedValue('decryptedMessage'); + getStateMock.mockReturnValue(mockExtState); + + const result = await decryptMessageController.decryptMessage( + messageToDecrypt, + ); + + expect(decryptMessageManagerMock.approveMessage).toBeCalledTimes(1); + expect(decryptMessageManagerMock.approveMessage).toBeCalledWith( + messageToDecrypt, + ); + expect(keyringControllerMock.decryptMessage).toBeCalledTimes(1); + expect(keyringControllerMock.decryptMessage).toBeCalledWith( + messageToDecrypt, + ); + expect(decryptMessageManagerMock.setMessageStatusAndResult).toBeCalledTimes( + 1, + ); + expect(decryptMessageManagerMock.setMessageStatusAndResult).toBeCalledWith( + messageIdMock, + 'decryptedMessage', + 'decrypted', + ); + expect(result).toBe(mockExtState); + }); + + it('should cancel decrypt request', async () => { + const messageToDecrypt = { + ...messageMock, + data: '0x7b22666f6f223a22626172227d', + }; + decryptMessageManagerMock.approveMessage.mockResolvedValue( + messageToDecrypt, + ); + keyringControllerMock.decryptMessage.mockRejectedValue(new Error('error')); + getStateMock.mockReturnValue(mockExtState); + + return expect( + decryptMessageController.decryptMessage(messageToDecrypt), + ).rejects.toThrow('error'); + }); + + it('should decrypt message inline', async () => { + const messageToDecrypt = { + ...messageMock, + data: '0x7b22666f6f223a22626172227d', + }; + decryptMessageManagerMock.getMessage.mockReturnValue(messageToDecrypt); + keyringControllerMock.decryptMessage.mockResolvedValue('decryptedMessage'); + getStateMock.mockReturnValue(mockExtState); + + const result = await decryptMessageController.decryptMessageInline( + messageToDecrypt, + ); + + expect(decryptMessageManagerMock.setResult).toBeCalledTimes(1); + expect(decryptMessageManagerMock.setResult).toBeCalledWith( + messageMock.metamaskId, + 'decryptedMessage', + ); + expect(result).toBe(mockExtState); + }); + + it('should be able to cancel decrypt message', async () => { + decryptMessageManagerMock.rejectMessage.mockResolvedValue(messageMock); + getStateMock.mockReturnValue(mockExtState); + + const result = await decryptMessageController.cancelDecryptMessage( + messageIdMock, + ); + + expect(decryptMessageManagerMock.rejectMessage).toBeCalledTimes(1); + expect(decryptMessageManagerMock.rejectMessage).toBeCalledWith( + messageIdMock, + ); + expect(result).toBe(mockExtState); + }); + + it('should be able to reject all unapproved messages', async () => { + decryptMessageManagerMock.getUnapprovedMessages.mockReturnValue({ + [messageIdMock]: messageMock, + }); + + await decryptMessageController.rejectUnapproved('reason to cancel'); + + expect(decryptMessageManagerMock.rejectMessage).toBeCalledTimes(1); + expect(decryptMessageManagerMock.rejectMessage).toBeCalledWith( + messageIdMock, + ); + expect(metricsEventMock).toBeCalledTimes(1); + expect(metricsEventMock).toBeCalledWith({ + event: 'reason to cancel', + category: MetaMetricsEventCategory.Messages, + properties: { + action: 'Decrypt Message Request', + }, + }); + }); +}); diff --git a/app/scripts/controllers/decrypt-message.ts b/app/scripts/controllers/decrypt-message.ts new file mode 100644 index 000000000..779b22f78 --- /dev/null +++ b/app/scripts/controllers/decrypt-message.ts @@ -0,0 +1,394 @@ +import EventEmitter from 'events'; +import log from 'loglevel'; +import { + DecryptMessageManager, + DecryptMessageParams, + DecryptMessageParamsMetamask, +} from '@metamask/message-manager'; +import { KeyringController } from '@metamask/eth-keyring-controller'; +import { + AbstractMessage, + AbstractMessageManager, + AbstractMessageParams, + AbstractMessageParamsMetamask, + MessageManagerState, + OriginalRequest, +} from '@metamask/message-manager/dist/AbstractMessageManager'; +import { + BaseControllerV2, + RestrictedControllerMessenger, +} from '@metamask/base-controller'; +import { + AcceptRequest, + AddApprovalRequest, + RejectRequest, +} from '@metamask/approval-controller'; +import { ApprovalType, ORIGIN_METAMASK } from '@metamask/controller-utils'; +import { Patch } from 'immer'; +import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics'; +import { stripHexPrefix } from '../../../shared/modules/hexstring-utils'; + +const controllerName = 'DecryptMessageController'; + +const stateMetadata = { + unapprovedDecryptMsgs: { persist: false, anonymous: false }, + unapprovedDecryptMsgCount: { persist: false, anonymous: false }, +}; + +export const getDefaultState = () => ({ + unapprovedDecryptMsgs: {}, + unapprovedDecryptMsgCount: 0, +}); + +export type CoreMessage = AbstractMessage & { + messageParams: AbstractMessageParams; +}; + +export type StateMessage = Required< + Omit +>; + +export type DecryptMessageControllerState = { + unapprovedDecryptMsgs: Record; + unapprovedDecryptMsgCount: number; +}; + +export type GetDecryptMessageState = { + type: `${typeof controllerName}:getState`; + handler: () => DecryptMessageControllerState; +}; + +export type DecryptMessageStateChange = { + type: `${typeof controllerName}:stateChange`; + payload: [DecryptMessageControllerState, Patch[]]; +}; + +export type DecryptMessageControllerActions = GetDecryptMessageState; + +export type DecryptMessageControllerEvents = DecryptMessageStateChange; + +type AllowedActions = AddApprovalRequest | AcceptRequest | RejectRequest; + +export type DecryptMessageControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + DecryptMessageControllerActions | AllowedActions, + DecryptMessageControllerEvents, + AllowedActions['type'], + never +>; + +export type DecryptMessageControllerOptions = { + getState: () => any; + keyringController: KeyringController; + messenger: DecryptMessageControllerMessenger; + metricsEvent: (payload: any, options?: any) => void; +}; + +/** + * Controller for decrypt signing requests requiring user approval. + */ +export default class DecryptMessageController extends BaseControllerV2< + typeof controllerName, + DecryptMessageControllerState, + DecryptMessageControllerMessenger +> { + hub: EventEmitter; + + private _getState: () => any; + + private _keyringController: KeyringController; + + private _metricsEvent: (payload: any, options?: any) => void; + + private _decryptMessageManager: DecryptMessageManager; + + /** + * Construct a DecryptMessage controller. + * + * @param options - The controller options. + * @param options.getState - Callback to retrieve all user state. + * @param options.keyringController - An instance of a keyring controller used to decrypt message + * @param options.messenger - A reference to the messaging system. + * @param options.metricsEvent - A function for emitting a metric event. + */ + constructor({ + getState, + keyringController, + metricsEvent, + messenger, + }: DecryptMessageControllerOptions) { + super({ + metadata: stateMetadata, + messenger, + name: controllerName, + state: getDefaultState(), + }); + this._getState = getState; + this._keyringController = keyringController; + this._metricsEvent = metricsEvent; + + this.hub = new EventEmitter(); + + this._decryptMessageManager = new DecryptMessageManager( + undefined, + undefined, + undefined, + ['decrypted'], + ); + + this._decryptMessageManager.hub.on('updateBadge', () => { + this.hub.emit('updateBadge'); + }); + + this._decryptMessageManager.hub.on( + 'unapprovedMessage', + (messageParams: AbstractMessageParamsMetamask) => { + this._requestApproval(messageParams); + }, + ); + + this._subscribeToMessageState( + this._decryptMessageManager, + (state, newMessages, messageCount) => { + state.unapprovedDecryptMsgs = newMessages; + state.unapprovedDecryptMsgCount = messageCount; + }, + ); + } + + /** + * A getter for the number of 'unapproved' Messages in the DecryptMessageManager. + * + * @returns The number of 'unapproved' Messages in the DecryptMessageManager. + */ + get unapprovedDecryptMsgCount(): number { + return this._decryptMessageManager.getUnapprovedMessagesCount(); + } + + /** + * Reset the controller state to the initial state. + */ + resetState() { + this.update(() => getDefaultState()); + } + + /** + * Clears all unapproved messages from memory. + */ + clearUnapproved() { + this._decryptMessageManager.update({ + unapprovedMessages: {}, + unapprovedMessagesCount: 0, + }); + } + + /** + * Called when a dapp uses the eth_decrypt method + * + * @param messageParams - The params passed to eth_decrypt. + * @param req - The original request, containing the origin. + * @returns Promise resolving to the raw data of the signature request. + */ + async newRequestDecryptMessage( + messageParams: DecryptMessageParams, + req: OriginalRequest, + ): Promise { + return this._decryptMessageManager.addUnapprovedMessageAsync( + messageParams, + req, + ); + } + + /** + * Signifies a user's approval to decrypt a message in queue. + * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. + * + * @param messageParams - The params of the message to decrypt & return to the Dapp. + * @returns A full state update. + */ + async decryptMessage(messageParams: DecryptMessageParamsMetamask) { + const messageId = messageParams.metamaskId as string; + try { + const cleanMessageParams = + await this._decryptMessageManager.approveMessage(messageParams); + + cleanMessageParams.data = this._parseMessageData(cleanMessageParams.data); + const rawMessage = await this._keyringController.decryptMessage( + cleanMessageParams, + ); + + this._decryptMessageManager.setMessageStatusAndResult( + messageId, + rawMessage, + 'decrypted', + ); + this._acceptApproval(messageId); + } catch (error) { + log.info('MetaMaskController - eth_decrypt failed.', error); + this._cancelAbstractMessage(this._decryptMessageManager, messageId); + throw error; + } + return this._getState(); + } + + /** + * Only decrypt message and don't touch transaction state + * + * @param messageParams - The params of the message to decrypt. + * @returns A full state update. + */ + async decryptMessageInline(messageParams: DecryptMessageParamsMetamask) { + const messageId = messageParams.metamaskId as string; + messageParams.data = this._parseMessageData(messageParams.data); + const rawMessage = await this._keyringController.decryptMessage( + messageParams, + ); + + this._decryptMessageManager.setResult(messageId, rawMessage); + + return this._getState(); + } + + /** + * Used to cancel a eth_decrypt type message. + * + * @param messageId - The ID of the message to cancel. + * @returns A full state update. + */ + cancelDecryptMessage(messageId: string) { + this._decryptMessageManager.rejectMessage(messageId); + this._rejectApproval(messageId); + return this._getState(); + } + + /** + * Reject all unapproved messages of any type. + * + * @param reason - A message to indicate why. + */ + rejectUnapproved(reason?: string) { + Object.keys(this._decryptMessageManager.getUnapprovedMessages()).forEach( + (messageId) => { + this._cancelAbstractMessage( + this._decryptMessageManager, + messageId, + reason, + ); + }, + ); + } + + private _acceptApproval(messageId: string) { + this.messagingSystem.call('ApprovalController:acceptRequest', messageId); + } + + private _cancelAbstractMessage( + messageManager: AbstractMessageManager< + AbstractMessage, + AbstractMessageParams, + AbstractMessageParamsMetamask + >, + messageId: string, + reason?: string, + ) { + if (reason) { + this._metricsEvent({ + event: reason, + category: MetaMetricsEventCategory.Messages, + properties: { + action: 'Decrypt Message Request', + }, + }); + } + + messageManager.rejectMessage(messageId); + this._rejectApproval(messageId); + + return this._getState(); + } + + private _subscribeToMessageState( + messageManager: AbstractMessageManager< + AbstractMessage, + AbstractMessageParams, + AbstractMessageParamsMetamask + >, + updateState: ( + state: DecryptMessageControllerState, + newMessages: Record, + messageCount: number, + ) => void, + ) { + messageManager.subscribe((state: MessageManagerState) => { + const newMessages = this._migrateMessages( + state.unapprovedMessages as any, + ); + this.update((draftState) => { + updateState(draftState, newMessages, state.unapprovedMessagesCount); + }); + }); + } + + private _migrateMessages( + coreMessages: Record, + ): Record { + const stateMessages: Record = {}; + + for (const messageId of Object.keys(coreMessages)) { + const coreMessage = coreMessages[messageId]; + const stateMessage = this._migrateMessage(coreMessage); + stateMessages[messageId] = stateMessage; + } + + return stateMessages; + } + + private _migrateMessage(coreMessage: CoreMessage): StateMessage { + const { messageParams, ...coreMessageData } = coreMessage; + + const stateMessage = { + ...coreMessageData, + rawSig: coreMessage.rawSig as string, + msgParams: messageParams, + origin: messageParams.origin, + }; + + return stateMessage; + } + + private _requestApproval(messageParams: AbstractMessageParamsMetamask) { + const id = messageParams.metamaskId as string; + const origin = messageParams.origin || ORIGIN_METAMASK; + try { + this.messagingSystem.call( + 'ApprovalController:addRequest', + { + id, + origin, + type: ApprovalType.EthDecrypt, + }, + true, + ); + } catch (error) { + log.info('Error adding request to approval controller', error); + } + } + + private _parseMessageData(data: string) { + const stripped = stripHexPrefix(data); + const buff = Buffer.from(stripped, 'hex'); + return JSON.parse(buff.toString('utf8')); + } + + private _rejectApproval(messageId: string) { + try { + this.messagingSystem.call( + 'ApprovalController:rejectRequest', + messageId, + 'Cancel', + ); + } catch (error) { + log.info('Error rejecting request to approval controller', error); + } + } +} diff --git a/app/scripts/controllers/encryption-public-key.ts b/app/scripts/controllers/encryption-public-key.ts index f4cb5e25e..626413b3f 100644 --- a/app/scripts/controllers/encryption-public-key.ts +++ b/app/scripts/controllers/encryption-public-key.ts @@ -342,36 +342,31 @@ export default class EncryptionPublicKeyController extends BaseControllerV2< messageCount: number, ) => void, ) { - messageManager.subscribe( - async (state: MessageManagerState) => { - const newMessages = await this._migrateMessages( - state.unapprovedMessages as any, - ); - this.update((draftState) => { - updateState(draftState, newMessages, state.unapprovedMessagesCount); - }); - }, - ); + messageManager.subscribe((state: MessageManagerState) => { + const newMessages = this._migrateMessages( + state.unapprovedMessages as any, + ); + this.update((draftState) => { + updateState(draftState, newMessages, state.unapprovedMessagesCount); + }); + }); } - private async _migrateMessages( + private _migrateMessages( coreMessages: Record, - ): Promise> { + ): Record { const stateMessages: Record = {}; for (const messageId of Object.keys(coreMessages)) { const coreMessage = coreMessages[messageId]; - const stateMessage = await this._migrateMessage(coreMessage); - + const stateMessage = this._migrateMessage(coreMessage); stateMessages[messageId] = stateMessage; } return stateMessages; } - private async _migrateMessage( - coreMessage: CoreMessage, - ): Promise { + private _migrateMessage(coreMessage: CoreMessage): StateMessage { const { messageParams, ...coreMessageData } = coreMessage; // Core message managers use messageParams but frontend uses msgParams with lots of references diff --git a/app/scripts/lib/decrypt-message-manager.js b/app/scripts/lib/decrypt-message-manager.js deleted file mode 100644 index 9249c907e..000000000 --- a/app/scripts/lib/decrypt-message-manager.js +++ /dev/null @@ -1,351 +0,0 @@ -import EventEmitter from 'events'; -import { ObservableStore } from '@metamask/obs-store'; -import { bufferToHex } from 'ethereumjs-util'; -import { ethErrors } from 'eth-rpc-errors'; -import log from 'loglevel'; -import { MESSAGE_TYPE } from '../../../shared/constants/app'; -import { MetaMetricsEventCategory } from '../../../shared/constants/metametrics'; -import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller'; -import createId from '../../../shared/modules/random-id'; -import { stripHexPrefix } from '../../../shared/modules/hexstring-utils'; -import { addHexPrefix } from './util'; - -const hexRe = /^[0-9A-Fa-f]+$/gu; - -/** - * Represents, and contains data about, an 'eth_decrypt' type decryption request. These are created when a - * decryption for an eth_decrypt call is requested. - * - * @typedef {object} DecryptMessage - * @property {number} id An id to track and identify the message object - * @property {object} msgParams The parameters to pass to the decryptMessage method once the decryption request is - * approved. - * @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask. - * @property {string} msgParams.data A hex string conversion of the raw buffer data of the decryption request - * @property {number} time The epoch time at which the this message was created - * @property {string} status Indicates whether the decryption request is 'unapproved', 'approved', 'decrypted' or 'rejected' - * @property {string} type The json-prc decryption method for which a decryption request has been made. A 'Message' will - * always have a 'eth_decrypt' type. - */ - -export default class DecryptMessageManager extends EventEmitter { - /** - * Controller in charge of managing - storing, adding, removing, updating - DecryptMessage. - * - * @param {object} opts - Controller options - * @param {Function} opts.metricEvent - A function for emitting a metric event. - */ - constructor(opts) { - super(); - this.memStore = new ObservableStore({ - unapprovedDecryptMsgs: {}, - unapprovedDecryptMsgCount: 0, - }); - - this.resetState = () => { - this.memStore.updateState({ - unapprovedDecryptMsgs: {}, - unapprovedDecryptMsgCount: 0, - }); - }; - - this.messages = []; - this.metricsEvent = opts.metricsEvent; - } - - /** - * A getter for the number of 'unapproved' DecryptMessages in this.messages - * - * @returns {number} The number of 'unapproved' DecryptMessages in this.messages - */ - get unapprovedDecryptMsgCount() { - return Object.keys(this.getUnapprovedMsgs()).length; - } - - /** - * A getter for the 'unapproved' DecryptMessages in this.messages - * - * @returns {object} An index of DecryptMessage ids to DecryptMessages, for all 'unapproved' DecryptMessages in - * this.messages - */ - getUnapprovedMsgs() { - return this.messages - .filter((msg) => msg.status === 'unapproved') - .reduce((result, msg) => { - result[msg.id] = msg; - return result; - }, {}); - } - - /** - * Creates a new DecryptMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add - * the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to - * this.memStore. - * - * @param {object} msgParams - The params for the eth_decrypt call to be made after the message is approved. - * @param {object} [req] - The original request object possibly containing the origin - * @returns {Promise} The raw decrypted message contents - */ - addUnapprovedMessageAsync(msgParams, req) { - return new Promise((resolve, reject) => { - if (!msgParams.from) { - reject(new Error('MetaMask Decryption: from field is required.')); - return; - } - const msgId = this.addUnapprovedMessage(msgParams, req); - this.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'decrypted': - resolve(data.rawData); - return; - case 'rejected': - reject( - ethErrors.provider.userRejectedRequest( - 'MetaMask Decryption: User denied message decryption.', - ), - ); - return; - case 'errored': - reject(new Error('This message cannot be decrypted')); - return; - default: - reject( - new Error( - `MetaMask Decryption: Unknown problem: ${JSON.stringify( - msgParams, - )}`, - ), - ); - } - }); - }); - } - - /** - * Creates a new DecryptMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add - * the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to - * this.memStore. - * - * @param {object} msgParams - The params for the eth_decryptMsg call to be made after the message is approved. - * @param {object} [req] - The original request object possibly containing the origin - * @returns {number} The id of the newly created DecryptMessage. - */ - addUnapprovedMessage(msgParams, req) { - log.debug( - `DecryptMessageManager addUnapprovedMessage: ${JSON.stringify( - msgParams, - )}`, - ); - // add origin from request - if (req) { - msgParams.origin = req.origin; - } - msgParams.data = this.normalizeMsgData(msgParams.data); - // create txData obj with parameters and meta data - const time = new Date().getTime(); - const msgId = createId(); - const msgData = { - id: msgId, - msgParams, - time, - status: 'unapproved', - type: MESSAGE_TYPE.ETH_DECRYPT, - }; - this.addMsg(msgData); - - // signal update - this.emit('update'); - return msgId; - } - - /** - * Adds a passed DecryptMessage to this.messages, and calls this._saveMsgList() to save the unapproved DecryptMessages from that - * list to this.memStore. - * - * @param {Message} msg - The DecryptMessage to add to this.messages - */ - addMsg(msg) { - this.messages.push(msg); - this._saveMsgList(); - } - - /** - * Returns a specified DecryptMessage. - * - * @param {number} msgId - The id of the DecryptMessage to get - * @returns {DecryptMessage|undefined} The DecryptMessage with the id that matches the passed msgId, or undefined - * if no DecryptMessage has that id. - */ - getMsg(msgId) { - return this.messages.find((msg) => msg.id === msgId); - } - - /** - * Approves a DecryptMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise - * with the message params modified for proper decryption. - * - * @param {object} msgParams - The msgParams to be used when eth_decryptMsg is called, plus data added by MetaMask. - * @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask. - * @returns {Promise} Promises the msgParams object with metamaskId removed. - */ - approveMessage(msgParams) { - this.setMsgStatusApproved(msgParams.metamaskId); - return this.prepMsgForDecryption(msgParams); - } - - /** - * Sets a DecryptMessage status to 'approved' via a call to this._setMsgStatus. - * - * @param {number} msgId - The id of the DecryptMessage to approve. - */ - setMsgStatusApproved(msgId) { - this._setMsgStatus(msgId, 'approved'); - } - - /** - * Sets a DecryptMessage status to 'decrypted' via a call to this._setMsgStatus and updates that DecryptMessage in - * this.messages by adding the raw decryption data of the decryption request to the DecryptMessage - * - * @param {number} msgId - The id of the DecryptMessage to decrypt. - * @param {buffer} rawData - The raw data of the message request - */ - setMsgStatusDecrypted(msgId, rawData) { - const msg = this.getMsg(msgId); - msg.rawData = rawData; - this._updateMsg(msg); - this._setMsgStatus(msgId, 'decrypted'); - } - - /** - * Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams - * - * @param {object} msgParams - The msgParams to modify - * @returns {Promise} Promises the msgParams with the metamaskId property removed - */ - async prepMsgForDecryption(msgParams) { - delete msgParams.metamaskId; - return msgParams; - } - - /** - * Sets a DecryptMessage status to 'rejected' via a call to this._setMsgStatus. - * - * @param {number} msgId - The id of the DecryptMessage to reject. - * @param reason - */ - rejectMsg(msgId, reason = undefined) { - if (reason) { - this.metricsEvent({ - event: reason, - category: MetaMetricsEventCategory.Messages, - properties: { - action: 'Decrypt Message Request', - }, - }); - } - this._setMsgStatus(msgId, 'rejected'); - } - - /** - * Sets a TypedMessage status to 'errored' via a call to this._setMsgStatus. - * - * @param {number} msgId - The id of the TypedMessage to error - * @param error - */ - errorMessage(msgId, error) { - const msg = this.getMsg(msgId); - msg.error = error; - this._updateMsg(msg); - this._setMsgStatus(msgId, 'errored'); - } - - /** - * Clears all unapproved messages from memory. - */ - clearUnapproved() { - this.messages = this.messages.filter((msg) => msg.status !== 'unapproved'); - this._saveMsgList(); - } - - /** - * Updates the status of a DecryptMessage in this.messages via a call to this._updateMsg - * - * @private - * @param {number} msgId - The id of the DecryptMessage to update. - * @param {string} status - The new status of the DecryptMessage. - * @throws A 'DecryptMessageManager - DecryptMessage not found for id: "${msgId}".' if there is no DecryptMessage - * in this.messages with an id equal to the passed msgId - * @fires An event with a name equal to `${msgId}:${status}`. The DecryptMessage is also fired. - * @fires If status is 'rejected' or 'decrypted', an event with a name equal to `${msgId}:finished` is fired along - * with the DecryptMessage - */ - _setMsgStatus(msgId, status) { - const msg = this.getMsg(msgId); - if (!msg) { - throw new Error( - `DecryptMessageManager - Message not found for id: "${msgId}".`, - ); - } - msg.status = status; - this._updateMsg(msg); - this.emit(`${msgId}:${status}`, msg); - if ( - status === 'rejected' || - status === 'decrypted' || - status === 'errored' - ) { - this.emit(`${msgId}:finished`, msg); - } - } - - /** - * Sets a DecryptMessage in this.messages to the passed DecryptMessage if the ids are equal. Then saves the - * unapprovedDecryptMsgs index to storage via this._saveMsgList - * - * @private - * @param {DecryptMessage} msg - A DecryptMessage that will replace an existing DecryptMessage (with the same - * id) in this.messages - */ - _updateMsg(msg) { - const index = this.messages.findIndex((message) => message.id === msg.id); - if (index !== -1) { - this.messages[index] = msg; - } - this._saveMsgList(); - } - - /** - * Saves the unapproved DecryptMessages, and their count, to this.memStore - * - * @private - * @fires 'updateBadge' - */ - _saveMsgList() { - const unapprovedDecryptMsgs = this.getUnapprovedMsgs(); - const unapprovedDecryptMsgCount = Object.keys(unapprovedDecryptMsgs).length; - this.memStore.updateState({ - unapprovedDecryptMsgs, - unapprovedDecryptMsgCount, - }); - this.emit(METAMASK_CONTROLLER_EVENTS.UPDATE_BADGE); - } - - /** - * A helper function that converts raw buffer data to a hex, or just returns the data if it is already formatted as a hex. - * - * @param {any} data - The buffer data to convert to a hex - * @returns {string} A hex string conversion of the buffer data - */ - normalizeMsgData(data) { - try { - const stripped = stripHexPrefix(data); - if (stripped.match(hexRe)) { - return addHexPrefix(stripped); - } - } catch (e) { - log.debug(`Message was not hex encoded, interpreting as utf8.`); - } - - return bufferToHex(Buffer.from(data, 'utf8')); - } -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a789ae227..e2e52493e 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -90,7 +90,6 @@ import { ///: END:ONLY_INCLUDE_IN } from '../../shared/constants/permissions'; import { UI_NOTIFICATIONS } from '../../shared/notifications'; -import { stripHexPrefix } from '../../shared/modules/hexstring-utils'; import { MILLISECOND, SECOND } from '../../shared/constants/time'; import { ORIGIN_METAMASK, @@ -150,7 +149,7 @@ import AlertController from './controllers/alert'; import OnboardingController from './controllers/onboarding'; import BackupController from './controllers/backup'; import IncomingTransactionsController from './controllers/incoming-transactions'; -import DecryptMessageManager from './lib/decrypt-message-manager'; +import DecryptMessageController from './controllers/decrypt-message'; import TransactionController from './controllers/transactions'; import DetectTokensController from './controllers/detect-tokens'; import SwapsController from './controllers/swaps'; @@ -1156,7 +1155,17 @@ export default class MetamaskController extends EventEmitter { ); this.networkController.lookupNetwork(); - this.decryptMessageManager = new DecryptMessageManager({ + this.decryptMessageController = new DecryptMessageController({ + getState: this.getState.bind(this), + keyringController: this.keyringController, + messenger: this.controllerMessenger.getRestricted({ + name: 'DecryptMessageController', + allowedActions: [ + `${this.approvalController.name}:addRequest`, + `${this.approvalController.name}:acceptRequest`, + `${this.approvalController.name}:rejectRequest`, + ], + }), metricsEvent: this.metaMetricsController.trackEvent.bind( this.metaMetricsController, ), @@ -1256,7 +1265,7 @@ export default class MetamaskController extends EventEmitter { () => { this.txController.txStateManager.clearUnapprovedTxs(); this.encryptionPublicKeyController.clearUnapproved(); - this.decryptMessageManager.clearUnapproved(); + this.decryptMessageController.clearUnapproved(); this.signController.clearUnapproved(); }, ); @@ -1321,11 +1330,14 @@ export default class MetamaskController extends EventEmitter { this.signController.newUnsignedPersonalMessage.bind( this.signController, ), - processDecryptMessage: this.newRequestDecryptMessage.bind(this), processEncryptionPublicKey: this.encryptionPublicKeyController.newRequestEncryptionPublicKey.bind( this.encryptionPublicKeyController, ), + processDecryptMessage: + this.decryptMessageController.newRequestDecryptMessage.bind( + this.decryptMessageController, + ), getPendingNonce: this.getPendingNonce.bind(this), getPendingTransactionByHash: (hash) => this.txController.getTransactions({ @@ -1347,7 +1359,7 @@ export default class MetamaskController extends EventEmitter { AccountTracker: this.accountTracker.store, TxController: this.txController.memStore, TokenRatesController: this.tokenRatesController, - DecryptMessageManager: this.decryptMessageManager.memStore, + DecryptMessageController: this.decryptMessageController, EncryptionPublicKeyController: this.encryptionPublicKeyController, SignController: this.signController, SwapsController: this.swapsController.store, @@ -1433,7 +1445,9 @@ export default class MetamaskController extends EventEmitter { const resetMethods = [ this.accountTracker.resetState, this.txController.resetState, - this.decryptMessageManager.resetState, + this.decryptMessageController.resetState.bind( + this.decryptMessageController, + ), this.encryptionPublicKeyController.resetState.bind( this.encryptionPublicKeyController, ), @@ -2137,10 +2151,18 @@ export default class MetamaskController extends EventEmitter { this.signController, ), - // decryptMessageManager - decryptMessage: this.decryptMessage.bind(this), - decryptMessageInline: this.decryptMessageInline.bind(this), - cancelDecryptMessage: this.cancelDecryptMessage.bind(this), + // decryptMessageController + decryptMessage: this.decryptMessageController.decryptMessage.bind( + this.decryptMessageController, + ), + decryptMessageInline: + this.decryptMessageController.decryptMessageInline.bind( + this.decryptMessageController, + ), + cancelDecryptMessage: + this.decryptMessageController.cancelDecryptMessage.bind( + this.decryptMessageController, + ), // EncryptionPublicKeyController encryptionPublicKey: @@ -3158,95 +3180,6 @@ export default class MetamaskController extends EventEmitter { return await this.txController.newUnapprovedTransaction(txParams, req); } - // eth_decrypt methods - - /** - * Called when a dapp uses the eth_decrypt method. - * - * @param {object} msgParams - The params of the message to sign & return to the Dapp. - * @param {object} req - (optional) the original request, containing the origin - * Passed back to the requesting Dapp. - */ - async newRequestDecryptMessage(msgParams, req) { - const promise = this.decryptMessageManager.addUnapprovedMessageAsync( - msgParams, - req, - ); - this.sendUpdate(); - this.opts.showUserConfirmation(); - return promise; - } - - /** - * Only decrypt message and don't touch transaction state - * - * @param {object} msgParams - The params of the message to decrypt. - * @returns {Promise} A full state update. - */ - async decryptMessageInline(msgParams) { - log.info('MetaMaskController - decryptMessageInline'); - // decrypt the message inline - const msgId = msgParams.metamaskId; - const msg = this.decryptMessageManager.getMsg(msgId); - try { - const stripped = stripHexPrefix(msgParams.data); - const buff = Buffer.from(stripped, 'hex'); - msgParams.data = JSON.parse(buff.toString('utf8')); - - msg.rawData = await this.keyringController.decryptMessage(msgParams); - } catch (e) { - msg.error = e.message; - } - this.decryptMessageManager._updateMsg(msg); - - return this.getState(); - } - - /** - * Signifies a user's approval to decrypt a message in queue. - * Triggers decrypt, and the callback function from newUnsignedDecryptMessage. - * - * @param {object} msgParams - The params of the message to decrypt & return to the Dapp. - * @returns {Promise} A full state update. - */ - async decryptMessage(msgParams) { - log.info('MetaMaskController - decryptMessage'); - const msgId = msgParams.metamaskId; - // sets the status op the message to 'approved' - // and removes the metamaskId for decryption - try { - const cleanMsgParams = await this.decryptMessageManager.approveMessage( - msgParams, - ); - - const stripped = stripHexPrefix(cleanMsgParams.data); - const buff = Buffer.from(stripped, 'hex'); - cleanMsgParams.data = JSON.parse(buff.toString('utf8')); - - // decrypt the message - const rawMess = await this.keyringController.decryptMessage( - cleanMsgParams, - ); - // tells the listener that the message has been decrypted and can be returned to the dapp - this.decryptMessageManager.setMsgStatusDecrypted(msgId, rawMess); - } catch (error) { - log.info('MetaMaskController - eth_decrypt failed.', error); - this.decryptMessageManager.errorMessage(msgId, error); - } - return this.getState(); - } - - /** - * Used to cancel a eth_decrypt type message. - * - * @param {string} msgId - The ID of the message to cancel. - */ - cancelDecryptMessage(msgId) { - const messageManager = this.decryptMessageManager; - messageManager.rejectMsg(msgId); - return this.getState(); - } - /** * @returns {boolean} true if the keyring type supports EIP-1559 */ diff --git a/development/ts-migration-dashboard/files-to-convert.json b/development/ts-migration-dashboard/files-to-convert.json index 099edb1f1..bf123f1e3 100644 --- a/development/ts-migration-dashboard/files-to-convert.json +++ b/development/ts-migration-dashboard/files-to-convert.json @@ -79,7 +79,6 @@ "app/scripts/lib/createRPCMethodTrackingMiddleware.test.js", "app/scripts/lib/createStreamSink.js", "app/scripts/lib/createTabIdMiddleware.js", - "app/scripts/lib/decrypt-message-manager.js", "app/scripts/lib/ens-ipfs/contracts/registry.js", "app/scripts/lib/ens-ipfs/contracts/resolver.js", "app/scripts/lib/ens-ipfs/resolver.js", diff --git a/jest.config.js b/jest.config.js index bbcb93a4a..a3813632b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,6 +6,7 @@ module.exports = { '!/app/scripts/controllers/network/**/test/*.ts', '/app/scripts/controllers/permissions/**/*.js', '/app/scripts/controllers/sign.ts', + '/app/scripts/controllers/decrypt-message.ts', '/app/scripts/flask/**/*.js', '/app/scripts/lib/**/*.js', '/app/scripts/lib/createRPCMethodTrackingMiddleware.js', @@ -44,6 +45,7 @@ module.exports = { '/app/scripts/controllers/network/**/*.test.ts', '/app/scripts/controllers/permissions/**/*.test.js', '/app/scripts/controllers/sign.test.ts', + '/app/scripts/controllers/decrypt-message.test.ts', '/app/scripts/flask/**/*.test.js', '/app/scripts/lib/**/*.test.js', '/app/scripts/lib/**/*.test.ts', diff --git a/package.json b/package.json index d89c7421a..2ae4f8c36 100644 --- a/package.json +++ b/package.json @@ -246,7 +246,7 @@ "@metamask/jazzicon": "^2.0.0", "@metamask/key-tree": "^7.0.0", "@metamask/logo": "^3.1.1", - "@metamask/message-manager": "^3.0.0", + "@metamask/message-manager": "^3.1.1", "@metamask/metamask-eth-abis": "^3.0.0", "@metamask/notification-controller": "^2.0.0", "@metamask/obs-store": "^8.1.0", diff --git a/types/eth-keyring-controller.d.ts b/types/eth-keyring-controller.d.ts index 81145fa60..ee7525bf3 100644 --- a/types/eth-keyring-controller.d.ts +++ b/types/eth-keyring-controller.d.ts @@ -11,5 +11,7 @@ declare module '@metamask/eth-keyring-controller' { }>; getEncryptionPublicKey: (address: string) => Promise; + + decryptMessage: (...any) => any; } } diff --git a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.js b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.js index d223a3e96..620aa41fc 100644 --- a/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.js +++ b/ui/pages/confirm-decrypt-message/confirm-decrypt-message.component.js @@ -221,7 +221,7 @@ export default class ConfirmDecryptMessage extends Component { } else { this.setState({ hasDecrypted: true, - rawMessage: result.rawData, + rawMessage: result.rawSig, }); } }); diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 41f7b6da7..71d8ead6c 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -497,14 +497,9 @@ export function getCurrentCurrency(state) { } export function getTotalUnapprovedCount(state) { - const { unapprovedDecryptMsgCount = 0, pendingApprovalCount = 0 } = - state.metamask; + const { pendingApprovalCount = 0 } = state.metamask; - return ( - unapprovedDecryptMsgCount + - pendingApprovalCount + - getSuggestedAssetCount(state) - ); + return pendingApprovalCount + getSuggestedAssetCount(state); } export function getTotalUnapprovedMessagesCount(state) { diff --git a/yarn.lock b/yarn.lock index 56e38c69d..7edb2d18e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3725,9 +3725,9 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^3.0.0, @metamask/controller-utils@npm:^3.1.0, @metamask/controller-utils@npm:^3.2.0, @metamask/controller-utils@npm:^3.3.0": - version: 3.3.0 - resolution: "@metamask/controller-utils@npm:3.3.0" +"@metamask/controller-utils@npm:^3.0.0, @metamask/controller-utils@npm:^3.1.0, @metamask/controller-utils@npm:^3.2.0, @metamask/controller-utils@npm:^3.3.0, @metamask/controller-utils@npm:^3.4.0": + version: 3.4.0 + resolution: "@metamask/controller-utils@npm:3.4.0" dependencies: "@metamask/utils": ^5.0.1 "@spruceid/siwe-parser": 1.1.3 @@ -3736,7 +3736,7 @@ __metadata: ethereumjs-util: ^7.0.10 ethjs-unit: ^0.1.6 fast-deep-equal: ^3.1.3 - checksum: 54e19f7bfd7b7762913313877484f0cfe9ac3e66cf43eabc6573e22433a7a36154a1f04fa5834807644a780b4b2200e0cafc06a0f0ef9fcead44304d742b2ad3 + checksum: c483a56a062118ad0b740ca65ec05810226af069bdcd7ff92adc250a9a4e8b9abf347876476ecd005f7890770b5bbf2f621a90b5a3698fdd059127d4337d7c6b languageName: node linkType: hard @@ -4024,18 +4024,18 @@ __metadata: languageName: node linkType: hard -"@metamask/message-manager@npm:^3.0.0": - version: 3.0.0 - resolution: "@metamask/message-manager@npm:3.0.0" +"@metamask/message-manager@npm:^3.1.1": + version: 3.1.1 + resolution: "@metamask/message-manager@npm:3.1.1" dependencies: "@metamask/base-controller": ^2.0.0 - "@metamask/controller-utils": ^3.1.0 + "@metamask/controller-utils": ^3.4.0 "@types/uuid": ^8.3.0 eth-sig-util: ^3.0.0 ethereumjs-util: ^7.0.10 jsonschema: ^1.2.4 uuid: ^8.3.2 - checksum: 14e0a4a398d95ce720e515bd1f35aee7b7b9f5f59367210a9125fe66fb561b630ae51b61f32048767f0bb30dd4a2e442e47c8d850de78f820feda7f72e4dc05e + checksum: 5f2341a67826b04a2b9dafff1bd53f1a7d3748e9617da5360248549eb5c048aebe542d3c364e77a5d4263358f8dfac8109f0f5faaabf0630c3be7d5857ab881d languageName: node linkType: hard @@ -24091,7 +24091,7 @@ __metadata: "@metamask/jazzicon": ^2.0.0 "@metamask/key-tree": ^7.0.0 "@metamask/logo": ^3.1.1 - "@metamask/message-manager": ^3.0.0 + "@metamask/message-manager": ^3.1.1 "@metamask/metamask-eth-abis": ^3.0.0 "@metamask/notification-controller": ^2.0.0 "@metamask/obs-store": ^8.1.0 From b4fc0bddd290d7e88a108cf8b811242c53f2b136 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:06:38 +0000 Subject: [PATCH 48/60] devDeps: bump @storybook/* (#18832) * devDeps: @storybook/*->6.5.16 * devDeps: copy-webpack-plugin@6.0.3->6.4.1 CVE-2021-27290 / GHSA-vx3p-948g-6vhq --- yarn.lock | 989 +++++++++++++++++++++--------------------------------- 1 file changed, 380 insertions(+), 609 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7edb2d18e..9ef142377 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2538,7 +2538,7 @@ __metadata: languageName: node linkType: hard -"@gar/promisify@npm:^1.1.3": +"@gar/promisify@npm:^1.0.1, @gar/promisify@npm:^1.1.3": version: 1.1.3 resolution: "@gar/promisify@npm:1.1.3" checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 @@ -4587,6 +4587,16 @@ __metadata: languageName: node linkType: hard +"@npmcli/fs@npm:^1.0.0": + version: 1.1.1 + resolution: "@npmcli/fs@npm:1.1.1" + dependencies: + "@gar/promisify": ^1.0.1 + semver: ^7.3.5 + checksum: f5ad92f157ed222e4e31c352333d0901df02c7c04311e42a81d8eb555d4ec4276ea9c635011757de20cc476755af33e91622838de573b17e52e2e7703f0a9965 + languageName: node + linkType: hard + "@npmcli/fs@npm:^2.1.0": version: 2.1.2 resolution: "@npmcli/fs@npm:2.1.2" @@ -5088,17 +5098,17 @@ __metadata: linkType: hard "@storybook/addon-a11y@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-a11y@npm:6.5.13" + version: 6.5.16 + resolution: "@storybook/addon-a11y@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 axe-core: ^4.2.0 core-js: ^3.8.2 global: ^4.4.0 @@ -5115,21 +5125,21 @@ __metadata: optional: true react-dom: optional: true - checksum: 6f1ba1f0d97d652a5346a33e051e1ff79aa07786532c6450c5c3dd677c2195e3ee8792cda756d4556e5fbaa2a72a0631843aec2880121b3439bad3e401c25359 + checksum: 05ce7f696254782b521a5e946f7d58b207d854e69ce8b624a14de0192ce558f640b9dae821e122911059a24d2f9907e783e8dce5fb9288d5cfbdf0833aaab503 languageName: node linkType: hard -"@storybook/addon-actions@npm:6.5.13, @storybook/addon-actions@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-actions@npm:6.5.13" +"@storybook/addon-actions@npm:6.5.16, @storybook/addon-actions@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/addon-actions@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 @@ -5150,21 +5160,21 @@ __metadata: optional: true react-dom: optional: true - checksum: 2679174b1467281860cd6f11fac5ba505e44629eb11ee90713d1c954569cfb54d80aa822a0ed1be2f92f11ca62889fec3dca96f61b89cf238503e0cea4b1db9a + checksum: d506a932f38412fc234cd58b5f2c8a0bfb8f3820b0ce8042234e9bf4bd277a2befc2d8458d061405ee72722206756375f471a22c37ea32f384259fcbb1a2b6a5 languageName: node linkType: hard -"@storybook/addon-backgrounds@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-backgrounds@npm:6.5.13" +"@storybook/addon-backgrounds@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-backgrounds@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 global: ^4.4.0 memoizerific: ^1.11.3 @@ -5179,23 +5189,23 @@ __metadata: optional: true react-dom: optional: true - checksum: 1b18255e0d8dceca56b8d6cf672506176eedad3809f11879d9754652538bf004f90637c0bf557de5e7bc24d5db5410da79e61f131493cb87b27340611cb31cf5 + checksum: d10f0a6b5bf8f9974d3be08f1c30023f3148a0121456bf6296dbf70678f2591440e6fb5fd0643bc937a822c49284d81afeeed66f1b3de775d24c1149f402824b languageName: node linkType: hard -"@storybook/addon-controls@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-controls@npm:6.5.13" +"@storybook/addon-controls@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-controls@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-common": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-common": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/node-logger": 6.5.13 - "@storybook/store": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/node-logger": 6.5.16 + "@storybook/store": 6.5.16 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 lodash: ^4.17.21 ts-dedent: ^2.0.0 @@ -5207,32 +5217,32 @@ __metadata: optional: true react-dom: optional: true - checksum: a4f86332686b5681366ad1f1eebb50cb9939ce3424ade64c0043b94827df15a34da0190101c8dc9a2b4b9af67fafd9d3fb50a5b98ff7a24fed6a37a2f8f37f27 + checksum: a9f1f577e5d991ae271c9823662adf65952554303094a2e0127bfe9d48e2415796628dadc3cfbc767600e21588336bfd9cb43da59fe76507b2186f6a61da34b8 languageName: node linkType: hard -"@storybook/addon-docs@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-docs@npm:6.5.13" +"@storybook/addon-docs@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-docs@npm:6.5.16" dependencies: "@babel/plugin-transform-react-jsx": ^7.12.12 "@babel/preset-env": ^7.12.11 "@jest/transform": ^26.6.2 "@mdx-js/react": ^1.6.22 - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/docs-tools": 6.5.13 + "@storybook/docs-tools": 6.5.16 "@storybook/mdx1-csf": ^0.0.1 - "@storybook/node-logger": 6.5.13 - "@storybook/postinstall": 6.5.13 - "@storybook/preview-web": 6.5.13 - "@storybook/source-loader": 6.5.13 - "@storybook/store": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/node-logger": 6.5.16 + "@storybook/postinstall": 6.5.16 + "@storybook/preview-web": 6.5.16 + "@storybook/source-loader": 6.5.16 + "@storybook/store": 6.5.16 + "@storybook/theming": 6.5.16 babel-loader: ^8.0.0 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 @@ -5254,26 +5264,26 @@ __metadata: optional: true react-dom: optional: true - checksum: 41755593a28497172d18efa623d6dd3054d5fe867f2a4bf02be3875a0d22ca5cf10f5bf3946c4fa6b392f955952aaf8c90b4ae88d0622a1e236c7333b58902c3 + checksum: 3203abc3af20bd8d22bda78c3c98b57f1c46ef29fe1942def0de687ddf08769592ec99d978048ed0aca82c13017b758392f644aaba40a0c0b68d2c61a9e5957d languageName: node linkType: hard "@storybook/addon-essentials@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-essentials@npm:6.5.13" + version: 6.5.16 + resolution: "@storybook/addon-essentials@npm:6.5.16" dependencies: - "@storybook/addon-actions": 6.5.13 - "@storybook/addon-backgrounds": 6.5.13 - "@storybook/addon-controls": 6.5.13 - "@storybook/addon-docs": 6.5.13 - "@storybook/addon-measure": 6.5.13 - "@storybook/addon-outline": 6.5.13 - "@storybook/addon-toolbars": 6.5.13 - "@storybook/addon-viewport": 6.5.13 - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/node-logger": 6.5.13 + "@storybook/addon-actions": 6.5.16 + "@storybook/addon-backgrounds": 6.5.16 + "@storybook/addon-controls": 6.5.16 + "@storybook/addon-docs": 6.5.16 + "@storybook/addon-measure": 6.5.16 + "@storybook/addon-outline": 6.5.16 + "@storybook/addon-toolbars": 6.5.16 + "@storybook/addon-viewport": 6.5.16 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/node-logger": 6.5.16 core-js: ^3.8.2 regenerator-runtime: ^0.13.7 ts-dedent: ^2.0.0 @@ -5314,7 +5324,7 @@ __metadata: optional: true webpack: optional: true - checksum: a7b1b34c7fbf0d863cf8dab3160cc267516cbcbeb155c4f91aab2c1d6005b23d5662a9104be0d733476ba4a0c8328ea899ae46bf55a9bddda5ce41996737b358 + checksum: f82a02d00f02c642dae01b2c6c32d48dc4647fe4adbf17d55bb517812d9e483a773084c1c5ceda39d7db5fdaebcaca324a28bb465e35fb524667ef2f5382b1d6 languageName: node linkType: hard @@ -5350,15 +5360,15 @@ __metadata: languageName: node linkType: hard -"@storybook/addon-measure@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-measure@npm:6.5.13" +"@storybook/addon-measure@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-measure@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 global: ^4.4.0 @@ -5370,19 +5380,19 @@ __metadata: optional: true react-dom: optional: true - checksum: 4bf1823f83a51e773cb941329bd1e637fba7d84c238a2af442eba4ab9950bda2d199bfa18194c62d7e25891166d8c89bf130303fc6c94d5aafa2eb0aaaeafa27 + checksum: 52fc33249679bb19fdd4e7285436b925832f3d18c223c495cea2b90aa68f08bc626199064eead88ea339ce7e7fa73940daf220e4408ccd4dfd3841288dc645e4 languageName: node linkType: hard -"@storybook/addon-outline@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-outline@npm:6.5.13" +"@storybook/addon-outline@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-outline@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 global: ^4.4.0 @@ -5396,19 +5406,19 @@ __metadata: optional: true react-dom: optional: true - checksum: f9ea9278ba7dd118b9db2dc8b695d661d2d289d4e52f5af02ba0e30f13245043f0c565a71925d8111694a3a02e6b8b459fbd42786fe794895cdb5c8345adf5f5 + checksum: cb838ecbbdb446552aab891e5fadef6663acf4b16b2bdc18b9a86c01866ccefff0129d9fb7d801604c43946fff5afdcb2c11a1a7813319948a08351c9f35bf46 languageName: node linkType: hard -"@storybook/addon-toolbars@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-toolbars@npm:6.5.13" +"@storybook/addon-toolbars@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-toolbars@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 regenerator-runtime: ^0.13.7 peerDependencies: @@ -5419,20 +5429,20 @@ __metadata: optional: true react-dom: optional: true - checksum: ec85023ffda5bdefe96cf6d6954c86fba67be190bb31cf3bb777d0a2493d606c78bed84d4bb19611d4114a35ba94f1efcc8331bc6032e0f9376a6fb797dc3ec2 + checksum: 7a30259bef831769db3e8d76ad439cc5deec919abf47b27a9d0143a581434748d2c8868fbbf8b9cce2910fd61f2200415b6ab5bc0dfab02436fbea2c312da770 languageName: node linkType: hard -"@storybook/addon-viewport@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addon-viewport@npm:6.5.13" +"@storybook/addon-viewport@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/addon-viewport@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 global: ^4.4.0 memoizerific: ^1.11.3 @@ -5446,21 +5456,21 @@ __metadata: optional: true react-dom: optional: true - checksum: ff602c8080c26a8513f76b9ba2cb2e287e31df598a5235aee8fa8c0337bb7e8e7d65620d03f2aa452801653c41d35ddf9dbfdb6a26d4f2b4d0cc7cff7b580915 + checksum: 4b1de32b85b305c22b976bae040c360063d6152c5077930953cc9cb565735a516c1d239b0670f9a8218264aabff9e8d6c4336fdb70698765009791f24c0fc867 languageName: node linkType: hard -"@storybook/addons@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/addons@npm:6.5.13" +"@storybook/addons@npm:6.5.16, @storybook/addons@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/addons@npm:6.5.16" dependencies: - "@storybook/api": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/api": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/router": 6.5.16 + "@storybook/theming": 6.5.16 "@types/webpack-env": ^1.16.0 core-js: ^3.8.2 global: ^4.4.0 @@ -5468,43 +5478,21 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 28589da00e8a26b44d4ed8a1938fe934187a85b187e2a0dcd3e6d114460ed5a07fbfe0a89a4d899739767b379015cbabadd47c5c266457922a8c4255e3d769a4 + checksum: 0463150e4cf7bd2b2aaafdbaadfb4420e4e0a31eb651cfc1a2d7f4b4974caf67878712602474585dfa18f583000608598045594909959d2e9e2ec32ba004392d languageName: node linkType: hard -"@storybook/addons@npm:6.5.15, @storybook/addons@npm:^6.5.13": - version: 6.5.15 - resolution: "@storybook/addons@npm:6.5.15" +"@storybook/api@npm:6.5.16, @storybook/api@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/api@npm:6.5.16" dependencies: - "@storybook/api": 6.5.15 - "@storybook/channels": 6.5.15 - "@storybook/client-logger": 6.5.15 - "@storybook/core-events": 6.5.15 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.15 - "@storybook/theming": 6.5.15 - "@types/webpack-env": ^1.16.0 - core-js: ^3.8.2 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 9de4cb9ff51cde37c456a0315f47c751daf4412a8d90321b5249a9b05f48a44dc48f01bbf83c9f369f63232da423d58ed47e4c03d50d16a8835d372022095b70 - languageName: node - linkType: hard - -"@storybook/api@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/api@npm:6.5.13" - dependencies: - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.13 + "@storybook/router": 6.5.16 "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 global: ^4.4.0 @@ -5518,59 +5506,31 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: dd7c8db0cdea2a47ab835c02217f10f99c54bfbf6d826deadf0b160ece4c94b1cb2558cfbaff4e4244c5c776095028a164762bd8de19fcfe10ae318fe0a3fbb4 + checksum: c873189ac1e501825d647903baa125899c492cee962cb86ebb7455110bd09194eeb6943f5c58a1f808ce4ee2e20e305f5604a4e60b07003c82a6fc6ceaee5ea9 languageName: node linkType: hard -"@storybook/api@npm:6.5.15, @storybook/api@npm:^6.5.13": - version: 6.5.15 - resolution: "@storybook/api@npm:6.5.15" - dependencies: - "@storybook/channels": 6.5.15 - "@storybook/client-logger": 6.5.15 - "@storybook/core-events": 6.5.15 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/router": 6.5.15 - "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.15 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - store2: ^2.12.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: cebf1b70309c9c4a135c4ad8d3ebd85d01cfa4942e43231831e67514604199d3ed26395bbe0f89954718498a800085bd7d6eaef61c5d702e3a669532a227bd93 - languageName: node - linkType: hard - -"@storybook/builder-webpack4@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/builder-webpack4@npm:6.5.13" +"@storybook/builder-webpack4@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/builder-webpack4@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/channel-postmessage": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/core-events": 6.5.13 - "@storybook/node-logger": 6.5.13 - "@storybook/preview-web": 6.5.13 - "@storybook/router": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/channel-postmessage": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/core-events": 6.5.16 + "@storybook/node-logger": 6.5.16 + "@storybook/preview-web": 6.5.16 + "@storybook/router": 6.5.16 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.13 - "@storybook/theming": 6.5.13 - "@storybook/ui": 6.5.13 + "@storybook/store": 6.5.16 + "@storybook/theming": 6.5.16 + "@storybook/ui": 6.5.16 "@types/node": ^14.0.10 || ^16.0.0 "@types/webpack": ^4.41.26 autoprefixer: ^9.8.6 @@ -5607,30 +5567,30 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: a95fea3951479d7724155a2ddbf2b04a8bfc0e7fddbf8415caed508b94ad71f7dc8d5d25464061ef26f3b4670f49f6ed40198b48b3f646d7af17d8daee5e89cb + checksum: 5e9137c390db00b4e166df3ca730eb1748f6bac92c841f3f75c37ad5277d6f5565f899de3bb0357fc51ce6821c8a8a8adba724e3dd7a3d1cc80816e09e5b7128 languageName: node linkType: hard "@storybook/builder-webpack5@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/builder-webpack5@npm:6.5.13" + version: 6.5.16 + resolution: "@storybook/builder-webpack5@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/channel-postmessage": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/core-events": 6.5.13 - "@storybook/node-logger": 6.5.13 - "@storybook/preview-web": 6.5.13 - "@storybook/router": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/channel-postmessage": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/core-events": 6.5.16 + "@storybook/node-logger": 6.5.16 + "@storybook/preview-web": 6.5.16 + "@storybook/router": 6.5.16 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.13 - "@storybook/theming": 6.5.13 + "@storybook/store": 6.5.16 + "@storybook/theming": 6.5.16 "@types/node": ^14.0.10 || ^16.0.0 babel-loader: ^8.0.0 babel-plugin-named-exports-order: ^0.0.2 @@ -5659,71 +5619,60 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: f980ab5c832bac9584f80eb0229934bb58ceb4cf24f756043acea4cb397f52f7af49c1fd53ac897aefb5ffc9c808bcb8a0c4867afd2c2a21b7ba2f0a56ae0089 + checksum: 0a6631f307c5ac56423860216d42ed95757906b004e949ed3dc2cce4f81d83d38de5cddbae65a0e65083eece6e4e8af05f6aabf5d78a80a7a7f62cf157a4e577 languageName: node linkType: hard -"@storybook/channel-postmessage@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/channel-postmessage@npm:6.5.13" +"@storybook/channel-postmessage@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/channel-postmessage@npm:6.5.16" dependencies: - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 core-js: ^3.8.2 global: ^4.4.0 qs: ^6.10.0 telejson: ^6.0.8 - checksum: 8d6ccfff2aeafaae30b5fc1af856be8d06b3703b96841ecc0d70959e51542514901763e1a291e1d0278afe31b23cc5c0a5b351994f321e9bd03490be5b51e2d0 + checksum: d3560d81dbf4710cc23b227c12be328d87e627581afcb5fec959f1e795fb2b5824db2a7f03a4ddcd185ec9a37a7025415d8bb43b7a245f2466395908eb3e9bc3 languageName: node linkType: hard -"@storybook/channel-websocket@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/channel-websocket@npm:6.5.13" +"@storybook/channel-websocket@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/channel-websocket@npm:6.5.16" dependencies: - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 core-js: ^3.8.2 global: ^4.4.0 telejson: ^6.0.8 - checksum: 16e3b1a51a1af093f6c78ab7ca9c4c69ed05b45fd9bbdefb3050809e92064ccbf7a46f6800d21df2555e5d110d64735dd8d35155e54c3118fa7b4efe6b3b0457 + checksum: 355c85f22d7cc65764871852debe347c43c3fe92d6a0caa64aecbe2dce78d4bf73b98e997099f9e4e7c204ad5821b979939b0700e446fa26478c1e1ba48e7380 languageName: node linkType: hard -"@storybook/channels@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/channels@npm:6.5.13" +"@storybook/channels@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/channels@npm:6.5.16" dependencies: core-js: ^3.8.2 ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 - checksum: 5b8881a2799a4c5ceafea40bc2c8bad1a31649036341eec8da5a77acf79a9d610afeaa5b4ed5d06022ed3c74cb9562dcfc5046d62fd8d27cd65bcba09aa5e903 + checksum: 3d7f7bc19ed7b250976e00e02ab544408806b439106bed18a5db9815612f6c5df9bdf7c1a97b5a40ba3194184ebe7e4c75e2bca5496025d6b26afefa95cfccbd languageName: node linkType: hard -"@storybook/channels@npm:6.5.15": - version: 6.5.15 - resolution: "@storybook/channels@npm:6.5.15" +"@storybook/client-api@npm:6.5.16, @storybook/client-api@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/client-api@npm:6.5.16" dependencies: - core-js: ^3.8.2 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - checksum: 7963c34246b3cc84bb6fb0965834110d9b839a5c32cced0756948e4e88fb8bf23a0d584723abbab6d30a6282fa1023017bb82eba68c23389652c77d8d33cb4f9 - languageName: node - linkType: hard - -"@storybook/client-api@npm:6.5.13, @storybook/client-api@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/client-api@npm:6.5.13" - dependencies: - "@storybook/addons": 6.5.13 - "@storybook/channel-postmessage": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/channel-postmessage": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.13 + "@storybook/store": 6.5.16 "@types/qs": ^6.9.5 "@types/webpack-env": ^1.16.0 core-js: ^3.8.2 @@ -5740,37 +5689,27 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: b0af25786b9144a55ebaa7754dd1b3701f5f8796770eaf59e7bc6d21ada12911fcbe4bf0da037d01bdda2c46138f265a948befe1f3de356fdc0ae3af80973388 + checksum: a62276fa67d2c3cc766ea9145d3798c0c8ef3f9de9fb18e7c43d67e39226f47a2546c4319ccc6075545df65dc4fc65bdb97e904062daf426be6534767eacada6 languageName: node linkType: hard -"@storybook/client-logger@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/client-logger@npm:6.5.13" +"@storybook/client-logger@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/client-logger@npm:6.5.16" dependencies: core-js: ^3.8.2 global: ^4.4.0 - checksum: 0252d9364a0b2a8faae588fdb29aaf458f660904c330ec7af790f63a668710926ece8f087f58f9b1bebb052e2fe517b8b74867e7500567499cc710ab71ccbbab + checksum: 0a86959b1bacb1b893e282173b48afe9c857b8cdc67a47ad87a7f11ba7dbc15ebc4f0d05c07dffb988e0cd3e1de0f09f300ee06c66afe4c50e9be83aaed75971 languageName: node linkType: hard -"@storybook/client-logger@npm:6.5.15": - version: 6.5.15 - resolution: "@storybook/client-logger@npm:6.5.15" +"@storybook/components@npm:6.5.16, @storybook/components@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/components@npm:6.5.16" dependencies: - core-js: ^3.8.2 - global: ^4.4.0 - checksum: cee16aea089b60b33ad643bde5e0d62274230d38e2033f0bfd0780fc092bc24b5acff63a6c569c9db989e59b89518ec964d0665a51548450716c4c50d3a3e66e - languageName: node - linkType: hard - -"@storybook/components@npm:6.5.13, @storybook/components@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/components@npm:6.5.13" - dependencies: - "@storybook/client-logger": 6.5.13 + "@storybook/client-logger": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 memoizerific: ^1.11.3 qs: ^6.10.0 @@ -5779,24 +5718,24 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 5d01c0f445f6574ccadcfa79afd99c078bd1f81d65e59186361100dc57bd73ccbb877e5a8bbc49dd6551bce1b32fbe6f135c2bea15c0126a83faf222cfaed878 + checksum: 1caf822bf1293ca043822f1c77f05c0f01631e8a61adad6bc4651ba9be78c8f4822ba0905e39c8feaa3fb44ae10422e9ccd3004348b18531fb82c54cfcea4fa9 languageName: node linkType: hard -"@storybook/core-client@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/core-client@npm:6.5.13" +"@storybook/core-client@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/core-client@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/channel-postmessage": 6.5.13 - "@storybook/channel-websocket": 6.5.13 - "@storybook/client-api": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/channel-postmessage": 6.5.16 + "@storybook/channel-websocket": 6.5.16 + "@storybook/client-api": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/preview-web": 6.5.13 - "@storybook/store": 6.5.13 - "@storybook/ui": 6.5.13 + "@storybook/preview-web": 6.5.16 + "@storybook/store": 6.5.16 + "@storybook/ui": 6.5.16 airbnb-js-shims: ^2.2.1 ansi-to-html: ^0.6.11 core-js: ^3.8.2 @@ -5814,13 +5753,13 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: c4350b1b579f0781a239fdede79f1d0975e297ecb61ba4096834d62bd553420615231dc9146c446d0178088e83863fd9dc720fbb4485b5779fac7d99ce3eeb9e + checksum: 467710777ddd740c431cf65035ecc489daae2fc5f4844a40b7339b806535e239140f40442a0e1d89356e107169c39d9e84d726c01982ed4609c043b6861e0778 languageName: node linkType: hard -"@storybook/core-common@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/core-common@npm:6.5.13" +"@storybook/core-common@npm:6.5.16, @storybook/core-common@npm:^6.5.0": + version: 6.5.16 + resolution: "@storybook/core-common@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 "@babel/plugin-proposal-class-properties": ^7.12.1 @@ -5844,7 +5783,7 @@ __metadata: "@babel/preset-react": ^7.12.10 "@babel/preset-typescript": ^7.12.7 "@babel/register": ^7.12.1 - "@storybook/node-logger": 6.5.13 + "@storybook/node-logger": 6.5.16 "@storybook/semver": ^7.3.2 "@types/node": ^14.0.10 || ^16.0.0 "@types/pretty-hrtime": ^1.0.0 @@ -5861,7 +5800,7 @@ __metadata: glob: ^7.1.6 handlebars: ^4.7.7 interpret: ^2.2.0 - json5: ^2.1.3 + json5: ^2.2.3 lazy-universal-dotenv: ^3.0.1 picomatch: ^2.3.0 pkg-dir: ^5.0.0 @@ -5878,108 +5817,35 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 369fbe41e9ac657410a8e7fb4668be0e77c50b84c29b352397cc26b72d79397a7e84dcbf7a94f2d02d819d395a66e30a3915de40e85936d7b7dc50bb426aeabb + checksum: 886a701876599939950c3c98e306b373cd026c7b995ca08d88475b3f35624a53763459d6b202728ec703e99126813a254b956c2d0fe7e85f99dcb5765a999b19 languageName: node linkType: hard -"@storybook/core-common@npm:^6.5.0": - version: 6.5.15 - resolution: "@storybook/core-common@npm:6.5.15" - dependencies: - "@babel/core": ^7.12.10 - "@babel/plugin-proposal-class-properties": ^7.12.1 - "@babel/plugin-proposal-decorators": ^7.12.12 - "@babel/plugin-proposal-export-default-from": ^7.12.1 - "@babel/plugin-proposal-nullish-coalescing-operator": ^7.12.1 - "@babel/plugin-proposal-object-rest-spread": ^7.12.1 - "@babel/plugin-proposal-optional-chaining": ^7.12.7 - "@babel/plugin-proposal-private-methods": ^7.12.1 - "@babel/plugin-proposal-private-property-in-object": ^7.12.1 - "@babel/plugin-syntax-dynamic-import": ^7.8.3 - "@babel/plugin-transform-arrow-functions": ^7.12.1 - "@babel/plugin-transform-block-scoping": ^7.12.12 - "@babel/plugin-transform-classes": ^7.12.1 - "@babel/plugin-transform-destructuring": ^7.12.1 - "@babel/plugin-transform-for-of": ^7.12.1 - "@babel/plugin-transform-parameters": ^7.12.1 - "@babel/plugin-transform-shorthand-properties": ^7.12.1 - "@babel/plugin-transform-spread": ^7.12.1 - "@babel/preset-env": ^7.12.11 - "@babel/preset-react": ^7.12.10 - "@babel/preset-typescript": ^7.12.7 - "@babel/register": ^7.12.1 - "@storybook/node-logger": 6.5.15 - "@storybook/semver": ^7.3.2 - "@types/node": ^14.0.10 || ^16.0.0 - "@types/pretty-hrtime": ^1.0.0 - babel-loader: ^8.0.0 - babel-plugin-macros: ^3.0.1 - babel-plugin-polyfill-corejs3: ^0.1.0 - chalk: ^4.1.0 - core-js: ^3.8.2 - express: ^4.17.1 - file-system-cache: ^1.0.5 - find-up: ^5.0.0 - fork-ts-checker-webpack-plugin: ^6.0.4 - fs-extra: ^9.0.1 - glob: ^7.1.6 - handlebars: ^4.7.7 - interpret: ^2.2.0 - json5: ^2.1.3 - lazy-universal-dotenv: ^3.0.1 - picomatch: ^2.3.0 - pkg-dir: ^5.0.0 - pretty-hrtime: ^1.0.3 - resolve-from: ^5.0.0 - slash: ^3.0.0 - telejson: ^6.0.8 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - webpack: 4 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 9c19c348137bea23295ff330d3a62d3551b6a8a2933f254f3f1cace4ef05e46b6c97e0cbca67cc5be45164e223d5ff52eced54b76564891c8a2dd085e3be4cc4 - languageName: node - linkType: hard - -"@storybook/core-events@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/core-events@npm:6.5.13" +"@storybook/core-events@npm:6.5.16, @storybook/core-events@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/core-events@npm:6.5.16" dependencies: core-js: ^3.8.2 - checksum: 2afeaf5fd658a4e9eedb9ad458ba0bcc73ad4ae5ba0e9971434818258db01d9b48b604d4db396ebfc1e1571dace3f6659e9ed61ac35428a792a4e24bbc08b29c + checksum: 1844bdabfb7828af7ddd54129fbb321bf65d8b65459eaac99c8f3f94c7c2f0ee000468362758076444083f863a3bc835ecd1e4f2128524eb5c00c8a576473bc9 languageName: node linkType: hard -"@storybook/core-events@npm:6.5.15, @storybook/core-events@npm:^6.5.13": - version: 6.5.15 - resolution: "@storybook/core-events@npm:6.5.15" - dependencies: - core-js: ^3.8.2 - checksum: 89916720933bc4de0b1f25c7cb1b8580d3cdd213b21a360f18ebd0b790cce2c641696282fee29bbc482ab2cc656271b2f0569f79559d90fb01fb16473421e79e - languageName: node - linkType: hard - -"@storybook/core-server@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/core-server@npm:6.5.13" +"@storybook/core-server@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/core-server@npm:6.5.16" dependencies: "@discoveryjs/json-ext": ^0.5.3 - "@storybook/builder-webpack4": 6.5.13 - "@storybook/core-client": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/builder-webpack4": 6.5.16 + "@storybook/core-client": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/csf-tools": 6.5.13 - "@storybook/manager-webpack4": 6.5.13 - "@storybook/node-logger": 6.5.13 + "@storybook/csf-tools": 6.5.16 + "@storybook/manager-webpack4": 6.5.16 + "@storybook/node-logger": 6.5.16 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.13 - "@storybook/telemetry": 6.5.13 + "@storybook/store": 6.5.16 + "@storybook/telemetry": 6.5.16 "@types/node": ^14.0.10 || ^16.0.0 "@types/node-fetch": ^2.5.7 "@types/pretty-hrtime": ^1.0.0 @@ -6023,16 +5889,16 @@ __metadata: optional: true typescript: optional: true - checksum: 142b13ef4fef21a68c8255f35f42ca5c3b9f636b51986f61dc6ae95485788d0f581552604b8a4a796e7cd2ad9548b87317ac9647ea44be58f64b91c440bb71ea + checksum: 2027adba39b2e0a5c3664241f48ec256a92866755aace96f3b8e2064b50237bbcd4e814bc58a1084006baae41c48d7d0eccefc9867d84e17d68d7f969e65f149 languageName: node linkType: hard -"@storybook/core@npm:6.5.13, @storybook/core@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/core@npm:6.5.13" +"@storybook/core@npm:6.5.16, @storybook/core@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/core@npm:6.5.16" dependencies: - "@storybook/core-client": 6.5.13 - "@storybook/core-server": 6.5.13 + "@storybook/core-client": 6.5.16 + "@storybook/core-server": 6.5.16 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -6044,13 +5910,13 @@ __metadata: optional: true typescript: optional: true - checksum: e0dbe5d8d52f2a12ab63db965d5d15ee671029a03b7204756954e2bc3253b560c8e430aaab5559ccbddcfd3e97d2bc1c0c58ed370aa593912724402aa86996b8 + checksum: f1732338741692007230a351419ef3aa4e387810d7d0c0e6ffb1159e1de4d757199f2b543cf4f6413fc40acda514b908d2fd9b3e0d56e3f6cec1e3a82c2fcc10 languageName: node linkType: hard -"@storybook/csf-tools@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/csf-tools@npm:6.5.13" +"@storybook/csf-tools@npm:6.5.16, @storybook/csf-tools@npm:^6.5.0": + version: 6.5.16 + resolution: "@storybook/csf-tools@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 "@babel/generator": ^7.12.11 @@ -6071,34 +5937,7 @@ __metadata: peerDependenciesMeta: "@storybook/mdx2-csf": optional: true - checksum: 2b8a5bed04ea89084334742e1095c4565b0b7367b5126e3a9b6648224b59c2136a9d57cbb9067264fc3951e9db58df40b23b975170180d171cce35dfabf2a090 - languageName: node - linkType: hard - -"@storybook/csf-tools@npm:^6.5.0": - version: 6.5.15 - resolution: "@storybook/csf-tools@npm:6.5.15" - dependencies: - "@babel/core": ^7.12.10 - "@babel/generator": ^7.12.11 - "@babel/parser": ^7.12.11 - "@babel/plugin-transform-react-jsx": ^7.12.12 - "@babel/preset-env": ^7.12.11 - "@babel/traverse": ^7.12.11 - "@babel/types": ^7.12.11 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/mdx1-csf": ^0.0.1 - core-js: ^3.8.2 - fs-extra: ^9.0.1 - global: ^4.4.0 - regenerator-runtime: ^0.13.7 - ts-dedent: ^2.0.0 - peerDependencies: - "@storybook/mdx2-csf": ^0.0.3 - peerDependenciesMeta: - "@storybook/mdx2-csf": - optional: true - checksum: d7faafd175b232bb8fa6008ae6db5a40619a158ed7556686649dee665ac0cbbdb3cc404d2b9c0314ba7783c3f5baf1d87788f324d24136bd0f8cc671d573208b + checksum: ee71a47d90186c35fc1dbcb6ece2888ff4d730bde823bb1bd242d802b74045b482d2c469f3a91687b691b6f828ce449b182896d1912033846b9746457ee960ba languageName: node linkType: hard @@ -6120,34 +5959,34 @@ __metadata: languageName: node linkType: hard -"@storybook/docs-tools@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/docs-tools@npm:6.5.13" +"@storybook/docs-tools@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/docs-tools@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.13 + "@storybook/store": 6.5.16 core-js: ^3.8.2 doctrine: ^3.0.0 lodash: ^4.17.21 regenerator-runtime: ^0.13.7 - checksum: d3ad4674922025aaf6e4e2b7c2ac6f4eaec8f5692dc9a792a15d2d5e38dcd2e1c138daffb31a3da04da1e04c645b3cd8d921890f9ba318bfee7b6a12f263b48a + checksum: 6351c5b1cbe5820f0f0dfcc3e4e7da8cca3c8d73a06c5803e65cb86e9e81ccbae53cec8e1b579af0ac9a5bbb6d4b6ac03ffe26af2220dc5dfe8f065067f0e2d7 languageName: node linkType: hard -"@storybook/manager-webpack4@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/manager-webpack4@npm:6.5.13" +"@storybook/manager-webpack4@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/manager-webpack4@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 "@babel/plugin-transform-template-literals": ^7.12.1 "@babel/preset-react": ^7.12.10 - "@storybook/addons": 6.5.13 - "@storybook/core-client": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/node-logger": 6.5.13 - "@storybook/theming": 6.5.13 - "@storybook/ui": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/core-client": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/node-logger": 6.5.16 + "@storybook/theming": 6.5.16 + "@storybook/ui": 6.5.16 "@types/node": ^14.0.10 || ^16.0.0 "@types/webpack": ^4.41.26 babel-loader: ^8.0.0 @@ -6180,23 +6019,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 6645f30b6199d0badb2097aca16478e4d8bc88210b55e60c4da86962e8b0a3441128f1e696cddf8a535591920617a7abf5f1f9771dabc486479e76b8d4b20fbd + checksum: 873c871c822ecde30fbd95e9517549a18c5bb2de46d6160d6dcd7c1b5635fda2073b5bc4bd4d87e72de6e8df8bccf39b81f062e07cd7a23ffb4b43293e488fbb languageName: node linkType: hard "@storybook/manager-webpack5@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/manager-webpack5@npm:6.5.13" + version: 6.5.16 + resolution: "@storybook/manager-webpack5@npm:6.5.16" dependencies: "@babel/core": ^7.12.10 "@babel/plugin-transform-template-literals": ^7.12.1 "@babel/preset-react": ^7.12.10 - "@storybook/addons": 6.5.13 - "@storybook/core-client": 6.5.13 - "@storybook/core-common": 6.5.13 - "@storybook/node-logger": 6.5.13 - "@storybook/theming": 6.5.13 - "@storybook/ui": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/core-client": 6.5.16 + "@storybook/core-common": 6.5.16 + "@storybook/node-logger": 6.5.16 + "@storybook/theming": 6.5.16 + "@storybook/ui": 6.5.16 "@types/node": ^14.0.10 || ^16.0.0 babel-loader: ^8.0.0 case-sensitive-paths-webpack-plugin: ^2.3.0 @@ -6226,7 +6065,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 95e720d00e8869f8ec5e8a36f50e5da6aaecdc9a1ea306ae3d7b50f2f07b60a9eb5cb3787e88262c664c958b1f56b7f34e9bf027eb627a96d127b5771ff6a137 + checksum: 1349c6b2af9d0cebc3c35c929e2ea0f9ff8d12f7a04c30126160d9c89a45b92412218304abda9126cf96303a2d73fb288a689a191fec12b0189f19e5f2032977 languageName: node linkType: hard @@ -6249,51 +6088,38 @@ __metadata: languageName: node linkType: hard -"@storybook/node-logger@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/node-logger@npm:6.5.13" +"@storybook/node-logger@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/node-logger@npm:6.5.16" dependencies: "@types/npmlog": ^4.1.2 chalk: ^4.1.0 core-js: ^3.8.2 npmlog: ^5.0.1 pretty-hrtime: ^1.0.3 - checksum: bcd1d98822687580e39f27003e16c73e3c775cdfe6e9f8fd8fbe9f4626a82f3f63fe281f9c894f3917faa52202ccb8217916978032d27ba6dbfa9720064e7739 + checksum: 4ae47c03b6cec6b820e0e482e6f6675bf745fca5c124eb919240c0339b9f4a1b110c8fde7c5ddbc1748d3992773c61d37ba1f5c489b42279cf03517d4e1d51c5 languageName: node linkType: hard -"@storybook/node-logger@npm:6.5.15": - version: 6.5.15 - resolution: "@storybook/node-logger@npm:6.5.15" - dependencies: - "@types/npmlog": ^4.1.2 - chalk: ^4.1.0 - core-js: ^3.8.2 - npmlog: ^5.0.1 - pretty-hrtime: ^1.0.3 - checksum: 9c01127d3b57db7a85759d2f179afec0e1207c0754e80e22472e73468f831e1dafa2a5bf1047e54f92d47b5103325c157c14655208a6ddcdb8f9e7ee0b256e48 - languageName: node - linkType: hard - -"@storybook/postinstall@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/postinstall@npm:6.5.13" +"@storybook/postinstall@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/postinstall@npm:6.5.16" dependencies: core-js: ^3.8.2 - checksum: 87e57e55c7973ea5794b439484d6a99c078b816c0a865c989ae31979000abda6fcfe670671e999a36630b52a91d54e6c0d174b41410cf876e20db976e5a23f56 + checksum: 023a19a0681675ce51f4acebf068f372e8657520680c67171c0a1b458f6009d1e444daa5680eeae7efb1088df184fbee61008548a73131d976201961dad65266 languageName: node linkType: hard -"@storybook/preview-web@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/preview-web@npm:6.5.13" +"@storybook/preview-web@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/preview-web@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/channel-postmessage": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/channel-postmessage": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/store": 6.5.13 + "@storybook/store": 6.5.16 ansi-to-html: ^0.6.11 core-js: ^3.8.2 global: ^4.4.0 @@ -6307,7 +6133,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: d66d29667a936ee80d15de07bdeec0c6cb2a476fdaa59f262297f5c7dc774acb57e4779c2dd77e61f5a6d9974ac3359babe587a2cd9baf6aa7673ec949b3234d + checksum: 6161c96e9ee459ef93c3d972374ce339ae57d0c5fa25730007484e4824f79a34814110431db97031107558e5ce41259710f8a54564e8975db0215b78c5572a1b languageName: node linkType: hard @@ -6330,22 +6156,22 @@ __metadata: linkType: hard "@storybook/react@npm:^6.5.13": - version: 6.5.13 - resolution: "@storybook/react@npm:6.5.13" + version: 6.5.16 + resolution: "@storybook/react@npm:6.5.16" dependencies: "@babel/preset-flow": ^7.12.1 "@babel/preset-react": ^7.12.10 "@pmmmwh/react-refresh-webpack-plugin": ^0.5.3 - "@storybook/addons": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core": 6.5.13 - "@storybook/core-common": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core": 6.5.16 + "@storybook/core-common": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 - "@storybook/docs-tools": 6.5.13 - "@storybook/node-logger": 6.5.13 + "@storybook/docs-tools": 6.5.16 + "@storybook/node-logger": 6.5.16 "@storybook/react-docgen-typescript-plugin": 1.0.2-canary.6.9d540b91e815f8fc2f8829189deb00553559ff63.0 "@storybook/semver": ^7.3.2 - "@storybook/store": 6.5.13 + "@storybook/store": 6.5.16 "@types/estree": ^0.0.51 "@types/node": ^14.14.20 || ^16.0.0 "@types/webpack-env": ^1.16.0 @@ -6390,15 +6216,15 @@ __metadata: build-storybook: bin/build.js start-storybook: bin/index.js storybook-server: bin/index.js - checksum: 5a21e4e49a0aba7376dbaef5408e03537cf937d3025e735b45848bce7c9f476a025ca9af4260aa32982a3da668e14a217f66a0ec465ed820369ff2fab49b2ab3 + checksum: c5396e748ef13acdb2590dc15ff0b3d95d3599abd0c372786d707164d3f71e46836240195dcd6f4bce6f90d2792602f6d31373fc87e069ef3c73a63d1e9a1289 languageName: node linkType: hard -"@storybook/router@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/router@npm:6.5.13" +"@storybook/router@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/router@npm:6.5.16" dependencies: - "@storybook/client-logger": 6.5.13 + "@storybook/client-logger": 6.5.16 core-js: ^3.8.2 memoizerific: ^1.11.3 qs: ^6.10.0 @@ -6406,23 +6232,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: ca144b2f6e3a46d5ac9d449b068d0905e9c72939c8574f095d8d7f7307b172a0c5c13f56ff08d5d5bff540292d9ed13eeecc3a4e600e282ea31e70ed763b735a - languageName: node - linkType: hard - -"@storybook/router@npm:6.5.15": - version: 6.5.15 - resolution: "@storybook/router@npm:6.5.15" - dependencies: - "@storybook/client-logger": 6.5.15 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - qs: ^6.10.0 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: d5ac1ac0d161e53764411dc84febed3819c5cefe669f2933434bcdc25bf011f89d2df2a504af8bf77f454e6598a74c794a17d01aad734c6ebe28cc13c490fff9 + checksum: 2812b93997026b1d85f02072d04f18e98e24de288efb73402f8d15ececd390e13dc620ef011268e09986c629f497ffa03230c2431e89b4e37c01b70761be2c6d languageName: node linkType: hard @@ -6438,34 +6248,34 @@ __metadata: languageName: node linkType: hard -"@storybook/source-loader@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/source-loader@npm:6.5.13" +"@storybook/source-loader@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/source-loader@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/client-logger": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/client-logger": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 estraverse: ^5.2.0 global: ^4.4.0 - loader-utils: ^2.0.0 + loader-utils: ^2.0.4 lodash: ^4.17.21 prettier: ">=2.2.1 <=2.3.0" regenerator-runtime: ^0.13.7 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 93da14a367a954f664d233f64bd9e7d983475e489b8fbe5c90b723ff793279ab899d86f967eb6882f7997296f4286f6f5c82c17ca83e9294c91f8e4aa0ec0a1d + checksum: a299acdd6f36add3222ef294e1118b7b1f38c2cd2b4648ebf9e1803a3ccf532c147dbe643a527915b570eb3ce36c4a17ca2b3566fa58a2a0a7821f0849ec3e07 languageName: node linkType: hard -"@storybook/store@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/store@npm:6.5.13" +"@storybook/store@npm:6.5.16, @storybook/store@npm:^6.5.0": + version: 6.5.16 + resolution: "@storybook/store@npm:6.5.16" dependencies: - "@storybook/addons": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/core-events": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/core-events": 6.5.16 "@storybook/csf": 0.0.2--canary.4566f4d.1 core-js: ^3.8.2 fast-deep-equal: ^3.1.3 @@ -6481,33 +6291,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 69f55927bd3569ec9d87f4351879fd07654d51524a0f9da05c64c7f7f3b50e33024f1554fa59668997e47189e9838b85b691de422ab539bd71126b56922d9381 - languageName: node - linkType: hard - -"@storybook/store@npm:^6.5.0": - version: 6.5.15 - resolution: "@storybook/store@npm:6.5.15" - dependencies: - "@storybook/addons": 6.5.15 - "@storybook/client-logger": 6.5.15 - "@storybook/core-events": 6.5.15 - "@storybook/csf": 0.0.2--canary.4566f4d.1 - core-js: ^3.8.2 - fast-deep-equal: ^3.1.3 - global: ^4.4.0 - lodash: ^4.17.21 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - slash: ^3.0.0 - stable: ^0.1.8 - synchronous-promise: ^2.0.15 - ts-dedent: ^2.0.0 - util-deprecate: ^1.0.2 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 918c3ed8c7a55ae4bf8bcb3a108d99a9d077c951b3f386cb0f8939d2eed7c9a9a2000075b341d5c934c0308c24287fc5cd110042a384411c25cec7632dfa5abb + checksum: f438fb020af240e23348742b2936a326bef1f7ffd489fe9f39cfd516310ab592a11609205fdacd11090b0c0b6bc72c75dff986085a6a97acc5efa64829a49309 languageName: node linkType: hard @@ -6527,12 +6311,12 @@ __metadata: languageName: node linkType: hard -"@storybook/telemetry@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/telemetry@npm:6.5.13" +"@storybook/telemetry@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/telemetry@npm:6.5.16" dependencies: - "@storybook/client-logger": 6.5.13 - "@storybook/core-common": 6.5.13 + "@storybook/client-logger": 6.5.16 + "@storybook/core-common": 6.5.16 chalk: ^4.1.0 core-js: ^3.8.2 detect-package-manager: ^2.0.1 @@ -6543,13 +6327,13 @@ __metadata: nanoid: ^3.3.1 read-pkg-up: ^7.0.1 regenerator-runtime: ^0.13.7 - checksum: 94ad6fb58b09c8073600ad95b2a48f476524ea7bc6155aee8e9682966a99ac875a9923ee6512252238e8c56eeef725a712e94ba87e1060d7dca9ab196a9051a6 + checksum: 21eef590b04db8ee85b0b1d875d8646e26492b3e90538a248314f92d6ab0642ec65db09c5d2bc0d7f547f0fa6b83ca4442bdc115b400861360e02d8cf179497e languageName: node linkType: hard "@storybook/test-runner@npm:^0.9.2": - version: 0.9.2 - resolution: "@storybook/test-runner@npm:0.9.2" + version: 0.9.4 + resolution: "@storybook/test-runner@npm:0.9.4" dependencies: "@babel/core": ^7.18.13 "@babel/generator": ^7.18.13 @@ -6565,6 +6349,7 @@ __metadata: can-bind-to-host: ^1.1.1 commander: ^9.0.0 expect-playwright: ^0.8.0 + glob: ^8.1.0 jest: ^28.0.0 jest-circus: ^28.0.0 jest-environment-node: ^28.0.0 @@ -6582,53 +6367,38 @@ __metadata: ts-dedent: ^2.0.0 bin: test-storybook: bin/test-storybook.js - checksum: 0805ca46473b2f01e9c525cfe988308166ab2633afe88e809b367bf50d5ae0b8bfeecd3971b416602570287720165f82feaa005b708184c0987477de05349e16 + checksum: f39ee856379c2c255c4dec60df4186049ab0312bd11a61dc19eba17c0b208fabbc618fd832adb0e82afe0449692994b7039267505a684d8a3fcac7310a99612d languageName: node linkType: hard -"@storybook/theming@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/theming@npm:6.5.13" +"@storybook/theming@npm:6.5.16, @storybook/theming@npm:^6.5.13": + version: 6.5.16 + resolution: "@storybook/theming@npm:6.5.16" dependencies: - "@storybook/client-logger": 6.5.13 + "@storybook/client-logger": 6.5.16 core-js: ^3.8.2 memoizerific: ^1.11.3 regenerator-runtime: ^0.13.7 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: f7a59c7d81b87f3fbf65c5eb72f5db5a5c1707236c92350d46bc7e1dcf848d57522ca5dcdd4fe19336d4611bd20727e0d900c4b591d2e8e1dd8a754cb9c56aa3 + checksum: 349affa5c5208240291a5d24c73d852e220bfaf36b8fda70564aec1cac6070248ce7566ccb755c55a6ce0844ab2bbfd55881f6f788240b38cb407714e393c6f3 languageName: node linkType: hard -"@storybook/theming@npm:6.5.15, @storybook/theming@npm:^6.5.13": - version: 6.5.15 - resolution: "@storybook/theming@npm:6.5.15" +"@storybook/ui@npm:6.5.16": + version: 6.5.16 + resolution: "@storybook/ui@npm:6.5.16" dependencies: - "@storybook/client-logger": 6.5.15 - core-js: ^3.8.2 - memoizerific: ^1.11.3 - regenerator-runtime: ^0.13.7 - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 84d09b6bdd0a00246b207ef4307fc0ecbb5861792547a070ed45470335c323f18ba607cd1d3f0a5cea7e979dd73315cdb091548fe70e5946c1593d8c691be7ba - languageName: node - linkType: hard - -"@storybook/ui@npm:6.5.13": - version: 6.5.13 - resolution: "@storybook/ui@npm:6.5.13" - dependencies: - "@storybook/addons": 6.5.13 - "@storybook/api": 6.5.13 - "@storybook/channels": 6.5.13 - "@storybook/client-logger": 6.5.13 - "@storybook/components": 6.5.13 - "@storybook/core-events": 6.5.13 - "@storybook/router": 6.5.13 + "@storybook/addons": 6.5.16 + "@storybook/api": 6.5.16 + "@storybook/channels": 6.5.16 + "@storybook/client-logger": 6.5.16 + "@storybook/components": 6.5.16 + "@storybook/core-events": 6.5.16 + "@storybook/router": 6.5.16 "@storybook/semver": ^7.3.2 - "@storybook/theming": 6.5.13 + "@storybook/theming": 6.5.16 core-js: ^3.8.2 memoizerific: ^1.11.3 qs: ^6.10.0 @@ -6637,7 +6407,7 @@ __metadata: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: d2866987f51d945246776d42628bc2b79e701f1e59fd511bb1e590c83c4b9d9adee5c7e1a11ecb2ef12b9192613e2d576694bbc9aeb1df5545567f2aa44c0145 + checksum: bfebcf4d56dc5fd6024eaa08fe50aecc3c348670b7c0ec6b467680d64d525421580b9c98839bcaf1e2a9e69b78478a21c9943a9a392b49a0405b4784038b2eba languageName: node linkType: hard @@ -11377,10 +11147,11 @@ __metadata: languageName: node linkType: hard -"cacache@npm:^15.0.4, cacache@npm:^15.0.5": - version: 15.0.5 - resolution: "cacache@npm:15.0.5" +"cacache@npm:^15.0.5": + version: 15.3.0 + resolution: "cacache@npm:15.3.0" dependencies: + "@npmcli/fs": ^1.0.0 "@npmcli/move-file": ^1.0.1 chownr: ^2.0.0 fs-minipass: ^2.0.0 @@ -11395,10 +11166,10 @@ __metadata: p-map: ^4.0.0 promise-inflight: ^1.0.1 rimraf: ^3.0.2 - ssri: ^8.0.0 + ssri: ^8.0.1 tar: ^6.0.2 unique-filename: ^1.1.1 - checksum: 911436a9df4caf868c91b75d58c8ba7c958dd4a1882cf18daeac003f46e81d79c11196affe8d86dd9137194466cc2f45b61707b5fbe5fea3d9b8e9220f669e48 + checksum: a07327c27a4152c04eb0a831c63c00390d90f94d51bb80624a66f4e14a6b6360bbf02a84421267bd4d00ca73ac9773287d8d7169e8d2eafe378d2ce140579db8 languageName: node linkType: hard @@ -12822,23 +12593,23 @@ __metadata: linkType: hard "copy-webpack-plugin@npm:^6.0.3": - version: 6.0.3 - resolution: "copy-webpack-plugin@npm:6.0.3" + version: 6.4.1 + resolution: "copy-webpack-plugin@npm:6.4.1" dependencies: - cacache: ^15.0.4 + cacache: ^15.0.5 fast-glob: ^3.2.4 find-cache-dir: ^3.3.1 glob-parent: ^5.1.1 globby: ^11.0.1 loader-utils: ^2.0.0 normalize-path: ^3.0.0 - p-limit: ^3.0.1 - schema-utils: ^2.7.0 - serialize-javascript: ^4.0.0 + p-limit: ^3.0.2 + schema-utils: ^3.0.0 + serialize-javascript: ^5.0.1 webpack-sources: ^1.4.3 peerDependencies: webpack: ^4.37.0 || ^5.0.0 - checksum: 7867a1398cebf11b16662b6776e01603e8e2cfb31cf36a8fec9da390471898693f14d3a3f8cbe092d7ab1bec393d7a820097d9adcedd7ca96ff2e1f98ea9c0f6 + checksum: b597938a6bb4a272ee94604e90088f1f9452309b5d41f377f81090ec69968e984c77764da76c9ad07c8692ec018abbe815fd685b9e74b57e2dd1f3180ada60ce languageName: node linkType: hard @@ -18058,16 +17829,16 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.1": - version: 8.0.3 - resolution: "glob@npm:8.0.3" +"glob@npm:^8.0.1, glob@npm:^8.1.0": + version: 8.1.0 + resolution: "glob@npm:8.1.0" dependencies: fs.realpath: ^1.0.0 inflight: ^1.0.4 inherits: 2 minimatch: ^5.0.1 once: ^1.3.0 - checksum: 50bcdea19d8e79d8de5f460b1939ffc2b3299eac28deb502093fdca22a78efebc03e66bf54f0abc3d3d07d8134d19a32850288b7440d77e072aa55f9d33b18c5 + checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 languageName: node linkType: hard @@ -22307,7 +22078,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2, json5@npm:^2.1.3, json5@npm:^2.2.2": +"json5@npm:^2.1.2, json5@npm:^2.1.3, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -23141,7 +22912,7 @@ __metadata: languageName: node linkType: hard -"loader-utils@npm:^2.0.0": +"loader-utils@npm:^2.0.0, loader-utils@npm:^2.0.4": version: 2.0.4 resolution: "loader-utils@npm:2.0.4" dependencies: @@ -26316,7 +26087,7 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^3.0.1, p-limit@npm:^3.0.2, p-limit@npm:^3.1.0": +"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0": version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: @@ -31385,12 +31156,12 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^8.0.0": - version: 8.0.0 - resolution: "ssri@npm:8.0.0" +"ssri@npm:^8.0.1": + version: 8.0.1 + resolution: "ssri@npm:8.0.1" dependencies: minipass: ^3.1.1 - checksum: 50085886f4f476f14ef40c063abca59b9855f773cb3962da4e873f2a010b4fc73b36b4b15f6439b816ee6bee36da30d1b6046cf5412a294fa316828de3ec8d9f + checksum: bc447f5af814fa9713aa201ec2522208ae0f4d8f3bda7a1f445a797c7b929a02720436ff7c478fb5edc4045adb02b1b88d2341b436a80798734e2494f1067b36 languageName: node linkType: hard From 2943ec3310218d02a321829ec6527f256ec57de7 Mon Sep 17 00:00:00 2001 From: legobeat <109787230+legobeat@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:07:04 +0000 Subject: [PATCH 49/60] devDeps: bumps source-map related dependencies (#18830) * devDeps: bumps source-map related dependencies * update lavamoat build policy --- lavamoat/build-system/policy.json | 39 ++++-------------- yarn.lock | 68 ++++++++++--------------------- 2 files changed, 28 insertions(+), 79 deletions(-) diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index aef3358f3..5db80bb56 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -4106,8 +4106,8 @@ "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic": { "packages": { "@babel/register>clone-deep>kind-of": true, - "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic>math-random": true, - "gulp>undertaker>bach>array-last>is-number": true + "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic>is-number": true, + "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic>math-random": true } }, "gulp-watch>anymatch>micromatch>braces>expand-range>fill-range>randomatic>math-random": { @@ -4388,20 +4388,10 @@ }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values": { "packages": { - "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>is-number": true, + "gulp-watch>chokidar>braces>fill-range>is-number": true, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>kind-of": true } }, - "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>is-number": { - "packages": { - "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>is-number>kind-of": true - } - }, - "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>is-number>kind-of": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, "gulp-watch>chokidar>braces>snapdragon>base>cache-base>has-value>has-values>kind-of": { "packages": { "browserify>insert-module-globals>is-buffer": true @@ -5146,24 +5136,14 @@ }, "packages": { "gulp-watch>chokidar>braces>extend-shallow": true, - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, + "gulp-watch>chokidar>braces>fill-range>is-number": true, "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": true, "stylelint>@stylelint/postcss-markdown>remark>remark-parse>repeat-string": true } }, - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": { - "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": true - } - }, - "gulp>glob-watcher>chokidar>braces>fill-range>is-number>kind-of": { - "packages": { - "browserify>insert-module-globals>is-buffer": true - } - }, "gulp>glob-watcher>chokidar>braces>fill-range>to-regex-range": { "packages": { - "gulp>glob-watcher>chokidar>braces>fill-range>is-number": true, + "gulp-watch>chokidar>braces>fill-range>is-number": true, "stylelint>@stylelint/postcss-markdown>remark>remark-parse>repeat-string": true } }, @@ -5313,7 +5293,6 @@ "gulp>gulp-cli>matchdep>micromatch>fragment-cache": true, "gulp>gulp-cli>matchdep>micromatch>nanomatch>define-property": true, "gulp>gulp-cli>matchdep>micromatch>nanomatch>extend-shallow": true, - "gulp>gulp-cli>matchdep>micromatch>nanomatch>is-odd": true, "gulp>gulp-cli>matchdep>micromatch>regex-not": true, "nyc>spawn-wrap>is-windows": true } @@ -5335,11 +5314,6 @@ "@babel/register>clone-deep>is-plain-object": true } }, - "gulp>gulp-cli>matchdep>micromatch>nanomatch>is-odd": { - "packages": { - "gulp>undertaker>bach>array-last>is-number": true - } - }, "gulp>gulp-cli>matchdep>micromatch>regex-not": { "packages": { "gulp-watch>chokidar>braces>to-regex>safe-regex": true, @@ -5429,7 +5403,7 @@ }, "gulp>undertaker>bach>array-initial": { "packages": { - "gulp>undertaker>bach>array-last>is-number": true, + "gulp>undertaker>bach>array-initial>is-number": true, "gulp>undertaker>object.defaults>array-slice": true } }, @@ -6595,6 +6569,7 @@ "url.resolve": true }, "globals": { + "TextDecoder": true, "setImmediate": true }, "packages": { diff --git a/yarn.lock b/yarn.lock index 9ef142377..6c0a33373 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8921,13 +8921,6 @@ __metadata: languageName: node linkType: hard -"amdefine@npm:>=0.0.4": - version: 1.0.1 - resolution: "amdefine@npm:1.0.1" - checksum: 9d4e15b94641643a9385b2841b4cb2bcf4e8e2f741ea4bd475c93ad7bab261ad4ed827a32e9c549b38b98759c4526c173ae4e6dde8caeb75ee5cebedc9863762 - languageName: node - linkType: hard - "ansi-align@npm:^2.0.0": version: 2.0.0 resolution: "ansi-align@npm:2.0.0" @@ -9647,7 +9640,7 @@ __metadata: languageName: node linkType: hard -"atob@npm:^2.0.0, atob@npm:^2.1.2": +"atob@npm:^2.1.2": version: 2.1.2 resolution: "atob@npm:2.1.2" bin: @@ -13028,14 +13021,14 @@ __metadata: linkType: hard "css@npm:^2.0.0": - version: 2.2.3 - resolution: "css@npm:2.2.3" + version: 2.2.4 + resolution: "css@npm:2.2.4" dependencies: - inherits: ^2.0.1 - source-map: ^0.1.38 - source-map-resolve: ^0.5.1 + inherits: ^2.0.3 + source-map: ^0.6.1 + source-map-resolve: ^0.5.2 urix: ^0.1.0 - checksum: 7020de5171addf25e20119fdf3989c555a6c1e6275b7434d3cff044323eaa07f5a69d7ad70e447e7f5938c8b5048d8c12409fc04523569315385761fe7e71999 + checksum: a35d483c5ccc04bcde3b1e7393d58ad3eee1dd6956df0f152de38e46a17c0ee193c30eec6b1e59831ad0e74599385732000e95987fcc9cb2b16c6d951bae49e1 languageName: node linkType: hard @@ -13325,9 +13318,9 @@ __metadata: linkType: hard "decode-uri-component@npm:^0.2.0": - version: 0.2.0 - resolution: "decode-uri-component@npm:0.2.0" - checksum: f3749344ab9305ffcfe4bfe300e2dbb61fc6359e2b736812100a3b1b6db0a5668cba31a05e4b45d4d63dbf1a18dfa354cd3ca5bb3ededddabb8cd293f4404f94 + version: 0.2.2 + resolution: "decode-uri-component@npm:0.2.2" + checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 languageName: node linkType: hard @@ -20086,15 +20079,6 @@ __metadata: languageName: node linkType: hard -"is-odd@npm:^2.0.0": - version: 2.0.0 - resolution: "is-odd@npm:2.0.0" - dependencies: - is-number: ^4.0.0 - checksum: 89da9e6dba221361d8af5384f26a49575610e1910118538cfbcc2c0469aa2cf7b695a2e85fb4bcbe7521480bd727c234c9b5397f24554cd96cd5c1e7a7ae5143 - languageName: node - linkType: hard - "is-path-cwd@npm:^1.0.0": version: 1.0.0 resolution: "is-path-cwd@npm:1.0.0" @@ -24930,22 +24914,21 @@ __metadata: linkType: hard "nanomatch@npm:^1.2.9": - version: 1.2.9 - resolution: "nanomatch@npm:1.2.9" + version: 1.2.13 + resolution: "nanomatch@npm:1.2.13" dependencies: arr-diff: ^4.0.0 array-unique: ^0.3.2 define-property: ^2.0.2 extend-shallow: ^3.0.2 fragment-cache: ^0.2.1 - is-odd: ^2.0.0 is-windows: ^1.0.2 kind-of: ^6.0.2 object.pick: ^1.3.0 regex-not: ^1.0.0 snapdragon: ^0.8.1 to-regex: ^3.0.1 - checksum: adba960532e85020cd5c1cbdf60aebd0568b3be63b32d2e0f9b00dbb43c66ccfb52b4d5cd0dd2931f47a724c5a6bcb59a85fb1a66e1c7e47dbdf8e38579ce89f + checksum: 54d4166d6ef08db41252eb4e96d4109ebcb8029f0374f9db873bd91a1f896c32ec780d2a2ea65c0b2d7caf1f28d5e1ea33746a470f32146ac8bba821d80d38d8 languageName: node linkType: hard @@ -30896,16 +30879,16 @@ __metadata: languageName: node linkType: hard -"source-map-resolve@npm:^0.5.0, source-map-resolve@npm:^0.5.1": - version: 0.5.1 - resolution: "source-map-resolve@npm:0.5.1" +"source-map-resolve@npm:^0.5.0, source-map-resolve@npm:^0.5.2": + version: 0.5.3 + resolution: "source-map-resolve@npm:0.5.3" dependencies: - atob: ^2.0.0 + atob: ^2.1.2 decode-uri-component: ^0.2.0 resolve-url: ^0.2.1 source-map-url: ^0.4.0 urix: ^0.1.0 - checksum: 97d6d665cc5c64d408cb97204a64fb508006926f2e7cc639cb3bf832f03a29ce59d14a281719e58b197ef1cd0837b24f3ceebfdf7e53abfd10b726eaaee0bc80 + checksum: c73fa44ac00783f025f6ad9e038ab1a2e007cd6a6b86f47fe717c3d0765b4a08d264f6966f3bd7cd9dbcd69e4832783d5472e43247775b2a550d6f2155d24bae languageName: node linkType: hard @@ -30940,9 +30923,9 @@ __metadata: linkType: hard "source-map-url@npm:^0.4.0": - version: 0.4.0 - resolution: "source-map-url@npm:0.4.0" - checksum: 63ed54045fcd7b4ec7ca17513f48fdc23b573eef679326ecf1a31333e1aaecc0a9c085adaa7d118283b160e65b71cc72da9e1385f2de4ac5ed68294e3920d719 + version: 0.4.1 + resolution: "source-map-url@npm:0.4.1" + checksum: 64c5c2c77aff815a6e61a4120c309ae4cac01298d9bcbb3deb1b46a4dd4c46d4a1eaeda79ec9f684766ae80e8dc86367b89326ce9dd2b89947bd9291fc1ac08c languageName: node linkType: hard @@ -30953,15 +30936,6 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.1.38": - version: 0.1.43 - resolution: "source-map@npm:0.1.43" - dependencies: - amdefine: ">=0.0.4" - checksum: 0a230f8cae8a8ea70bd36701c33d01fb0c437b798508a561c896a99b42f5af81a206176a250fc654c7c57a736b8081c4b4a6c9887455f7d2724f847451f1d7d9 - languageName: node - linkType: hard - "source-map@npm:^0.5.0, source-map@npm:^0.5.1, source-map@npm:^0.5.6, source-map@npm:^0.5.7, source-map@npm:~0.5.3": version: 0.5.7 resolution: "source-map@npm:0.5.7" From d428a4895fdda897c144b079995911ffa7f17cb7 Mon Sep 17 00:00:00 2001 From: "Digvijay Pundir (DJ)" <61174028+dj-pundir@users.noreply.github.com> Date: Wed, 26 Apr 2023 20:43:14 +0530 Subject: [PATCH 50/60] Update knobs to control: MetamaskTemplateRenderer (#18677) Co-authored-by: Brad Decker --- .../metamask-template-renderer.stories.js | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/ui/components/app/metamask-template-renderer/metamask-template-renderer.stories.js b/ui/components/app/metamask-template-renderer/metamask-template-renderer.stories.js index a1f782240..c494fae2b 100644 --- a/ui/components/app/metamask-template-renderer/metamask-template-renderer.stories.js +++ b/ui/components/app/metamask-template-renderer/metamask-template-renderer.stories.js @@ -1,5 +1,4 @@ import React from 'react'; -import { object } from '@storybook/addon-knobs'; import { TextColor, TypographyVariant, @@ -8,6 +7,12 @@ import MetaMaskTemplateRenderer from '.'; export default { title: 'Components/App/MetamaskTemplateRenderer', + component: MetaMaskTemplateRenderer, + argTypes: { + sections: { + control: 'object', + }, + }, }; const SECTIONS = { @@ -85,25 +90,12 @@ const SECTIONS = { ], }; -export const DefaultStory = () => ( - +export const DefaultStory = (args) => ( + ); DefaultStory.storyName = 'Default'; -export const WithInvalidElement = () => ( - -); +DefaultStory.args = { + sections: SECTIONS, +}; From a6d7c436bcfddd6fd6c952c5e4a4ce5201b8801b Mon Sep 17 00:00:00 2001 From: Harsh Shukla <125105825+PrgrmrHarshShukla@users.noreply.github.com> Date: Wed, 26 Apr 2023 20:55:18 +0530 Subject: [PATCH 51/60] Part of #17670 for file: detected-token-ignored-popover.js (#18738) Co-authored-by: Brad Decker --- .../detected-token-ignored-popover.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js b/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js index b32428c18..708b078db 100644 --- a/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js +++ b/ui/components/app/detected-token/detected-token-ignored-popover/detected-token-ignored-popover.js @@ -51,7 +51,6 @@ const DetectedTokenIgnoredPopover = ({ Date: Wed, 26 Apr 2023 21:17:25 +0500 Subject: [PATCH 52/60] Update Button prop name type to variant (#18774) * Update Button prop name type to variant * fix: lint errors on running test cases * change remaining files * change typo: BUTTON_VARIANTS to BUTTON_VARIANT * fix: button.test.js lint errors * update: button instances & import in remaing files * fix: prettier warnings --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> Co-authored-by: Brad Decker --- .../hold-to-reveal-modal.js | 4 +-- .../app/snaps/snap-version/snap-version.js | 4 +-- .../terms-of-use-popup/terms-of-use-popup.js | 4 +-- .../component-library/button/README.mdx | 22 ++++++------- .../button/button.constants.js | 2 +- .../component-library/button/button.js | 20 ++++++------ .../button/button.stories.js | 18 +++++------ .../component-library/button/button.test.js | 31 ++++++++++--------- .../component-library/button/index.js | 2 +- ui/components/component-library/index.js | 2 +- .../compliance-settings.js | 4 +-- .../custody-confirm-link-modal.js | 4 +-- .../network-list-menu/network-list-menu.js | 4 +-- .../create-account/connect-hardware/index.js | 8 ++--- .../confirm-add-custodian-token.js | 4 +-- .../confirm-add-institutional-feature.js | 4 +-- ui/pages/keychains/reveal-seed.js | 10 +++--- .../settings/snaps/view-snap/view-snap.js | 4 +-- 18 files changed, 77 insertions(+), 74 deletions(-) diff --git a/ui/components/app/modals/hold-to-reveal-modal/hold-to-reveal-modal.js b/ui/components/app/modals/hold-to-reveal-modal/hold-to-reveal-modal.js index bf4b42ccf..3cd352e9a 100644 --- a/ui/components/app/modals/hold-to-reveal-modal/hold-to-reveal-modal.js +++ b/ui/components/app/modals/hold-to-reveal-modal/hold-to-reveal-modal.js @@ -5,7 +5,7 @@ import Box from '../../../ui/box'; import { Text, Button, - BUTTON_TYPES, + BUTTON_VARIANT, ButtonIcon, IconName, } from '../../../component-library'; @@ -86,7 +86,7 @@ const HoldToRevealModal = ({ onLongPressed, hideModal }) => { , - - + + + ``` ### Size diff --git a/ui/components/component-library/button/button.constants.js b/ui/components/component-library/button/button.constants.js index 4f5f6ef0f..b555bb11a 100644 --- a/ui/components/component-library/button/button.constants.js +++ b/ui/components/component-library/button/button.constants.js @@ -8,7 +8,7 @@ export const BUTTON_SIZES = { AUTO: Size.auto, }; -export const BUTTON_TYPES = { +export const BUTTON_VARIANT = { PRIMARY: 'primary', SECONDARY: 'secondary', LINK: 'link', diff --git a/ui/components/component-library/button/button.js b/ui/components/component-library/button/button.js index eaaa5486b..111a01458 100644 --- a/ui/components/component-library/button/button.js +++ b/ui/components/component-library/button/button.js @@ -5,15 +5,15 @@ import { ButtonPrimary } from '../button-primary'; import { ButtonSecondary } from '../button-secondary'; import { ButtonLink } from '../button-link'; -import { BUTTON_TYPES } from './button.constants'; +import { BUTTON_VARIANT } from './button.constants'; -export const Button = ({ type, ...props }) => { - switch (type) { - case BUTTON_TYPES.PRIMARY: +export const Button = ({ variant, ...props }) => { + switch (variant) { + case BUTTON_VARIANT.PRIMARY: return ; - case BUTTON_TYPES.SECONDARY: + case BUTTON_VARIANT.SECONDARY: return ; - case BUTTON_TYPES.LINK: + case BUTTON_VARIANT.LINK: return ; default: return ; @@ -22,11 +22,11 @@ export const Button = ({ type, ...props }) => { Button.propTypes = { /** - * Select the type of Button. - * Possible values could be 'BUTTON_TYPES.PRIMARY', 'BUTTON_TYPES.SECONDARY', 'BUTTON_TYPES.LINK' - * Button will default to `BUTTON_TYPES.PRIMARY` + * Select the variant of Button. + * Possible values could be 'BUTTON_VARIANT.PRIMARY', 'BUTTON_VARIANT.SECONDARY', 'BUTTON_VARIANT.LINK' + * Button will default to `BUTTON_VARIANT.PRIMARY` */ - type: PropTypes.oneOf(Object.values(BUTTON_TYPES)), + variant: PropTypes.oneOf(Object.values(BUTTON_VARIANT)), /** * Button accepts all the props from ButtonPrimary (same props as ButtonSecondary & ButtonLink) */ diff --git a/ui/components/component-library/button/button.stories.js b/ui/components/component-library/button/button.stories.js index e85d37fa6..bc2176611 100644 --- a/ui/components/component-library/button/button.stories.js +++ b/ui/components/component-library/button/button.stories.js @@ -11,7 +11,7 @@ import { BUTTON_LINK_SIZES } from '../button-link/button-link.constants'; import Box from '../../ui/box/box'; import { Text } from '../text'; import README from './README.mdx'; -import { Button, BUTTON_TYPES } from '.'; +import { Button, BUTTON_VARIANT } from '.'; const marginSizeControlOptions = [ undefined, @@ -85,8 +85,8 @@ export default { control: 'select', options: Object.values(BUTTON_LINK_SIZES), }, - type: { - options: Object.values(BUTTON_TYPES), + variant: { + options: Object.values(BUTTON_VARIANT), control: 'select', }, marginTop: { @@ -119,15 +119,15 @@ export const DefaultStory = (args) => - - @@ -150,12 +150,12 @@ export const SizeStory = (args) => ( - - {' '} inherits the font-size of the parent element. Inherit size only used for diff --git a/ui/components/component-library/button/button.test.js b/ui/components/component-library/button/button.test.js index 1fd245238..f612b4da6 100644 --- a/ui/components/component-library/button/button.test.js +++ b/ui/components/component-library/button/button.test.js @@ -2,7 +2,7 @@ import { render } from '@testing-library/react'; import React from 'react'; import { IconName } from '..'; -import { BUTTON_SIZES, BUTTON_TYPES } from './button.constants'; +import { BUTTON_SIZES, BUTTON_VARIANT } from './button.constants'; import { Button } from './button'; describe('Button', () => { @@ -46,28 +46,31 @@ describe('Button', () => { it('should render with different button types', () => { const { getByTestId, container } = render( <> - - + , ); - expect(getByTestId(BUTTON_TYPES.PRIMARY)).toHaveClass( - `mm-button-${BUTTON_TYPES.PRIMARY}`, + expect(getByTestId(BUTTON_VARIANT.PRIMARY)).toHaveClass( + `mm-button-${BUTTON_VARIANT.PRIMARY}`, ); - expect(getByTestId(BUTTON_TYPES.SECONDARY)).toHaveClass( - `mm-button-${BUTTON_TYPES.SECONDARY}`, + expect(getByTestId(BUTTON_VARIANT.SECONDARY)).toHaveClass( + `mm-button-${BUTTON_VARIANT.SECONDARY}`, ); - expect(getByTestId(BUTTON_TYPES.LINK)).toHaveClass( - `mm-button-${BUTTON_TYPES.LINK}`, + expect(getByTestId(BUTTON_VARIANT.LINK)).toHaveClass( + `mm-button-${BUTTON_VARIANT.LINK}`, ); expect(container).toMatchSnapshot(); }); @@ -77,7 +80,7 @@ describe('Button', () => { <> + + + + + +`; diff --git a/ui/pages/institutional/interactive-replacement-token-page/index.js b/ui/pages/institutional/interactive-replacement-token-page/index.js new file mode 100644 index 000000000..0d0241f73 --- /dev/null +++ b/ui/pages/institutional/interactive-replacement-token-page/index.js @@ -0,0 +1,3 @@ +import InteractiveReplacementTokenPage from './interactive-replacement-token-page'; + +export default InteractiveReplacementTokenPage; diff --git a/ui/pages/institutional/interactive-replacement-token-page/index.scss b/ui/pages/institutional/interactive-replacement-token-page/index.scss new file mode 100644 index 000000000..a1d39a9c9 --- /dev/null +++ b/ui/pages/institutional/interactive-replacement-token-page/index.scss @@ -0,0 +1,23 @@ +.interactive-replacement-token-page { + opacity: 0.8; + + &__item { + border-bottom: 1px solid --color-border-default; + + &-clipboard { + background-color: transparent; + } + } + + &__item:first-child { + margin-top: 12px; + } + + &__item:last-child { + border: 0; + } + + &__item:hover { + background-color: rgba(0, 0, 0, 0.03); + } +} diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js new file mode 100644 index 000000000..751168841 --- /dev/null +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.js @@ -0,0 +1,349 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import PropTypes from 'prop-types'; +import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; +import { getMostRecentOverviewPage } from '../../../ducks/history/history'; +import { getMetaMaskAccounts } from '../../../selectors'; +import Button from '../../../components/ui/button'; +import CustodyLabels from '../../../components/institutional/custody-labels/custody-labels'; +import PulseLoader from '../../../components/ui/pulse-loader'; +import { INSTITUTIONAL_FEATURES_DONE_ROUTE } from '../../../helpers/constants/routes'; +import { SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../shared/constants/swaps'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import { shortenAddress } from '../../../helpers/utils/util'; +import Tooltip from '../../../components/ui/tooltip'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { + mmiActionsFactory, + showInteractiveReplacementTokenBanner, +} from '../../../store/institutional/institution-background'; +import Box from '../../../components/ui/box'; +import { + Text, + Label, + Icon, + ButtonLink, + IconName, + IconSize, +} from '../../../components/component-library'; +import { + OVERFLOW_WRAP, + TextColor, + JustifyContent, + BLOCK_SIZES, + DISPLAY, + FLEX_DIRECTION, + IconColor, +} from '../../../helpers/constants/design-system'; +import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; + +const getButtonLinkHref = ({ address }) => { + const url = SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[CHAIN_IDS.MAINNET]; + return `${url}address/${address}`; +}; + +export default function InteractiveReplacementTokenPage({ history }) { + const dispatch = useDispatch(); + const isMountedRef = useRef(false); + const mmiActions = mmiActionsFactory(); + const { address } = useSelector((state) => state.metamask.modal.props); + const { + selectedAddress, + custodyAccountDetails, + interactiveReplacementToken, + mmiConfiguration, + } = useSelector((state) => state.metamask); + const { custodianName } = + custodyAccountDetails[toChecksumHexAddress(address || selectedAddress)] || + {}; + const { url } = interactiveReplacementToken || {}; + const { custodians } = mmiConfiguration; + const custodian = + custodians.find((item) => item.name === custodianName) || {}; + const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); + const metaMaskAccounts = useSelector(getMetaMaskAccounts); + const connectRequests = useSelector( + (state) => state.metamask.institutionalFeatures?.connectRequests, + ); + const [isLoading, setIsLoading] = useState(false); + const [tokenAccounts, setTokenAccounts] = useState([]); + const [error, setError] = useState(false); + const t = useI18nContext(); + const [copied, handleCopy] = useCopyToClipboard(); + const { + removeAddTokenConnectRequest, + setCustodianNewRefreshToken, + getCustodianAccounts, + } = mmiActions; + const connectRequest = connectRequests ? connectRequests[0] : undefined; + + useEffect(() => { + isMountedRef.current = true; + return () => (isMountedRef.current = false); + }, []); + + useEffect(() => { + const getTokenAccounts = async () => { + if (!connectRequest) { + history.push(mostRecentOverviewPage); + return; + } + + try { + const custodianAccounts = await dispatch( + getCustodianAccounts( + connectRequest.token, + connectRequest.apiUrl, + connectRequest.service, + false, + ), + ); + + const filteredAccounts = custodianAccounts.filter( + (account) => metaMaskAccounts[account.address.toLowerCase()], + ); + + const mappedAccounts = filteredAccounts.map((account) => ({ + address: account.address, + name: account.name, + labels: account.labels, + balance: + metaMaskAccounts[account.address.toLowerCase()]?.balance || 0, + })); + + if (isMountedRef.current) { + setTokenAccounts(mappedAccounts); + setIsLoading(false); + } + } catch (e) { + setError(true); + setIsLoading(false); + } + }; + + getTokenAccounts(); + // We just want to get the accounts in the render of the component + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (!connectRequest) { + history.push(mostRecentOverviewPage); + return null; + } + + const onRemoveAddTokenConnectRequest = ({ origin, apiUrl, token }) => { + dispatch( + removeAddTokenConnectRequest({ + origin, + apiUrl, + token, + }), + ); + }; + + const handleReject = () => { + onRemoveAddTokenConnectRequest(connectRequest); + history.push(mostRecentOverviewPage); + }; + + const handleApprove = async () => { + if (error) { + global.platform.openTab({ + url, + }); + handleReject(); + return; + } + + setIsLoading(true); + + try { + await Promise.all( + tokenAccounts.map(async (account) => { + await dispatch( + setCustodianNewRefreshToken({ + address: account.address, + newAuthDetails: { + refreshToken: connectRequest.token, + refreshTokenUrl: connectRequest.apiUrl, + }, + }), + ); + }), + ); + + dispatch(showInteractiveReplacementTokenBanner({})); + + onRemoveAddTokenConnectRequest(connectRequest); + + history.push({ + pathname: INSTITUTIONAL_FEATURES_DONE_ROUTE, + state: { + imgSrc: custodian?.iconUrl, + title: t('custodianReplaceRefreshTokenChangedTitle'), + description: t('custodianReplaceRefreshTokenChangedSubtitle'), + }, + }); + + if (isMountedRef.current) { + setIsLoading(false); + } + } catch (e) { + console.error(e); + } + }; + + return ( + + + + {t('custodianReplaceRefreshTokenTitle')}{' '} + {error ? t('failed').toLowerCase() : ''} + + {!error && ( + + {t('custodianReplaceRefreshTokenSubtitle')} + + )} + + + + {error ? ( + + {t('custodianReplaceRefreshTokenChangedFailed', [ + custodian.displayName || 'Custodian', + ])} + + ) : null} + + {tokenAccounts.map((account, idx) => { + return ( + + + + + + {account.labels && ( + + )} + + + + ); + })} + + + + + {isLoading ? ( +
+ +
+ ) : ( +
+ + +
+ )} +
+
+ ); +} + +InteractiveReplacementTokenPage.propTypes = { + history: PropTypes.object, +}; diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.stories.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.stories.js new file mode 100644 index 000000000..ed51dbc78 --- /dev/null +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.stories.js @@ -0,0 +1,71 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import { action } from '@storybook/addon-actions'; +import configureStore from '../../../store/store'; +import testData from '../../../../.storybook/test-data'; +import InteractiveReplacementTokenPage from '.'; + +const address = '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F'; +const customData = { + ...testData, + metamask: { + ...testData.metamask, + modal: { props: address }, + selectedAddress: address, + interactiveReplacementToken: { + url: 'https://saturn-custody-ui.codefi.network/', + }, + custodyAccountDetails: { + [address]: { balance: '0x', custodianName: 'Jupiter' }, + }, + mmiConfiguration: { + custodians: [ + { + production: true, + name: 'Jupiter', + type: 'Jupiter', + iconUrl: 'iconUrl', + displayName: 'displayName', + }, + ], + }, + institutionalFeatures: { + complianceProjectId: '', + connectRequests: [ + { + labels: [ + { + key: 'service', + value: 'test', + }, + ], + origin: 'origin', + token: 'testToken', + feature: 'custodian', + service: 'Jupiter', + apiUrl: 'https://', + environment: 'Jupiter', + }, + ], + }, + }, +}; + +const store = configureStore(customData); + +export default { + title: 'Pages/Institutional/InteractiveReplacementTokenPage', + decorators: [(story) => {story()}], + component: InteractiveReplacementTokenPage, + args: { + history: { + push: action('history.push()'), + }, + }, +}; + +export const DefaultStory = (args) => ( + +); + +DefaultStory.storyName = 'InteractiveReplacementTokenPage'; diff --git a/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js new file mode 100644 index 000000000..d462f4a7a --- /dev/null +++ b/ui/pages/institutional/interactive-replacement-token-page/interactive-replacement-token-page.test.js @@ -0,0 +1,225 @@ +import React from 'react'; +import { screen, act, fireEvent, waitFor } from '@testing-library/react'; +import configureMockStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import mockState from '../../../../test/data/mock-state.json'; +import { SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP } from '../../../../shared/constants/swaps'; +import { CHAIN_IDS } from '../../../../shared/constants/network'; +import { shortenAddress } from '../../../helpers/utils/util'; +import InteractiveReplacementTokenPage from '.'; + +const custodianAccounts = [ + { + address: '0x9d0ba4ddac06032527b140912ec808ab9451b788', + balance: '0x', + name: 'Jupiter', + labels: [ + { + key: 'service', + value: 'Label test 1', + }, + ], + }, + { + address: '0xeb9e64b93097bc15f01f13eae97015c57ab64823', + balance: '0x', + name: 'Jupiter', + labels: [ + { + key: 'service', + value: 'Label test 2', + }, + ], + }, +]; + +const mockedShowInteractiveReplacementTokenBanner = jest.fn(); + +const mockedRemoveAddTokenConnectRequest = jest + .fn() + .mockReturnValue({ type: 'TYPE' }); +const mockedSetCustodianNewRefreshToken = jest + .fn() + .mockReturnValue({ type: 'TYPE' }); +let mockedGetCustodianConnectRequest = jest + .fn() + .mockReturnValue(async () => await custodianAccounts); + +jest.mock('../../../store/institutional/institution-background', () => ({ + mmiActionsFactory: () => ({ + removeAddTokenConnectRequest: mockedRemoveAddTokenConnectRequest, + setCustodianNewRefreshToken: mockedSetCustodianNewRefreshToken, + getCustodianAccounts: mockedGetCustodianConnectRequest, + }), + showInteractiveReplacementTokenBanner: () => + mockedShowInteractiveReplacementTokenBanner, +})); + +const address = '0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F'; +const custodianAddress = '0xeb9e64b93097bc15f01f13eae97015c57ab64823'; +const accountName = 'Jupiter'; +const labels = [ + { + key: 'service', + value: 'label test', + }, +]; +const connectRequests = [ + { + labels, + origin: 'origin', + apiUrl: 'apiUrl', + token: { + projectName: 'projectName', + projectId: 'projectId', + clientId: 'clientId', + }, + }, +]; + +const props = { + history: { + push: jest.fn(), + }, +}; + +const render = ({ newState } = {}) => { + const state = { + ...mockState, + metamask: { + ...mockState.metamask, + modal: { props: address }, + selectedAddress: address, + interactiveReplacementToken: { + url: 'https://saturn-custody-ui.codefi.network/', + }, + custodyAccountDetails: { + [address]: { balance: '0x', custodianName: 'Jupiter' }, + }, + mmiConfiguration: { + custodians: [ + { + production: true, + name: 'Jupiter', + type: 'Jupiter', + iconUrl: 'iconUrl', + displayName: 'displayName', + }, + ], + }, + institutionalFeatures: { + complianceProjectId: '', + connectRequests, + }, + ...newState, + }, + }; + const middlewares = [thunk]; + const mockStore = configureMockStore(middlewares); + const store = mockStore(state); + + return renderWithProvider( + , + store, + ); +}; + +describe('Interactive Replacement Token Page', function () { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should render all the accounts correctly', async () => { + const expectedHref = `${ + SWAPS_CHAINID_DEFAULT_BLOCK_EXPLORER_URL_MAP[CHAIN_IDS.MAINNET] + }address/${custodianAddress}`; + + await act(async () => await render()); + + expect(screen.getByText(accountName)).toBeInTheDocument(); + const link = screen.getByRole('link', { + name: shortenAddress(custodianAddress), + }); + + expect(link).toHaveAttribute('href', expectedHref); + expect( + screen.getByText(shortenAddress(custodianAddress)), + ).toBeInTheDocument(); + expect( + screen.getByText(custodianAccounts[1].labels[0].value), + ).toBeInTheDocument(); + }); + + it('should not render if connectRequests is empty', async () => { + const newState = { + institutionalFeatures: { + connectRequests: [], + }, + }; + + const { queryByTestId } = render({ newState }); + + expect( + queryByTestId('interactive-replacement-token'), + ).not.toBeInTheDocument(); + }); + + it('should call onRemoveAddTokenConnectRequest and navigate to mostRecentOverviewPage when handleReject is called', () => { + const mostRecentOverviewPage = '/mostRecentOverviewPage'; + + const { getByText } = render(); + + fireEvent.click(getByText('Reject')); + + expect(mockedRemoveAddTokenConnectRequest).toHaveBeenCalled(); + expect(mockedRemoveAddTokenConnectRequest).toHaveBeenCalledWith({ + origin: connectRequests[0].origin, + apiUrl: connectRequests[0].apiUrl, + token: connectRequests[0].token, + }); + expect(props.history.push).toHaveBeenCalled(); + expect(props.history.push).toHaveBeenCalledWith(mostRecentOverviewPage); + }); + + it('should call onRemoveAddTokenConnectRequest, setCustodianNewRefreshToken, and dispatch showInteractiveReplacementTokenBanner when handleApprove is called', async () => { + const mostRecentOverviewPage = { + pathname: '/institutional-features/done', + state: { + description: + 'You can now use your custodian accounts in MetaMask Institutional.', + imgSrc: 'iconUrl', + title: 'Your custodian token has been refreshed', + }, + }; + + await act(async () => { + const { getByText } = await render(); + fireEvent.click(getByText('Approve')); + }); + + expect(mockedShowInteractiveReplacementTokenBanner).toHaveBeenCalled(); + expect(mockedRemoveAddTokenConnectRequest).toHaveBeenCalled(); + expect(mockedRemoveAddTokenConnectRequest).toHaveBeenCalledWith({ + origin: connectRequests[0].origin, + apiUrl: connectRequests[0].apiUrl, + token: connectRequests[0].token, + }); + expect(props.history.push).toHaveBeenCalled(); + expect(props.history.push).toHaveBeenCalledWith(mostRecentOverviewPage); + }); + + it('should reject if there are errors', async () => { + mockedGetCustodianConnectRequest = jest.fn().mockReturnValue(async () => { + throw new Error(); + }); + + await act(async () => { + const { getByText, container } = await render(); + fireEvent.click(getByText('Approve')); + await waitFor(() => { + expect(container).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/ui/pages/pages.scss b/ui/pages/pages.scss index 925feceb0..9d926ccd9 100644 --- a/ui/pages/pages.scss +++ b/ui/pages/pages.scss @@ -12,8 +12,9 @@ @import 'connected-accounts/index'; @import 'connected-sites/index'; @import 'create-account/index'; -///: BEGIN:ONLY_INCLUDE_IN(mmi) +///: BEGIN:ONLY_INCLUDE_IN(build-mmi) @import "create-account/institutional/connect-custody/index"; +@import "institutional/interactive-replacement-token-page/index"; ///: END:ONLY_INCLUDE_IN @import 'error/index'; @import 'send/gas-display/index'; diff --git a/ui/store/institutional/institution-background.ts b/ui/store/institutional/institution-background.ts index 21a1432db..7defb2abe 100644 --- a/ui/store/institutional/institution-background.ts +++ b/ui/store/institutional/institution-background.ts @@ -14,23 +14,27 @@ import { import { MetaMaskReduxState } from '../store'; import { isErrorWithMessage } from '../../../shared/modules/error'; -export function showInteractiveReplacementTokenBanner( - url: string, - oldRefreshToken: string, -) { - return () => { - callBackgroundMethod( - 'showInteractiveReplacementTokenBanner', - [url, oldRefreshToken], - (err) => { - if (isErrorWithMessage(err)) { - throw new Error(err.message); - } - }, - ); +export function showInteractiveReplacementTokenBanner({ + url, + oldRefreshToken, +}: { + url: string; + oldRefreshToken: string; +}): ThunkAction { + return async (dispatch) => { + try { + await submitRequestToBackground('showInteractiveReplacementTokenBanner', [ + url, + oldRefreshToken, + ]); + } catch (err: any) { + if (err) { + dispatch(displayWarning(err.message)); + throw new Error(err.message); + } + } }; } - /** * A factory that contains all MMI actions ready to use * Example usage: From c450fae84ff24249868d45e263f34b55ed553aef Mon Sep 17 00:00:00 2001 From: David Drazic Date: Thu, 27 Apr 2023 10:49:49 +0200 Subject: [PATCH 57/60] Update Snaps icon in settings search and fix missing icon (#18803) Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- ui/helpers/constants/settings.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/helpers/constants/settings.js b/ui/helpers/constants/settings.js index 4c1b9c8bc..2fbc8e713 100644 --- a/ui/helpers/constants/settings.js +++ b/ui/helpers/constants/settings.js @@ -131,7 +131,7 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('contacts'), descriptionMessage: (t) => t('contacts'), route: CONTACT_LIST_ROUTE, - icon: ICON_NAMES.BOOK, + iconName: ICON_NAMES.BOOK, }, ///: BEGIN:ONLY_INCLUDE_IN(snaps) { @@ -139,7 +139,7 @@ export const SETTINGS_CONSTANTS = [ sectionMessage: (t) => t('snaps'), descriptionMessage: (t) => t('snaps'), route: SNAPS_LIST_ROUTE, - icon: 'fa fa-flask', + iconName: ICON_NAMES.SNAPS, }, ///: END:ONLY_INCLUDE_IN { From e6455e92ae86ed0f94035784fb0cefcb83ec27e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Thu, 27 Apr 2023 11:27:31 +0100 Subject: [PATCH 58/60] [MMI] custody page component (#18688) --- app/_locales/en/messages.json | 30 + .../__snapshots__/jwt-url-form.test.js.snap | 1 - .../jwt-url-form/jwt-url-form.js | 2 - .../jwt-url-form/jwt-url-form.scss | 1 + ui/helpers/constants/routes.ts | 10 +- .../__snapshots__/account-list.test.js.snap | 8 +- .../connect-custody/account-list.js | 24 +- .../connect-custody/account-list.stories.js | 0 .../connect-custody/account-list.test.js | 0 .../institutional/connect-custody/index.js | 0 .../institutional/connect-custody/index.scss | 0 .../__snapshots__/custody.test.js.snap | 174 ++++++ ui/pages/institutional/custody/custody.js | 591 ++++++++++++++++++ .../institutional/custody/custody.stories.js | 52 ++ .../institutional/custody/custody.test.js | 113 ++++ ui/pages/institutional/custody/index.js | 1 + ui/pages/institutional/custody/index.scss | 14 + ui/pages/pages.scss | 6 +- ui/selectors/institutional/selectors.js | 2 +- 19 files changed, 1004 insertions(+), 25 deletions(-) rename ui/pages/{create-account => }/institutional/connect-custody/__snapshots__/account-list.test.js.snap (95%) rename ui/pages/{create-account => }/institutional/connect-custody/account-list.js (90%) rename ui/pages/{create-account => }/institutional/connect-custody/account-list.stories.js (100%) rename ui/pages/{create-account => }/institutional/connect-custody/account-list.test.js (100%) rename ui/pages/{create-account => }/institutional/connect-custody/index.js (100%) rename ui/pages/{create-account => }/institutional/connect-custody/index.scss (100%) create mode 100644 ui/pages/institutional/custody/__snapshots__/custody.test.js.snap create mode 100644 ui/pages/institutional/custody/custody.js create mode 100644 ui/pages/institutional/custody/custody.stories.js create mode 100644 ui/pages/institutional/custody/custody.test.js create mode 100644 ui/pages/institutional/custody/index.js create mode 100644 ui/pages/institutional/custody/index.scss diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 9a4cec433..def53a578 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -333,6 +333,12 @@ "alerts": { "message": "Alerts" }, + "allCustodianAccountsConnectedSubtitle": { + "message": "You have either already connected all your custodian accounts or don’t have any account to connect to MetaMask Institutional." + }, + "allCustodianAccountsConnectedTitle": { + "message": "No accounts available to connect" + }, "allOfYour": { "message": "All of your $1", "description": "$1 is the symbol or name of the token that the user is approving spending" @@ -724,6 +730,12 @@ "connectAccountOrCreate": { "message": "Connect account or create new" }, + "connectCustodialAccountMsg": { + "message": "Please choose the custodian you want to connect in order to add or refresh a token." + }, + "connectCustodialAccountTitle": { + "message": "Custodial Accounts" + }, "connectHardwareWallet": { "message": "Connect hardware wallet" }, @@ -950,6 +962,9 @@ "custodianReplaceRefreshTokenTitle": { "message": "Replace custodian token" }, + "custodyApiUrl": { + "message": "$1 API URL" + }, "custodyDeeplinkDescription": { "message": "Approve the transaction in the $1 app. Once all required custody approvals have been performed the transaction will complete. Check your $1 app for status." }, @@ -1388,6 +1403,9 @@ "enterANumber": { "message": "Enter a number" }, + "enterCustodianToken": { + "message": "Enter your $1 token or add a new token" + }, "enterMaxSpendLimit": { "message": "Enter max spend limit" }, @@ -2909,6 +2927,9 @@ "passwordsDontMatch": { "message": "Passwords don't match" }, + "pasteJWTToken": { + "message": "Paste or drop your token here:" + }, "pastePrivateKey": { "message": "Enter your private key string here:", "description": "For importing an account from a private key" @@ -3519,18 +3540,27 @@ "seedPhraseWriteDownHeader": { "message": "Write down your Secret Recovery Phrase" }, + "select": { + "message": "Select" + }, "selectAccounts": { "message": "Select the account(s) to use on this site" }, "selectAll": { "message": "Select all" }, + "selectAllAccounts": { + "message": "Select all accounts" + }, "selectAnAccount": { "message": "Select an account" }, "selectAnAccountAlreadyConnected": { "message": "This account has already been connected to MetaMask" }, + "selectAnAccountHelp": { + "message": "Select the custodian accounts to use in MetaMask Institutional." + }, "selectHdPath": { "message": "Select HD path" }, diff --git a/ui/components/institutional/jwt-url-form/__snapshots__/jwt-url-form.test.js.snap b/ui/components/institutional/jwt-url-form/__snapshots__/jwt-url-form.test.js.snap index cdf419d89..c84e7439d 100644 --- a/ui/components/institutional/jwt-url-form/__snapshots__/jwt-url-form.test.js.snap +++ b/ui/components/institutional/jwt-url-form/__snapshots__/jwt-url-form.test.js.snap @@ -17,7 +17,6 @@ exports[`JwtUrlForm shows JWT text area when no jwt token exists 1`] = ` input text

+ + +
+

+ API URL +

+
+ +
+
+ +
+ + +
+ + + +`; + +exports[`CustodyPage renders CustodyPage 3`] = `
`; diff --git a/ui/pages/institutional/custody/custody.js b/ui/pages/institutional/custody/custody.js new file mode 100644 index 000000000..a9ac39ad8 --- /dev/null +++ b/ui/pages/institutional/custody/custody.js @@ -0,0 +1,591 @@ +import React, { + useState, + useMemo, + useCallback, + useEffect, + useContext, +} from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { useHistory } from 'react-router-dom'; +import { v4 as uuidv4 } from 'uuid'; +import { useI18nContext } from '../../../hooks/useI18nContext'; +import { mmiActionsFactory } from '../../../store/institutional/institution-background'; +import { MetaMetricsContext } from '../../../contexts/metametrics'; +import { + ButtonIcon, + Button, + Text, + Label, + IconName, + IconSize, + BUTTON_SIZES, + BUTTON_VARIANT, +} from '../../../components/component-library'; +import { + AlignItems, + DISPLAY, + FLEX_DIRECTION, + FONT_WEIGHT, + Color, + JustifyContent, + BorderRadius, + BorderColor, + BLOCK_SIZES, + TextColor, + TEXT_ALIGN, + TextVariant, +} from '../../../helpers/constants/design-system'; +import Box from '../../../components/ui/box'; +import { + CUSTODY_ACCOUNT_DONE_ROUTE, + DEFAULT_ROUTE, +} from '../../../helpers/constants/routes'; +import { getCurrentChainId, getProvider } from '../../../selectors'; +import { getMMIConfiguration } from '../../../selectors/institutional/selectors'; +import CustodyAccountList from '../connect-custody/account-list'; +import JwtUrlForm from '../../../components/institutional/jwt-url-form'; + +const CustodyPage = () => { + const t = useI18nContext(); + const history = useHistory(); + const trackEvent = useContext(MetaMetricsContext); + const dispatch = useDispatch(); + + const mmiActions = mmiActionsFactory(); + const currentChainId = useSelector(getCurrentChainId); + const provider = useSelector(getProvider); + const { custodians } = useSelector(getMMIConfiguration); + + const [selectedAccounts, setSelectedAccounts] = useState({}); + const [selectedCustodianName, setSelectedCustodianName] = useState(''); + const [selectedCustodianImage, setSelectedCustodianImage] = useState(null); + const [selectedCustodianDisplayName, setSelectedCustodianDisplayName] = + useState(''); + const [selectedCustodianType, setSelectedCustodianType] = useState(''); + const [connectError, setConnectError] = useState(''); + const [currentJwt, setCurrentJwt] = useState(''); + const [selectError, setSelectError] = useState(''); + const [jwtList, setJwtList] = useState([]); + const [apiUrl, setApiUrl] = useState(''); + const [addNewTokenClicked, setAddNewTokenClicked] = useState(false); + const [chainId, setChainId] = useState(0); + const [connectRequest, setConnectRequest] = useState(undefined); + const [accounts, setAccounts] = useState(); + + const custodianButtons = useMemo(() => { + const custodianItems = []; + custodians.forEach((custodian) => { + if ( + (!custodian.production && + process.env.METAMASK_ENVIRONMENT === 'production') || + custodian.hidden || + (connectRequest && + Object.keys(connectRequest).length && + custodian.name !== selectedCustodianName) + ) { + return; + } + + custodianItems.push( + + + {custodian.iconUrl && ( + {custodian.displayName} + )} + {custodian.displayName} + + + + , + ); + }); + + return custodianItems; + }, [connectRequest, custodians, dispatch, selectedCustodianName]); + + const handleConnectError = useCallback( + (e) => { + let errorMessage; + const detailedError = e.message.split(':'); + + if (detailedError.length > 1 && !isNaN(parseInt(detailedError[0], 10))) { + if (parseInt(detailedError[0], 10) === 401) { + // Authentication Error + errorMessage = + 'Authentication error. Please ensure you have entered the correct token'; + } + } + + if (/Network Error/u.test(e.message)) { + errorMessage = + 'Network error. Please ensure you have entered the correct API URL'; + } + + if (!errorMessage) { + errorMessage = e.message; + } + + setConnectError( + `Something went wrong connecting your custodian account. Error details: ${errorMessage}`, + ); + trackEvent({ + category: 'MMI', + event: 'Connect to custodian error', + properties: { + custodian: selectedCustodianName, + }, + }); + }, + [selectedCustodianName, trackEvent], + ); + + const getCustodianAccounts = useCallback( + async (token, custody, getNonImportedAccounts) => { + return await dispatch( + mmiActions.getCustodianAccounts( + token, + apiUrl, + custody || selectedCustodianType, + getNonImportedAccounts, + ), + ); + }, + [dispatch, mmiActions, apiUrl, selectedCustodianType], + ); + + const connect = useCallback(async () => { + try { + // If you have one JWT already, but no dropdown yet, currentJwt is null! + const jwt = currentJwt || jwtList[0]; + setConnectError(''); + const accountsValue = await getCustodianAccounts( + jwt, + apiUrl, + selectedCustodianType, + true, + ); + setAccounts(accountsValue); + trackEvent({ + category: 'MMI', + event: 'Connect to custodian', + properties: { + custodian: selectedCustodianName, + apiUrl, + rpc: Boolean(connectRequest), + }, + }); + } catch (e) { + handleConnectError(e); + } + }, [ + apiUrl, + connectRequest, + currentJwt, + getCustodianAccounts, + handleConnectError, + jwtList, + selectedCustodianName, + selectedCustodianType, + trackEvent, + ]); + + useEffect(() => { + const fetchConnectRequest = async () => { + const connectRequestValue = await dispatch( + mmiActions.getCustodianConnectRequest(), + ); + setChainId(parseInt(currentChainId, 16)); + + // check if it's empty object + if (Object.keys(connectRequestValue).length) { + setConnectRequest(connectRequestValue); + setCurrentJwt( + connectRequestValue.token || + (await dispatch(mmiActions.getCustodianToken())), + ); + setSelectedCustodianType(connectRequestValue.custodianType); + setSelectedCustodianName(connectRequestValue.custodianName); + setApiUrl(connectRequestValue.apiUrl); + connect(); + } + }; + + // call the function + fetchConnectRequest() + // make sure to catch any error + .catch(console.error); + }, [dispatch, connect, currentChainId, mmiActions]); + + useEffect(() => { + const handleNetworkChange = async () => { + if (!isNaN(chainId)) { + const jwt = currentJwt || jwtList[0]; + + if (jwt && jwt.length) { + setAccounts( + await getCustodianAccounts( + jwt, + apiUrl, + selectedCustodianType, + true, + ), + ); + } + } + }; + + if (parseInt(chainId, 16) !== chainId) { + setChainId(parseInt(currentChainId, 16)); + handleNetworkChange(); + } + }, [ + getCustodianAccounts, + apiUrl, + currentJwt, + jwtList, + selectedCustodianType, + currentChainId, + chainId, + ]); + + const cancelConnectCustodianToken = () => { + setSelectedCustodianName(''); + setSelectedCustodianType(''); + setSelectedCustodianImage(null); + setSelectedCustodianDisplayName(''); + setApiUrl(''); + setCurrentJwt(''); + setConnectError(''); + setSelectError(''); + }; + + const setSelectAllAccounts = (e) => { + const allAccounts = {}; + + if (e.currentTarget.checked) { + accounts.forEach((account) => { + allAccounts[account.address] = { + name: account.name, + custodianDetails: account.custodianDetails, + labels: account.labels, + token: currentJwt, + apiUrl, + chainId: account.chainId, + custodyType: selectedCustodianType, + custodyName: selectedCustodianName, + }; + }); + setSelectedAccounts(allAccounts); + } else { + setSelectedAccounts({}); + } + }; + + return ( + + {connectError && ( + + {connectError} + + )} + + {selectError && ( + + {selectError} + + )} + + {!accounts && !selectedCustodianType ? ( + + history.push(DEFAULT_ROUTE)} + display={DISPLAY.FLEX} + /> + + {t('connectCustodialAccountTitle')} + + + {t('connectCustodialAccountMsg')} + + +
    {custodianButtons}
+
+
+ ) : null} + + {!accounts && selectedCustodianType && ( + <> + + cancelConnectCustodianToken()} + display={[DISPLAY.FLEX]} + /> + + + {selectedCustodianImage && ( + {selectedCustodianDisplayName} + )} + {selectedCustodianDisplayName} + + + + {t('enterCustodianToken', [selectedCustodianDisplayName])} + + + + setCurrentJwt(jwt)} + jwtInputText={t('pasteJWTToken')} + apiUrl={apiUrl} + urlInputText={t('custodyApiUrl', [selectedCustodianDisplayName])} + onUrlChange={(url) => setApiUrl(url)} + /> + + + + + + + )} + + {accounts && accounts.length > 0 && ( + <> + + {t('selectAnAccount')} + + {t('selectAnAccountHelp')} + + + + setSelectAllAccounts(e)} + checked={Object.keys(selectedAccounts).length === accounts.length} + /> + + + { + if (selectedAccounts[account.address]) { + delete selectedAccounts[account.address]; + } else { + selectedAccounts[account.address] = { + name: account.name, + custodianDetails: account.custodianDetails, + labels: account.labels, + token: currentJwt, + apiUrl, + chainId: account.chainId, + custodyType: selectedCustodianType, + custodyName: selectedCustodianName, + }; + } + + setSelectedAccounts(selectedAccounts); + }} + provider={provider} + selectedAccounts={selectedAccounts} + onAddAccounts={async () => { + try { + await dispatch( + mmiActions.connectCustodyAddresses( + selectedCustodianType, + selectedCustodianName, + selectedAccounts, + ), + ); + const selectedCustodian = custodians.find( + (custodian) => custodian.name === selectedCustodianName, + ); + history.push({ + pathname: CUSTODY_ACCOUNT_DONE_ROUTE, + state: { + imgSrc: selectedCustodian.iconUrl, + title: t('custodianAccountAddedTitle'), + description: t('custodianAccountAddedDesc'), + }, + }); + trackEvent({ + category: 'MMI', + event: 'Custodial accounts connected', + properties: { + custodian: selectedCustodianName, + numberOfAccounts: Object.keys(selectedAccounts).length, + chainId, + }, + }); + } catch (e) { + setSelectError(e.message); + } + }} + onCancel={() => { + setAccounts(null); + setSelectedCustodianName(null); + setSelectedCustodianType(null); + setSelectedAccounts({}); + setCurrentJwt(''); + setApiUrl(''); + setAddNewTokenClicked(false); + + if (Object.keys(connectRequest).length) { + history.push(DEFAULT_ROUTE); + } + + trackEvent({ + category: 'MMI', + event: 'Connect to custodian cancel', + properties: { + custodian: selectedCustodianName, + numberOfAccounts: Object.keys(selectedAccounts).length, + chainId, + }, + }); + }} + /> + + )} + + {accounts && accounts.length === 0 && ( + + + {t('allCustodianAccountsConnectedTitle')} + + + {t('allCustodianAccountsConnectedSubtitle')} + + + + + + + )} +
+ ); +}; + +export default CustodyPage; diff --git a/ui/pages/institutional/custody/custody.stories.js b/ui/pages/institutional/custody/custody.stories.js new file mode 100644 index 000000000..1b34abc27 --- /dev/null +++ b/ui/pages/institutional/custody/custody.stories.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { Provider } from 'react-redux'; +import configureStore from '../../../store/store'; +import testData from '../../../../.storybook/test-data'; +import CustodyPage from '.'; + +const customData = { + ...testData, + metamask: { + ...testData.metamask, + mmiConfiguration: { + portfolio: { + enabled: true, + url: 'https://portfolio.io', + }, + custodians: [ + { + type: 'Saturn', + name: 'saturn', + apiUrl: 'https://saturn-custody.dev.metamask-institutional.io', + iconUrl: + 'https://saturn-custody-ui.dev.metamask-institutional.io/saturn.svg', + displayName: 'Saturn Custody', + production: true, + refreshTokenUrl: null, + isNoteToTraderSupported: false, + version: 1, + }, + ], + }, + }, +}; + +const store = configureStore(customData); + +export default { + title: 'Pages/Institutional/CustodyPage', + decorators: [(story) => {story()}], + component: CustodyPage, + argTypes: { + onClick: { + action: 'onClick', + }, + onChange: { + action: 'onChange', + }, + }, +}; + +export const DefaultStory = (args) => ; + +DefaultStory.storyName = 'CustodyPage'; diff --git a/ui/pages/institutional/custody/custody.test.js b/ui/pages/institutional/custody/custody.test.js new file mode 100644 index 000000000..b9381e309 --- /dev/null +++ b/ui/pages/institutional/custody/custody.test.js @@ -0,0 +1,113 @@ +import React from 'react'; +import configureMockStore from 'redux-mock-store'; +import { fireEvent, waitFor, screen } from '@testing-library/react'; +import thunk from 'redux-thunk'; +import { renderWithProvider } from '../../../../test/lib/render-helpers'; +import CustodyPage from '.'; + +const mockedReturnedValue = jest.fn().mockReturnValue({ type: 'TYPE' }); +const mockedGetCustodianJWTList = jest.fn().mockReturnValue({ type: 'TYPE' }); + +const mockedGetCustodianAccounts = jest.fn().mockReturnValue(async () => null); +const mockedGetCustodianToken = jest.fn().mockReturnValue('testJWT'); + +const mockedGetCustodianConnectRequest = jest.fn().mockReturnValue({ + type: 'TYPE', + custodian: 'saturn', + token: 'token', + apiUrl: 'url', + custodianType: 'JSON-RPC', + custodianName: 'Saturn', +}); + +jest.mock('../../../store/institutional/institution-background', () => ({ + mmiActionsFactory: () => ({ + getCustodianConnectRequest: mockedGetCustodianConnectRequest, + getCustodianToken: mockedGetCustodianToken, + getCustodianAccounts: mockedGetCustodianAccounts, + getCustodianAccountsByAddress: mockedReturnedValue, + getCustodianJWTList: mockedGetCustodianJWTList, + connectCustodyAddresses: mockedReturnedValue, + }), +})); + +describe('CustodyPage', function () { + const mockStore = { + metamask: { + provider: { chainId: 0x1, type: 'test' }, + mmiConfiguration: { + portfolio: { + enabled: true, + url: 'https://portfolio.io', + }, + custodians: [ + { + type: 'Saturn', + name: 'saturn', + apiUrl: 'https://saturn-custody.dev.metamask-institutional.io', + iconUrl: + 'https://saturn-custody-ui.dev.metamask-institutional.io/saturn.svg', + displayName: 'Saturn Custody', + production: true, + refreshTokenUrl: null, + isNoteToTraderSupported: false, + version: 1, + }, + ], + }, + preferences: { + useNativeCurrencyAsPrimaryCurrency: true, + }, + appState: { + isLoading: false, + }, + history: { + mostRecentOverviewPage: '/', + }, + }, + }; + + const store = configureMockStore([thunk])(mockStore); + + it('renders CustodyPage', async () => { + const { container } = renderWithProvider(, store); + + await waitFor(() => { + expect(container).toMatchSnapshot(); + }); + }); + + it('opens connect custody without any custody selected', async () => { + const { getByTestId } = renderWithProvider(, store); + + await waitFor(() => { + expect(getByTestId('custody-connect-button')).toBeDefined(); + }); + }); + + it('calls getCustodianJwtList on custody select when connect btn is click', async () => { + const { getByTestId } = renderWithProvider(, store); + + const custodyBtn = getByTestId('custody-connect-button'); + await waitFor(() => { + fireEvent.click(custodyBtn); + }); + + await waitFor(() => { + expect(mockedGetCustodianJWTList).toHaveBeenCalled(); + }); + }); + + it('clicks connect button and shows the jwt form', async () => { + const { getByTestId } = renderWithProvider(, store); + const custodyBtn = getByTestId('custody-connect-button'); + + await waitFor(() => { + fireEvent.click(custodyBtn); + }); + + await waitFor(() => { + expect(screen.getByTestId('jwt-form-connect-button')).toBeInTheDocument(); + }); + }); +}); diff --git a/ui/pages/institutional/custody/index.js b/ui/pages/institutional/custody/index.js new file mode 100644 index 000000000..a53ef30e0 --- /dev/null +++ b/ui/pages/institutional/custody/index.js @@ -0,0 +1 @@ +export { default } from './custody'; diff --git a/ui/pages/institutional/custody/index.scss b/ui/pages/institutional/custody/index.scss new file mode 100644 index 000000000..d2f7ef0fa --- /dev/null +++ b/ui/pages/institutional/custody/index.scss @@ -0,0 +1,14 @@ +@import '../../../components/institutional/jwt-dropdown/jwt-dropdown.scss'; +@import '../../../components/institutional/jwt-url-form/jwt-url-form.scss'; + +.custody-accounts-empty { + min-height: 300px; + + &__footer { + border-top: 1px solid var(--color-border-muted); + position: absolute; + width: 100%; + bottom: 0; + left: 0; + } +} diff --git a/ui/pages/pages.scss b/ui/pages/pages.scss index 9d926ccd9..26b50cbfb 100644 --- a/ui/pages/pages.scss +++ b/ui/pages/pages.scss @@ -13,7 +13,11 @@ @import 'connected-sites/index'; @import 'create-account/index'; ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) -@import "create-account/institutional/connect-custody/index"; +@import "institutional/connect-custody/index"; +@import "institutional/custody/index"; +@import "institutional/institutional-entity-done-page/index"; +@import "institutional/compliance-feature-page/index"; +@import "institutional/confirm-add-custodian-token/index"; @import "institutional/interactive-replacement-token-page/index"; ///: END:ONLY_INCLUDE_IN @import 'error/index'; diff --git a/ui/selectors/institutional/selectors.js b/ui/selectors/institutional/selectors.js index b45786188..d8dc5c7d1 100644 --- a/ui/selectors/institutional/selectors.js +++ b/ui/selectors/institutional/selectors.js @@ -71,7 +71,7 @@ export function getMMIAddressFromModalOrAddress(state) { } export function getMMIConfiguration(state) { - return state.metamask.mmiConfiguration; + return state.metamask.mmiConfiguration || []; } export function getInteractiveReplacementToken(state) { From 1253c768c71708ce5847d5419427b6e1fc19705e Mon Sep 17 00:00:00 2001 From: Bernardo Garces Chapero Date: Thu, 27 Apr 2023 12:39:37 +0200 Subject: [PATCH 59/60] Return state when calling EncryptionPublicKeyController.cancelEncryptionPublicKey (#18845) * returns state * adds unit test --- app/scripts/controllers/encryption-public-key.test.ts | 9 +++++++++ app/scripts/controllers/encryption-public-key.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/encryption-public-key.test.ts b/app/scripts/controllers/encryption-public-key.test.ts index cc5b61cc1..cb5581831 100644 --- a/app/scripts/controllers/encryption-public-key.test.ts +++ b/app/scripts/controllers/encryption-public-key.test.ts @@ -352,6 +352,15 @@ describe('EncryptionPublicKeyController', () => { 'Cancel', ); }); + + it('returns current state', async () => { + getStateMock.mockReturnValueOnce(stateMock); + expect( + await encryptionPublicKeyController.cancelEncryptionPublicKey( + messageIdMock, + ), + ).toEqual(stateMock); + }); }); describe('message manager events', () => { diff --git a/app/scripts/controllers/encryption-public-key.ts b/app/scripts/controllers/encryption-public-key.ts index 626413b3f..4ea2c1afe 100644 --- a/app/scripts/controllers/encryption-public-key.ts +++ b/app/scripts/controllers/encryption-public-key.ts @@ -275,7 +275,7 @@ export default class EncryptionPublicKeyController extends BaseControllerV2< * @param msgId - The id of the message to cancel. */ cancelEncryptionPublicKey(msgId: string) { - this._cancelAbstractMessage(this._encryptionPublicKeyManager, msgId); + return this._cancelAbstractMessage(this._encryptionPublicKeyManager, msgId); } /** From 6e4de3bee82a2b9e2117a47079fa9c6de2a27d8d Mon Sep 17 00:00:00 2001 From: seaona <54408225+seaona@users.noreply.github.com> Date: Thu, 27 Apr 2023 13:01:17 +0200 Subject: [PATCH 60/60] [e2e] test-dapp update to `v6.0.0` (#18844) * Test dapp update to v6.0.0 and tweak initial token amounts to adjust to the new contract * Update gas estimates for new TST contract --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- package.json | 2 +- test/e2e/seeder/smart-contracts.js | 2 +- test/e2e/tests/send-eth.spec.js | 4 ++-- test/e2e/tests/send-hex-address.spec.js | 4 ++-- yarn.lock | 10 +++++----- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 2ae4f8c36..969245bb9 100644 --- a/package.json +++ b/package.json @@ -378,7 +378,7 @@ "@metamask/eslint-config-typescript": "^9.0.1", "@metamask/forwarder": "^1.1.0", "@metamask/phishing-warning": "^2.1.0", - "@metamask/test-dapp": "^5.6.0", + "@metamask/test-dapp": "^6.0.0", "@sentry/cli": "^1.58.0", "@storybook/addon-a11y": "^6.5.13", "@storybook/addon-actions": "^6.5.13", diff --git a/test/e2e/seeder/smart-contracts.js b/test/e2e/seeder/smart-contracts.js index fe0f0262a..48d472b4e 100644 --- a/test/e2e/seeder/smart-contracts.js +++ b/test/e2e/seeder/smart-contracts.js @@ -14,7 +14,7 @@ const { } = require('@metamask/test-dapp/dist/constants.json'); const hstFactory = { - initialAmount: 100, + initialAmount: 10, tokenName: 'TST', decimalUnits: 4, tokenSymbol: 'TST', diff --git a/test/e2e/tests/send-eth.spec.js b/test/e2e/tests/send-eth.spec.js index fbc84854b..56c9f744c 100644 --- a/test/e2e/tests/send-eth.spec.js +++ b/test/e2e/tests/send-eth.spec.js @@ -336,11 +336,11 @@ describe('Send ETH from dapp using advanced gas controls', function () { await driver.clickElement({ text: 'Save', tag: 'button' }); await driver.waitForSelector({ css: '.transaction-detail-item:nth-of-type(1) h6:nth-of-type(2)', - text: '0.02367237 ETH', + text: '0.04503836 ETH', }); await driver.waitForSelector({ css: '.transaction-detail-item:nth-of-type(2) h6:nth-of-type(2)', - text: '0.02367237 ETH', + text: '0.04503836 ETH', }); await driver.clickElement({ text: 'Confirm', tag: 'button' }); diff --git a/test/e2e/tests/send-hex-address.spec.js b/test/e2e/tests/send-hex-address.spec.js index 08d7b2c1d..c971f4f01 100644 --- a/test/e2e/tests/send-hex-address.spec.js +++ b/test/e2e/tests/send-hex-address.spec.js @@ -155,7 +155,7 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { }); await driver.waitForSelector({ css: '.transaction-detail-item', - text: '0.00008346 ETH', + text: '0.00008455 ETH', }); await driver.clickElement({ text: 'Next', tag: 'button' }); @@ -220,7 +220,7 @@ describe('Send ERC20 to a 40 character hexadecimal address', function () { }); await driver.waitForSelector({ css: '.transaction-detail-item', - text: '0.00008346 ETH', + text: '0.00008455 ETH', }); await driver.clickElement({ text: 'Next', tag: 'button' }); diff --git a/yarn.lock b/yarn.lock index 6c0a33373..9669cd3b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4435,10 +4435,10 @@ __metadata: languageName: node linkType: hard -"@metamask/test-dapp@npm:^5.6.0": - version: 5.6.0 - resolution: "@metamask/test-dapp@npm:5.6.0" - checksum: 352399ee03a9bee7a2a1045a102d4993a3b4b17a4c2c87b77265924dc6b04659b743f79a08f91bfbeeea3b7cbb9d1a88dc251ec32366877312e9eaa01ce0c82f +"@metamask/test-dapp@npm:^6.0.0": + version: 6.0.0 + resolution: "@metamask/test-dapp@npm:6.0.0" + checksum: eee793c8816d1205667002bd0ef60d248f3a35027937d66a51fd6a87e6eb7be70efd63052412d4dbabdd4329a5e729ab8293655dbdd8d3329bd732b1b1be45d1 languageName: node linkType: hard @@ -23866,7 +23866,7 @@ __metadata: "@metamask/snaps-utils": ^0.32.2 "@metamask/subject-metadata-controller": ^2.0.0 "@metamask/swappable-obj-proxy": ^2.1.0 - "@metamask/test-dapp": ^5.6.0 + "@metamask/test-dapp": ^6.0.0 "@metamask/utils": ^5.0.0 "@ngraveio/bc-ur": ^1.1.6 "@popperjs/core": ^2.4.0