Skip to content

Commit 35c8ac1

Browse files
committed
chore: new crash recovery dialog ux
1 parent a686ee4 commit 35c8ac1

File tree

1 file changed

+126
-23
lines changed

1 file changed

+126
-23
lines changed

src/main.js

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -190,29 +190,112 @@ function _unregisterServiceWorkers() {
190190

191191
const SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR = "SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR";
192192

193-
async function _recoverOnFailure(err) {
194-
if (!Phoenix.isNativeApp && !navigator.onLine) {
195-
alert('No internet connection. Please check your connection and reload page.');
196-
return;
197-
}
198-
// metrics api might not be available here as we were seeing no metrics raised. Only bugsnag there.
199-
window.logger && window.logger.reportError(err,
200-
'Critical error when loading brackets. Trying to reload again.');
201-
const restartedOnce = sessionStorage.getItem(SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR);
202-
let shouldRestart;
203-
if(!restartedOnce){
204-
sessionStorage.setItem(SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR, "true");
205-
shouldRestart = true;
206-
} else {
207-
shouldRestart = confirm("Oops! Something went wrong. Reload app?");
208-
if(shouldRestart instanceof Promise){
209-
shouldRestart = await shouldRestart;
193+
function confirmReload(title, message) {
194+
// vanilla js elements as we dont know if anything else is available in crash scenario
195+
const modal = document.createElement('div');
196+
const modalContent = document.createElement('div');
197+
const modalTitle = document.createElement('h2');
198+
const modalMessage = document.createElement('p');
199+
const buttonsContainer = document.createElement('div'); // Container for buttons
200+
const copyButton = document.createElement('button');
201+
const getHelpButton = document.createElement('button');
202+
const reloadButton = document.createElement('button');
203+
204+
// Set content
205+
modalTitle.textContent = title;
206+
message.split('\n').forEach((part, index, array) => {
207+
modalMessage.appendChild(document.createTextNode(part));
208+
if (index < array.length - 1) { // Don't add a break on the last element
209+
modalMessage.appendChild(document.createElement('br'));
210210
}
211-
}
212-
if(!shouldRestart) {
213-
return;
214-
}
211+
});
212+
copyButton.textContent = 'Copy Error';
213+
getHelpButton.textContent = 'Get Help';
214+
reloadButton.textContent = 'Reload Page';
215+
216+
// Styling for visibility
217+
modalTitle.style.color = 'red';
218+
modal.style.color = 'black';
219+
modal.style.position = 'fixed';
220+
modal.style.top = '0';
221+
modal.style.left = '0';
222+
modal.style.width = '100%';
223+
modal.style.height = '100%';
224+
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.75)';
225+
modal.style.zIndex = '10000000'; // Ensure modal is on top
226+
modal.style.display = 'flex';
227+
modal.style.justifyContent = 'center';
228+
modal.style.alignItems = 'center';
229+
230+
modalContent.style.backgroundColor = 'white';
231+
modalContent.style.padding = '20px';
232+
modalContent.style.borderRadius = '10px';
233+
modalContent.style.textAlign = 'center';
234+
modalContent.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
235+
236+
// Styling buttons and their container
237+
buttonsContainer.style.marginTop = '20px';
238+
buttonsContainer.style.display = 'flex';
239+
buttonsContainer.style.justifyContent = 'space-around'; // Space buttons nicely
240+
241+
copyButton.style.padding = '10px 20px';
242+
copyButton.style.marginRight = '10px'; // Space between buttons
243+
copyButton.style.border = 'none';
244+
copyButton.style.color = 'white';
245+
copyButton.style.backgroundColor = '#288edf';
246+
copyButton.style.borderRadius = '5px';
247+
copyButton.style.cursor = 'pointer';
248+
249+
getHelpButton.style.padding = '10px 20px';
250+
getHelpButton.style.marginRight = '10px'; // Space between buttons
251+
getHelpButton.style.border = 'none';
252+
getHelpButton.style.color = 'white';
253+
getHelpButton.style.backgroundColor = '#4CAF50';
254+
getHelpButton.style.borderRadius = '5px';
255+
getHelpButton.style.cursor = 'pointer';
256+
257+
reloadButton.style.padding = '10px 20px';
258+
reloadButton.style.border = 'none';
259+
reloadButton.style.color = 'white';
260+
reloadButton.style.backgroundColor = '#4CAF50';
261+
reloadButton.style.borderRadius = '5px';
262+
reloadButton.style.cursor = 'pointer';
263+
264+
// Event listeners for buttons
265+
copyButton.onclick = function() {
266+
navigator.clipboard.writeText(message).then(() => {
267+
alert('Error Message copied!');
268+
}, (err) => {
269+
console.error('Failed to copy text: ', err);
270+
});
271+
};
272+
getHelpButton.onclick = function() {
273+
Phoenix.app.openURLInDefaultBrowser("https://github.com/phcode-dev/phoenix/discussions");
274+
};
275+
276+
// Append children
277+
modalContent.appendChild(modalTitle);
278+
modalContent.appendChild(modalMessage);
279+
buttonsContainer.appendChild(copyButton);
280+
buttonsContainer.appendChild(getHelpButton);
281+
buttonsContainer.appendChild(reloadButton);
282+
modalContent.appendChild(buttonsContainer);
283+
modal.appendChild(modalContent);
215284

285+
// Append modal to the body
286+
document.body.appendChild(modal);
287+
288+
return new Promise(resolve =>{
289+
reloadButton.onclick = function() {
290+
resolve(true);
291+
reloadButton.textContent = 'Reloading...';
292+
reloadButton.style.color = 'darkgray';
293+
reloadButton.style.backgroundColor = 'grey';
294+
};
295+
});
296+
}
297+
298+
function resetCacheAndRestart() {
216299
// try a cache reset
217300
if(window._resetCacheIfNeeded){
218301
window._resetCacheIfNeeded(true)
@@ -233,9 +316,29 @@ async function _recoverOnFailure(err) {
233316
}
234317
}
235318

236-
define(function (require) {
237-
319+
async function _recoverOnFailure(err) {
320+
if (!Phoenix.isNativeApp && !navigator.onLine) {
321+
alert('No internet connection. Please check your connection and reload page.');
322+
return;
323+
}
324+
// metrics api might not be available here as we were seeing no metrics raised. Only bugsnag there.
325+
window.logger && window.logger.reportError(err,
326+
'Critical error when loading brackets. Trying to reload again.');
327+
const restartedOnce = sessionStorage.getItem(SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR);
328+
let shouldRestart;
329+
if(!restartedOnce){
330+
sessionStorage.setItem(SESSION_RESTART_ONCE_DUE_TO_CRITICAL_ERROR, "true");
331+
shouldRestart = true;
332+
} else {
333+
shouldRestart = await confirmReload('Oops! Something went wrong', (err.message +"\n"+ err.stack)||err);
334+
}
335+
if(!shouldRestart) {
336+
return;
337+
}
338+
resetCacheAndRestart();
339+
}
238340

341+
define(function (require) {
239342
// Load compatibility shims--these need to load early, be careful moving this
240343
// Event dispatcher must be loaded before worker comm https://github.com/phcode-dev/phoenix/pull/678
241344
require(["utils/Metrics", "utils/Compatibility", "utils/EventDispatcher"], function () {

0 commit comments

Comments
 (0)