@@ -190,29 +190,112 @@ function _unregisterServiceWorkers() {
190190
191191const 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