luci-base: luci.js: rework error handling
authorJo-Philipp Wich <jo@mein.io>
Wed, 11 Sep 2019 07:28:21 +0000 (09:28 +0200)
committerJo-Philipp Wich <jo@mein.io>
Wed, 11 Sep 2019 10:21:05 +0000 (12:21 +0200)
 - Capture stack trace in L.raise() if passed type is not an Error instance
 - Use L.ui.addNotification in L.error() to render the error message
 - Prevent duplicate error reporting in the ui

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
modules/luci-base/htdocs/luci-static/resources/luci.js

index 80648633dfba9bac2093e5f7ba9ead0185916642..0b9886680596d1b9af8c06721a991f86823fa1db 100644 (file)
 
                        if (type instanceof Error) {
                                e = type;
-                               stack = (e.stack || '').split(/\n/);
 
                                if (msg)
                                        e.message = msg + ': ' + e.message;
                        }
                        else {
+                               try { throw new Error('stacktrace') }
+                               catch (e2) { stack = (e2.stack || '').split(/\n/) }
+
                                e = new (window[type || 'Error'] || Error)(msg || 'Unspecified error');
                                e.name = type || 'Error';
                        }
 
+                       stack = (stack || []).map(function(frame) {
+                               frame = frame.replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim();
+                               return frame ? '  ' + frame : '';
+                       });
+
+                       if (!/^  at /.test(stack[0]))
+                               stack.shift();
+
+                       if (/\braise /.test(stack[0]))
+                               stack.shift();
+
+                       if (/\berror /.test(stack[0]))
+                               stack.shift();
+
+                       if (stack.length)
+                               e.message += '\n' + stack.join('\n');
+
                        if (window.console && console.debug)
                                console.debug(e);
 
                                L.raise.apply(L, Array.prototype.slice.call(arguments));
                        }
                        catch (e) {
-                               var stack = (e.stack || '').split(/\n/).map(function(frame) {
-                                       frame = frame.replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim();
-                                       return frame ? '  ' + frame : '';
-                               });
-
-                               if (!/^  at /.test(stack[0]))
-                                       stack.shift();
-
-                               if (/\braise /.test(stack[0]))
-                                       stack.shift();
-
-                               if (/\berror /.test(stack[0]))
-                                       stack.shift();
-
-                               stack = stack.length ? '\n' + stack.join('\n') : '';
+                               if (!e.reported) {
+                                       if (L.ui)
+                                               L.ui.addNotification(e.name || _('Runtime error'),
+                                                       E('pre', {}, e.message), 'danger');
+                                       else
+                                               L.dom.content(document.querySelector('#maincontent'),
+                                                       E('pre', { 'class': 'alert-message error' }, e.message));
 
-                               if (L.ui)
-                                       L.ui.showModal(e.name || _('Runtime error'),
-                                               E('pre', { 'class': 'alert-message error' }, e.message + stack));
-                               else
-                                       L.dom.content(document.querySelector('#maincontent'),
-                                               E('pre', { 'class': 'alert-message error' }, e + stack));
+                                       e.reported = true;
+                               }
 
                                throw e;
                        }