diff --git a/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/__manifest__.py index 7e7c9a77086..7bf4d9127bd 100644 --- a/addons/point_of_sale/__manifest__.py +++ b/addons/point_of_sale/__manifest__.py @@ -194,7 +194,6 @@ 'point_of_sale.qunit_suite_tests': [ 'web/static/tests/legacy/component_extension_tests.js', 'point_of_sale/static/tests/unit/**/*', - ('remove', 'point_of_sale/static/tests/unit/helpers/test_main.js') ], 'point_of_sale.assets_backend_prod_only': [ 'point_of_sale/static/src/js/chrome_adapter.js', diff --git a/addons/point_of_sale/static/tests/unit/helpers/test_main.js b/addons/point_of_sale/static/tests/unit/helpers/test_main.js deleted file mode 100644 index f42e01cbd6e..00000000000 --- a/addons/point_of_sale/static/tests/unit/helpers/test_main.js +++ /dev/null @@ -1,23 +0,0 @@ -odoo.define('web.web_client', function (require) { - // this module is required by the test - const { bus } = require('web.core'); - const WebClient = require('web.AbstractWebClient'); - - // listen to unhandled rejected promises, and when the rejection is not due - // to a crash, prevent the browser from displaying an 'unhandledrejection' - // error in the console, which would make tests crash on each Promise.reject() - // something similar is done by the CrashManagerService, but by default, it - // isn't deployed in tests - bus.on('crash_manager_unhandledrejection', this, function (ev) { - if (!ev.reason || !(ev.reason instanceof Error)) { - ev.stopPropagation(); - ev.stopImmediatePropagation(); - ev.preventDefault(); - } - }); - - owl.config.mode = "dev"; - - const webClient = new WebClient(); - return webClient; -}); diff --git a/addons/web/__manifest__.py b/addons/web/__manifest__.py index e596e50b492..62305f57316 100644 --- a/addons/web/__manifest__.py +++ b/addons/web/__manifest__.py @@ -204,7 +204,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/js/services/session.js', 'web/static/src/legacy/js/public/public_env.js', - 'web/static/src/legacy/js/public/public_crash_manager.js', 'web/static/src/legacy/js/public/public_root.js', 'web/static/src/legacy/js/public/public_root_instance.js', 'web/static/src/legacy/js/public/public_widget.js', @@ -396,7 +395,6 @@ This module provides the core of the Odoo Web Client. 'web/static/src/legacy/js/services/config.js', 'web/static/src/legacy/js/services/core.js', 'web/static/src/legacy/js/services/local_storage_service.js', - 'web/static/src/legacy/js/services/crash_manager.js', 'web/static/src/legacy/js/core/error_utils.js', 'web/static/src/legacy/js/services/session_storage_service.js', 'web/static/src/legacy/js/common_env.js', @@ -408,7 +406,6 @@ This module provides the core of the Odoo Web Client. # Used during the transition of the web architecture 'web.frontend_legacy': [ - # Old rainbow man kept for website compatibility 'web/static/src/legacy/frontend/**/*', ], diff --git a/addons/web/static/src/core/network/rpc_service.js b/addons/web/static/src/core/network/rpc_service.js index 0bf6056a51c..e2261754650 100644 --- a/addons/web/static/src/core/network/rpc_service.js +++ b/addons/web/static/src/core/network/rpc_service.js @@ -25,7 +25,7 @@ export class ConnectionAbortedError extends Error {} // ----------------------------------------------------------------------------- // Main RPC method // ----------------------------------------------------------------------------- -function makeErrorFromResponse(reponse) { +export function makeErrorFromResponse(reponse) { // Odoo returns error like this, in a error field instead of properly // using http error codes... const { code, data: errorData, message, type: subType } = reponse; diff --git a/addons/web/static/src/legacy/frontend/public_crash_manager/public_crash_manager.js b/addons/web/static/src/legacy/frontend/public_crash_manager/public_crash_manager.js new file mode 100644 index 00000000000..a9942498278 --- /dev/null +++ b/addons/web/static/src/legacy/frontend/public_crash_manager/public_crash_manager.js @@ -0,0 +1,398 @@ +odoo.define('web.CrashManager', function (require) { + "use strict"; + + const AbstractService = require('web.AbstractService'); + var ajax = require('web.ajax'); + var core = require('web.core'); + var Dialog = require('web.Dialog'); + var Widget = require('web.Widget'); + var config = require('web.config'); + var { formatTraceback, annotateTraceback } = require("@web/legacy/js/core/error_utils"); + + var _t = core._t; + var _lt = core._lt; + + // Register this eventlistener before qunit does. + // Some errors needs to be negated by the crash_manager. + window.addEventListener('unhandledrejection', ev => + core.bus.trigger('crash_manager_unhandledrejection', ev) + ); + + let active = true; + + /** + * An extension of Dialog Widget to render the warnings and errors on the website. + * Extend it with your template of choice like ErrorDialog/WarningDialog + */ + var CrashManagerDialog = Dialog.extend({ + xmlDependencies: (Dialog.prototype.xmlDependencies || []).concat( + ['/web/static/src/legacy/frontend/public_crash_manager/public_crash_manager.xml'] + ), + + /** + * @param {Object} error + * @param {string} error.message the message in Warning/Error Dialog + * @param {string} error.traceback the traceback in ErrorDialog + * + * @constructor + */ + init: function (parent, options, error) { + this._super.apply(this, [parent, options]); + this.error = error; + this.message = error.message; + this.traceback = error.traceback; + core.bus.off('close_dialogs', this); + }, + + willStart: async function () { + await this._super() + const jsError = this.error.data && this.error.data.jsError; + if (jsError) { + if (config.isDebug('assets')) { + this.traceback = await annotateTraceback(jsError); + } else { + this.traceback = formatTraceback(jsError); + } + } + }, + + start: async function () { + await this._super(); + const message = this.message; + const traceback = this.traceback; + + if (!traceback) { + return; + } + this.$(".o_error_detail").on("shown.bs.collapse", function (e) { + e.target.scrollTop = e.target.scrollHeight; + }); + + const $clipboardBtn = this.$(".o_clipboard_button"); + $clipboardBtn.tooltip({title: _t("Copied !"), trigger: "manual", placement: "left"}); + this.clipboard = new window.ClipboardJS($clipboardBtn[0], { + text: function () { + return (_t("Error") + ":\n" + message + "\n\n" + traceback).trim(); + }, + // Container added because of Bootstrap modal that give the focus to another element. + // We need to give to correct focus to ClipboardJS (see in ClipboardJS doc) + // https://github.com/zenorocha/clipboard.js/issues/155 + container: this.el, + }); + this.clipboard.on("success", function (e) { + _.defer(function () { + $clipboardBtn.tooltip("show"); + _.delay(function () { + $clipboardBtn.tooltip("hide"); + }, 800); + }); + }); + }, + destroy() { + if (this.clipboard) { + this.$(".o_clipboard_button").tooltip('dispose'); + this.clipboard.destroy(); + } + this._super(); + } + }); + + var ErrorDialog = CrashManagerDialog.extend({ + template: 'CrashManager.error', + }); + + var WarningDialog = CrashManagerDialog.extend({ + template: 'CrashManager.warning', + + /** + * Sets size to medium by default. + * + * @override + */ + init: function (parent, options, error) { + this._super(parent, _.extend({ + size: 'medium', + }, options), error); + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Focuses the ok button. + * + * @override + */ + open: function () { + this._super({shouldFocusButtons: true}); + }, + }); + + var CrashManager = AbstractService.extend({ + init: function () { + var self = this; + active = true; + this.isConnected = true; + this.odooExceptionTitleMap = { + 'odoo.addons.base.models.ir_mail_server.MailDeliveryException': _lt("MailDeliveryException"), + 'odoo.exceptions.AccessDenied': _lt("Access Denied"), + 'odoo.exceptions.AccessError': _lt("Access Error"), + 'odoo.exceptions.MissingError': _lt("Missing Record"), + 'odoo.exceptions.UserError': _lt("User Error"), + 'odoo.exceptions.ValidationError': _lt("Validation Error"), + 'odoo.exceptions.Warning': _lt("Warning"), + }; + + this._super.apply(this, arguments); + + // crash manager integration + core.bus.on('rpc_error', this, this.rpc_error); + window.onerror = function (message, file, line, col, error) { + // Scripts injected in DOM (eg: google API's js files) won't return a clean error on window.onerror. + // The browser will just give you a 'Script error.' as message and nothing else for security issue. + // To enable onerror to work properly with CORS file, you should: + // 1. add crossorigin="anonymous" to your