Skip to content

Commit 763d6cc

Browse files
runway-github[bot]MajorLiftDDDDDanica
authored
release(runway): cherry-pick feat: Add MetaMetrics event to "Infinite spinner" error screen cp-13.3.0 (#35851)
- feat: Add MetaMetrics event to "Infinite spinner" error screen cp-13.3.0 (#35619) <!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** This PR implements user-controlled error reporting on the critical error screen, allowing users to opt into sending crash reports to help with debugging while maintaining transparency about data collection. **Error Reporting Checkbox:** - Added checkbox above restart button with "Report this error" text - Checkbox pre-selected by default - Info icon (ℹ️) next to checkbox text **Legal Text Popover:** - Info icon shows popover with legal text on click - A bit styling with rounded corners and shadow - Explains data collection and privacy policy **Sentry Integration:** - Checkbox checked → sends error to Sentry via fetch API on restart - Checkbox unchecked → no data sent, just restarts MetaMask - Includes error details, user agent, extension version <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> [![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/MetaMask/metamask-extension/pull/35619?quickstart=1) ## **Changelog** <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry: Added checkbox for emitting Sentry event when restarting MetaMask from error page ## **Related issues** Fixes: https://github.com/MetaMask/MetaMask-planning/issues/5651 ## **Manual testing steps** 1. open the extension's devtools 2. execute the following code (its creates an invalid state object): ``` // browser and chrome are NOT scuttled in test builds, so we can use them // to access the storage API here const browser = globalThis.browser ?? globalThis.chrome; // corrupt the primary database by setting `meta` to `null` browser.storage.local.set({ meta: null }, () => { browser.runtime.reload() }); ``` 3. open the popup. The error modal should be displayed to the user. 4. Click i icon beside "report this error" should show a popover of legal text 5. Click restart metamask, should see a request sending to sentry before reloading 6. If uncheck the checkbox "report this error", there won't be any request sending to sentry before reloading ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> **Recording:** https://www.loom.com/share/876c2fefb7224c1da85c14d2538d9ca2?sid=3e5835e7-2ec5-4277-ac01-ba072460b602 **Screenshot: ** <img width="406" height="606" alt="Screenshot 2025-09-10 at 00 36 43" src="https://github.com/user-attachments/assets/9d152017-e3ce-4da5-81dc-b4f8e5434a23" /> <img width="403" height="605" alt="Screenshot 2025-09-10 at 00 36 48" src="https://github.com/user-attachments/assets/386ccd0a-3fde-48f0-b3dc-acbbe18a01aa" /> ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Extension Coding Standards](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: dddddanica <[email protected]> [5adb0e7](5adb0e7) Co-authored-by: Jongsun Suh <[email protected]> Co-authored-by: dddddanica <[email protected]>
1 parent 604f567 commit 763d6cc

File tree

7 files changed

+563
-16
lines changed

7 files changed

+563
-16
lines changed

app/_locales/en/messages.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/_locales/en_GB/messages.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

shared/lib/error-utils.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,21 @@ export async function maybeGetLocaleContext(currentLocale) {
8989
*
9090
* @param {import('../../ui/helpers/utils/display-critical-error').CriticalErrorTranslationKey} errorKey - The key for the error message.
9191
* @param {ErrorLike} error - The error object to log.
92-
* @param {{preferredLocale: string, t: (string) => string}} localeContext - The MetaMask state containing the current locale.
92+
* @param {{preferredLocale: string, t: (string) => string}} localeContext - The MetaMask state containing the current locale and translation function.
9393
* @param {string} [supportLink] - The support link to include in the footer.
9494
* @returns {string} The HTML string for the critical error message.
9595
*/
9696
export function getErrorHtml(errorKey, error, localeContext, supportLink) {
9797
switchDirectionForPreferredLocale(localeContext.preferredLocale);
9898
const { t } = localeContext;
9999

100+
const legalText = `
101+
<span>${lodashEscape(t('errorLegalTextSummary'))}</span>
102+
<p>• ${lodashEscape(t('errorLegalTextFirstInfo'))}</p>
103+
<p>• ${lodashEscape(t('errorLegalTextSecondInfo'))}</p>
104+
<span>${lodashEscape(t('errorLegalTextNoPersonalInfo'))}</span>
105+
`;
106+
100107
const footer = supportLink
101108
? `
102109
<p class="critical-error__footer">
@@ -106,7 +113,7 @@ export function getErrorHtml(errorKey, error, localeContext, supportLink) {
106113
class="critical-error__link"
107114
target="_blank"
108115
rel="noopener noreferrer">
109-
${lodashEscape(t('sendBugReport'))}
116+
${lodashEscape(t('errorPageContactSupport'))}
110117
</a>
111118
</p>
112119
`
@@ -131,7 +138,39 @@ export function getErrorHtml(errorKey, error, localeContext, supportLink) {
131138
${errorKey === 'somethingIsWrong' ? t('somethingIsWrong') : ''}
132139
</p>
133140
${detailsRawHtml}
134-
<button id="critical-error-button" class="critical-error__button-restore button btn-primary">
141+
<label class="critical-error__report">
142+
<input
143+
id="critical-error-checkbox"
144+
type="checkbox"
145+
checked
146+
class="critical-error__report-checkbox"
147+
/>
148+
<span class="critical-error__report-text">
149+
${lodashEscape(t('reportThisError'))}
150+
</span>
151+
<button
152+
id="critical-error-tip-anchor"
153+
popovertarget="critical-error-legal-text"
154+
type="button"
155+
class="critical-error__info"
156+
>
157+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="critical-error__info-icon">
158+
<path d="m11 17h2v-6h-2zm1-8c.2833 0 .5208-.09583.7125-.2875s.2875-.42917.2875-.7125-.0958-.52083-.2875-.7125-.4292-.2875-.7125-.2875-.5208.09583-.7125.2875-.2875.42917-.2875.7125.0958.52083.2875.7125.4292.2875.7125.2875zm0 13c-1.3833 0-2.68333-.2625-3.9-.7875s-2.275-1.2375-3.175-2.1375-1.6125-1.9583-2.1375-3.175-.7875-2.5167-.7875-3.9.2625-2.68333.7875-3.9 1.2375-2.275 2.1375-3.175 1.95833-1.6125 3.175-2.1375 2.5167-.7875 3.9-.7875 2.6833.2625 3.9.7875 2.275 1.2375 3.175 2.1375 1.6125 1.95833 2.1375 3.175.7875 2.5167.7875 3.9-.2625 2.6833-.7875 3.9-1.2375 2.275-2.1375 3.175-1.9583 1.6125-3.175 2.1375-2.5167.7875-3.9.7875zm0-2c2.2333 0 4.125-.775 5.675-2.325s2.325-3.4417 2.325-5.675c0-2.23333-.775-4.125-2.325-5.675s-3.4417-2.325-5.675-2.325c-2.23333 0-4.125.775-5.675 2.325s-2.325 3.44167-2.325 5.675c0 2.2333.775 4.125 2.325 5.675s3.44167 2.325 5.675 2.325z"/>
159+
</svg>
160+
</button>
161+
</label>
162+
<div
163+
popover
164+
anchor="critical-error-tip-anchor"
165+
id="critical-error-legal-text"
166+
class="critical-error__legal-text"
167+
>
168+
${legalText}
169+
</div>
170+
<button
171+
id="critical-error-button"
172+
class="critical-error__button-restore button btn-primary"
173+
title="Report this error and restart MetaMask">
135174
${lodashEscape(t('restartMetamask'))}
136175
</button>
137176
${footer}

shared/lib/error-utils.test.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ describe('Error utils Tests', function () {
5050
stillGettingMessage: {
5151
message: 'Still getting this message?',
5252
},
53-
sendBugReport: {
54-
message: 'Send us a bug report.',
53+
errorPageContactSupport: {
54+
message: 'Contact support',
5555
},
5656
},
5757
},
@@ -77,12 +77,13 @@ describe('Error utils Tests', function () {
7777
const restartMetamaskMessage = currentLocale.restartMetamask.message;
7878
const stillGettingMessageMessage =
7979
currentLocale.stillGettingMessage.message;
80-
const sendBugReportMessage = currentLocale.sendBugReport.message;
80+
const errorPageContactSupport =
81+
currentLocale.errorPageContactSupport.message;
8182

8283
expect(errorHtml).toContain(troubleStartingMessage);
8384
expect(errorHtml).toContain(troubleStartingTitle);
8485
expect(errorHtml).toContain(restartMetamaskMessage);
8586
expect(errorHtml).toContain(stillGettingMessageMessage);
86-
expect(errorHtml).toContain(sendBugReportMessage);
87+
expect(errorHtml).toContain(errorPageContactSupport);
8788
});
8889
});

ui/css/errors.scss

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
border-radius: 4px;
44
border-left: var(--color-warning-default) 4px solid;
55
background-color: var(--color-warning-muted);
6-
color: inherit; // Required to inherit color set from prefers-color-scheme
6+
color: inherit; // Required to inherit color set from prefers-color-schem
77
display: flex;
88
padding: 12px 12px 12px 8px;
99
gap: 8px;
1010
line-height: 24px;
11+
height: 92vh;
1112

1213
& h1 {
1314
font-size: 20px;
@@ -26,7 +27,6 @@
2627
> span {
2728
flex: 0 0 auto;
2829
max-width: 100%;
29-
padding-inline-end: 8px;
3030
}
3131
}
3232

@@ -50,14 +50,92 @@
5050

5151
& p {
5252
margin: 1em 0;
53-
54-
&.small {
55-
font-size: 12px;
56-
}
5753
}
5854

5955
&__details {
6056
max-height: 10em;
6157
overflow: auto;
6258
}
59+
60+
&__legal-text {
61+
position: fixed;
62+
top: 158px;
63+
left: -8px;
64+
background-color: var(--color-background-default);
65+
border-radius: 12px;
66+
padding: 20px;
67+
max-width: 320px;
68+
text-align: left;
69+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
70+
border: 1px solid rgba(0, 0, 0, 0.08);
71+
color: var(--color-text-default);
72+
font-size: 14px;
73+
line-height: 1.2;
74+
z-index: 1000;
75+
76+
span {
77+
display: block;
78+
margin-bottom: 12px;
79+
font-weight: 500;
80+
}
81+
82+
p {
83+
margin: 8px 0;
84+
font-weight: 400;
85+
}
86+
}
87+
88+
&__report {
89+
display: flex;
90+
align-items: center;
91+
cursor: pointer;
92+
font-size: 14px;
93+
user-select: none;
94+
margin-bottom: 8px;
95+
}
96+
97+
&__report-checkbox {
98+
appearance: none;
99+
-webkit-appearance: none;
100+
width: 18px;
101+
height: 18px;
102+
border-radius: 4px;
103+
display: inline-flex;
104+
align-items: center;
105+
justify-content: center;
106+
cursor: pointer;
107+
transition: background 0.2s ease;
108+
position: relative;
109+
margin-right: 4px;
110+
background-color: var(--color-background-default);
111+
border: 2px solid var(--color-border-default);
112+
}
113+
114+
&__report-checkbox:checked {
115+
background-color: var(--color-primary-default);
116+
border: none;
117+
}
118+
119+
&__report-checkbox:checked::after {
120+
content: "";
121+
position: absolute;
122+
width: 5px;
123+
height: 10px;
124+
border: solid var(--color-primary-inverse);
125+
border-width: 0 2px 2px 0;
126+
transform: rotate(45deg);
127+
}
128+
129+
&__info {
130+
background: none;
131+
border: none;
132+
cursor: pointer;
133+
margin-left: 4px;
134+
135+
&-icon {
136+
width: 18px;
137+
height: 18px;
138+
fill: var(--color-primary-default);
139+
}
140+
}
63141
}

0 commit comments

Comments
 (0)