[IMP] web, http, http_routing, *: new asset for test files
Coming with https://github.com/odoo/enterprise/pull/4281 This commit goal is to encapsulate every tour-test into a separate assets bundle that would be called only during tests (command line) or by URL (debug=tests). That way, a lot of .js files would not be loaded anymore uselessly outside test mode and will speed up the page loads (especially in the frontend as the backend do not reload the page anyway). In order to do that, we needed to propagate the `debug` state from page to page. Otherwise, every page change during a test would simply lose the debug mode and the test would stop as the test assets would not be loaded. As we could not add the `&debug=tests` on every link (either hardcoded or preprocess during the rendering), it has been decided to store it in session. Technical summary: 1. `debug` state (currently only stored in URL) will be stored in session. Either when adding the `debug` param in URL (handled with _dispatch) or by starting Odoo with `test-enable` or `test-file` (handled by session init). 2. Once activated (and so set in session), debug mode will be remain activated even if not visible in URL (after a page navigation eg). To remove it, set its value to nothing, `debug=`. That will exit debug mode (whatever mode it is: debug, assets, tests). 3. As tour-test files are now in a separate bundle, every layout (when needed) should `t-call="web.compiled_assets_tests"`. As it would be redundant and verbose, no `t-if` is needed on the t-call to load it only in test debug mode. That will be handled by `compiled_assets_tests` that will actually do the conditionnal t-call-assets to web.assets_tests, if tests debug mode is activated. 4. In addition to separating the tour-tests files in a separate bundle, we also moved those files to a specific folder under /static/tests/tours next to QUnit tests. 5. Also, tour files will be moved in a specific folder /static/src/js/tours for cleanness purpose (those files will still be kept in their 'normal' assets as needed outside test mode since it is tours). closes odoo/odoo#33213 Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
This commit is contained in:
@@ -20,14 +20,13 @@
|
|||||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_action.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_action.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_model.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_model.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_renderer.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/reconciliation/reconciliation_renderer.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/reconciliation/tour_reconciliation.js"></script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="/account/static/src/js/account_payment_field.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/account_payment_field.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/mail_activity.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/mail_activity.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="/account/static/src/js/bank_statement.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/bank_statement.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/section_and_note_fields_backend.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/section_and_note_fields_backend.js"></script>
|
||||||
<script type="text/javascript" src="/account/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/account/static/src/js/tours/account.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="/account/static/src/js/bills_tree_upload.js"/>
|
<script type="text/javascript" src="/account/static/src/js/bills_tree_upload.js"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -39,6 +38,12 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Account Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/account/static/tests/tours/reconciliation.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template id="qunit_suite" name="account tests" inherit_id="web.qunit_suite">
|
<template id="qunit_suite" name="account tests" inherit_id="web.qunit_suite">
|
||||||
<xpath expr="//script[contains(@src, '/web/static/tests/views/kanban_tests.js')]" position="after">
|
<xpath expr="//script[contains(@src, '/web/static/tests/views/kanban_tests.js')]" position="after">
|
||||||
<script type="text/javascript" src="/account/static/tests/reconciliation_tests.js"></script>
|
<script type="text/javascript" src="/account/static/tests/reconciliation_tests.js"></script>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ odoo.define('base_import.import', function (require) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AbstractAction = require('web.AbstractAction');
|
var AbstractAction = require('web.AbstractAction');
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var session = require('web.session');
|
var session = require('web.session');
|
||||||
var time = require('web.time');
|
var time = require('web.time');
|
||||||
@@ -414,7 +415,7 @@ var DataImport = AbstractAction.extend({
|
|||||||
|
|
||||||
var $thing = $();
|
var $thing = $();
|
||||||
var bind = function (d) {};
|
var bind = function (d) {};
|
||||||
if (session.debug) {
|
if (config.isDebug()) {
|
||||||
$thing = $(QWeb.render('ImportView.create_record_option')).insertAfter(v).hide();
|
$thing = $(QWeb.render('ImportView.create_record_option')).insertAfter(v).hide();
|
||||||
bind = function (data) {
|
bind = function (data) {
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_backend" name="crm assets" inherit_id="web.assets_backend">
|
<template id="assets_backend" name="crm assets" inherit_id="web.assets_backend">
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<link rel="stylesheet" href="/crm/static/src/css/crm.css"/>
|
<link rel="stylesheet" href="/crm/static/src/css/crm.css"/>
|
||||||
<script type="text/javascript" src="/crm/static/src/js/tour.js"></script>
|
</xpath>
|
||||||
</xpath>
|
</template>
|
||||||
</template>
|
<template id="assets_tests" name="CRM Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/crm/static/src/js/tours/crm.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_view.js"></script>
|
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_view.js"></script>
|
||||||
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_widget_mixin.js"></script>
|
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_widget_mixin.js"></script>
|
||||||
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_widget.js"></script>
|
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_widget.js"></script>
|
||||||
<script type="text/javascript" src="/event_sale/static/src/js/event_configurator_test_ui.js"></script>
|
</xpath>
|
||||||
|
</template>
|
||||||
|
<template id="assets_tests" name="Event Sale Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/event_sale/static/tests/tours/event_configurator_ui.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
<template id="qunit_suite" inherit_id="web.qunit_suite" name="event_sale_tests">
|
<template id="qunit_suite" inherit_id="web.qunit_suite" name="event_sale_tests">
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_backend" inherit_id="web.assets_backend" name="event_sale_product_configurator assets backend">
|
<template id="assets_backend" inherit_id="web.assets_backend" name="event_sale_product_configurator assets backend">
|
||||||
<xpath expr="script[last()]" position="after">
|
<xpath expr="script[last()]" position="after">
|
||||||
<script type="text/javascript" src="/event_sale_product_configurator/static/src/js/event_configurator_test_ui.js"></script>
|
|
||||||
<script type="text/javascript" src="/event_sale_product_configurator/static/src/js/product_configurator_widget.js"></script>
|
<script type="text/javascript" src="/event_sale_product_configurator/static/src/js/product_configurator_widget.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Event Sale Product Configurator Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/event_sale_product_configurator/static/tests/tours/event_configurator_ui.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<data>
|
<data>
|
||||||
<template id="assets_backend_expense" name="hr_expense assets" inherit_id="web.assets_backend">
|
<template id="assets_tests" name="HR Expense Assets Tests" inherit_id="web.assets_tests">
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/hr_expense/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/hr_expense/static/src/js/tours/hr_expense.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -5,7 +5,11 @@
|
|||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<link rel="stylesheet" type="text/scss" href="/hr_recruitment/static/src/scss/hr_job.scss"/>
|
<link rel="stylesheet" type="text/scss" href="/hr_recruitment/static/src/scss/hr_job.scss"/>
|
||||||
<script type="text/javascript" src="/hr_recruitment/static/src/js/recruitment.js"></script>
|
<script type="text/javascript" src="/hr_recruitment/static/src/js/recruitment.js"></script>
|
||||||
<script type="text/javascript" src="/hr_recruitment/static/src/js/tour.js"></script>
|
</xpath>
|
||||||
|
</template>
|
||||||
|
<template id="assets_tests" name="HR Recruitment Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/hr_recruitment/static/src/js/tours/hr_recruitment.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class Proxy(http.Controller):
|
|||||||
<p>The list of connected USB devices as seen by the IoTBox</p>
|
<p>The list of connected USB devices as seen by the IoTBox</p>
|
||||||
"""
|
"""
|
||||||
if debug is None:
|
if debug is None:
|
||||||
resp += """(<a href="/hw_proxy/status?debug">debug version</a>)"""
|
resp += """(<a href="/hw_proxy/status?debug=1">debug version</a>)"""
|
||||||
devices = subprocess.check_output("lsusb").decode('utf-8').split('\n')
|
devices = subprocess.check_output("lsusb").decode('utf-8').split('\n')
|
||||||
count = 0
|
count = 0
|
||||||
resp += "<div class='devices'>\n"
|
resp += "<div class='devices'>\n"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ var config = require('web.config');
|
|||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
var dom = require('web.dom');
|
var dom = require('web.dom');
|
||||||
var session = require('web.session');
|
|
||||||
|
|
||||||
var QWeb = core.qweb;
|
var QWeb = core.qweb;
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
@@ -731,7 +730,7 @@ var Discuss = AbstractAction.extend({
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_renderButtons: function () {
|
_renderButtons: function () {
|
||||||
this.$buttons = $(QWeb.render('mail.discuss.ControlButtons', { debug: session.debug }));
|
this.$buttons = $(QWeb.render('mail.discuss.ControlButtons', { debug: config.isDebug() }));
|
||||||
this.$buttons.find('button').css({display:'inline-block'});
|
this.$buttons.find('button').css({display:'inline-block'});
|
||||||
this.$buttons
|
this.$buttons
|
||||||
.on('click', '.o_mail_discuss_button_invite', this._onInviteButtonClicked.bind(this))
|
.on('click', '.o_mail_discuss_button_invite', this._onInviteButtonClicked.bind(this))
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
odoo.define('mail.DebugManager', function (require) {
|
odoo.define('mail.DebugManager.Backend', function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var DebugManager = require('web.DebugManager');
|
var DebugManager = require('web.DebugManager.Backend');
|
||||||
|
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ odoo.define('mail.ActivityRenderer', function (require) {
|
|||||||
|
|
||||||
var AbstractRenderer = require('web.AbstractRenderer');
|
var AbstractRenderer = require('web.AbstractRenderer');
|
||||||
var ActivityRecord = require('mail.ActivityRecord');
|
var ActivityRecord = require('mail.ActivityRecord');
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var field_registry = require('web.field_registry');
|
var field_registry = require('web.field_registry');
|
||||||
var KanbanColumnProgressBar = require('web.KanbanColumnProgressBar');
|
var KanbanColumnProgressBar = require('web.KanbanColumnProgressBar');
|
||||||
@@ -32,7 +33,7 @@ var ActivityRenderer = AbstractRenderer.extend({
|
|||||||
init: function (parent, state, params) {
|
init: function (parent, state, params) {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
this.qweb = new qweb(session.debug, {_s: session.origin});
|
this.qweb = new qweb(config.isDebug(), {_s: session.origin});
|
||||||
this.qweb.add_template(utils.json_node_to_xml(params.templates));
|
this.qweb.add_template(utils.json_node_to_xml(params.templates));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@
|
|||||||
<!-- systray -->
|
<!-- systray -->
|
||||||
<script type="text/javascript" src="/mail/static/src/js/systray/systray_activity_menu.js"></script>
|
<script type="text/javascript" src="/mail/static/src/js/systray/systray_activity_menu.js"></script>
|
||||||
<script type="text/javascript" src="/mail/static/src/js/systray/systray_messaging_menu.js"></script>
|
<script type="text/javascript" src="/mail/static/src/js/systray/systray_messaging_menu.js"></script>
|
||||||
<script type="text/javascript" src="/mail/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/mail/static/src/js/tours/mail.js"></script>
|
||||||
<script type="text/javascript" src="/mail/static/src/js/user_menu.js"></script>
|
<script type="text/javascript" src="/mail/static/src/js/user_menu.js"></script>
|
||||||
<!-- tools -->
|
<!-- tools -->
|
||||||
<script type="text/javascript" src="/mail/static/src/js/tools/debug_manager.js"></script>
|
<script type="text/javascript" src="/mail/static/src/js/tools/debug_manager.js"></script>
|
||||||
|
|||||||
@@ -136,6 +136,7 @@
|
|||||||
<a target="_blank" class="label label-danger" href="https://www.odoo.com/page/website-builder">Odoo</a>
|
<a target="_blank" class="label label-danger" href="https://www.odoo.com/page/website-builder">Odoo</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-left text-muted" itemscope="itemscope" itemtype="https://schema.org/Organization">
|
<div class="pull-left text-muted" itemscope="itemscope" itemtype="https://schema.org/Organization">
|
||||||
|
<t t-call="web.debug_icon"/>
|
||||||
Copyright &copy; <span t-field="res_company.name" itemprop="name">Company name</span>
|
Copyright &copy; <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ _logger = logging.getLogger(__name__)
|
|||||||
class PosController(http.Controller):
|
class PosController(http.Controller):
|
||||||
|
|
||||||
@http.route('/pos/web', type='http', auth='user')
|
@http.route('/pos/web', type='http', auth='user')
|
||||||
def pos_web(self, debug=False, **k):
|
def pos_web(self, **k):
|
||||||
# if user not logged in, log him in
|
# if user not logged in, log him in
|
||||||
pos_sessions = request.env['pos.session'].search([
|
pos_sessions = request.env['pos.session'].search([
|
||||||
('state', '=', 'opened'),
|
('state', '=', 'opened'),
|
||||||
|
|||||||
@@ -293,8 +293,7 @@ var Gui = core.Class.extend({
|
|||||||
this.chrome.loading_message(_t('Closing ...'));
|
this.chrome.loading_message(_t('Closing ...'));
|
||||||
|
|
||||||
this.pos.push_order().then(function(){
|
this.pos.push_order().then(function(){
|
||||||
var url = "/web#action=point_of_sale.action_client_pos_menu";
|
window.location = "/web#action=point_of_sale.action_client_pos_menu";
|
||||||
window.location = session.debug ? $.param.querystring(url, {debug: session.debug}) : url;
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ exports.PosModel = Backbone.Model.extend({
|
|||||||
|
|
||||||
this.proxy_queue = new devices.JobQueue(); // used to prevent parallels communications to the proxy
|
this.proxy_queue = new devices.JobQueue(); // used to prevent parallels communications to the proxy
|
||||||
this.db = new PosDB(); // a local database used to search trough products and categories & store pending orders
|
this.db = new PosDB(); // a local database used to search trough products and categories & store pending orders
|
||||||
this.debug = config.debug; //debug mode
|
this.debug = config.isDebug(); //debug mode
|
||||||
|
|
||||||
// Business data; loaded from the server at launch
|
// Business data; loaded from the server at launch
|
||||||
this.company_logo = null;
|
this.company_logo = null;
|
||||||
@@ -2251,7 +2251,7 @@ exports.Order = Backbone.Model.extend({
|
|||||||
} else {
|
} else {
|
||||||
subreceipt = subreceipt.split('\n').slice(1).join('\n');
|
subreceipt = subreceipt.split('\n').slice(1).join('\n');
|
||||||
var qweb = new QWeb2.Engine();
|
var qweb = new QWeb2.Engine();
|
||||||
qweb.debug = config.debug;
|
qweb.debug = config.isDebug();
|
||||||
qweb.default_dict = _.clone(QWeb.default_dict);
|
qweb.default_dict = _.clone(QWeb.default_dict);
|
||||||
qweb.add_template('<templates><t t-name="subreceipt">'+subreceipt+'</t></templates>');
|
qweb.add_template('<templates><t t-name="subreceipt">'+subreceipt+'</t></templates>');
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<script type="text/javascript" src="/point_of_sale/static/src/js/gui.js"></script>
|
<script type="text/javascript" src="/point_of_sale/static/src/js/gui.js"></script>
|
||||||
<script type="text/javascript" src="/point_of_sale/static/src/js/popups.js"></script>
|
<script type="text/javascript" src="/point_of_sale/static/src/js/popups.js"></script>
|
||||||
<script type="text/javascript" src="/point_of_sale/static/src/js/screens.js"></script>
|
<script type="text/javascript" src="/point_of_sale/static/src/js/screens.js"></script>
|
||||||
<script type="text/javascript" src="/point_of_sale/static/src/js/tests.js"></script>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template id="wysiwyg_iframe_css_assets" name="CSS assets for wysiwyg iframe content">
|
<template id="wysiwyg_iframe_css_assets" name="CSS assets for wysiwyg iframe content">
|
||||||
|
|||||||
@@ -3,7 +3,13 @@
|
|||||||
<template id="assets_backend" name="hr assets" inherit_id="web.assets_backend">
|
<template id="assets_backend" name="hr assets" inherit_id="web.assets_backend">
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<link rel="stylesheet" type="text/scss" href="/point_of_sale/static/src/scss/pos_dashboard.scss"/>
|
<link rel="stylesheet" type="text/scss" href="/point_of_sale/static/src/scss/pos_dashboard.scss"/>
|
||||||
<script type="text/javascript" src="/point_of_sale/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/point_of_sale/static/src/js/tours/point_of_sale.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Point Of Sale Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/point_of_sale/static/tests/tours/point_of_sale.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -31,12 +31,14 @@
|
|||||||
var odoo = {
|
var odoo = {
|
||||||
csrf_token: "<t t-esc="request.csrf_token(None)"/>",
|
csrf_token: "<t t-esc="request.csrf_token(None)"/>",
|
||||||
session_info: <t t-raw="session_info"/>,
|
session_info: <t t-raw="session_info"/>,
|
||||||
|
debug: "<t t-esc="debug"/>",
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||||
<t t-call-assets="point_of_sale.pos_assets_backend" t-css="false"/>
|
<t t-call-assets="point_of_sale.pos_assets_backend" t-css="false"/>
|
||||||
<t t-call-assets="point_of_sale.assets"/>
|
<t t-call-assets="point_of_sale.assets"/>
|
||||||
|
<t t-call="web.conditional_assets_tests"/>
|
||||||
|
|
||||||
<script type="text/javascript" id="loading-script" t-raw="init">
|
<script type="text/javascript" id="loading-script" t-raw="init">
|
||||||
odoo.define('web.web_client', function (require) {
|
odoo.define('web.web_client', function (require) {
|
||||||
|
|||||||
@@ -18,10 +18,15 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//script[last()]" position="after">
|
<xpath expr="//script[last()]" position="after">
|
||||||
<script type="text/javascript" src="/portal/static/src/js/portal.js"></script>
|
<script type="text/javascript" src="/portal/static/src/js/portal.js"></script>
|
||||||
<script type="text/javascript" src="/portal/static/src/js/portal_tour.js"></script>
|
|
||||||
<script type="text/javascript" src="/portal/static/src/js/portal_chatter.js"></script>
|
<script type="text/javascript" src="/portal/static/src/js/portal_chatter.js"></script>
|
||||||
<script type="text/javascript" src="/portal/static/src/js/portal_signature.js"></script>
|
<script type="text/javascript" src="/portal/static/src/js/portal_signature.js"></script>
|
||||||
<script type="text/javascript" src="/portal/static/src/js/portal_sidebar.js"></script>
|
<script type="text/javascript" src="/portal/static/src/js/portal_sidebar.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Portal Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/portal/static/tests/tours/portal.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<link rel="stylesheet" href="/project/static/src/css/project.css"/>
|
<link rel="stylesheet" href="/project/static/src/css/project.css"/>
|
||||||
<script type="text/javascript" src="/project/static/src/js/project.js"></script>
|
<script type="text/javascript" src="/project/static/src/js/project.js"></script>
|
||||||
<script type="text/javascript" src="/project/static/src/js/project_task_kanban_examples.js"></script>
|
<script type="text/javascript" src="/project/static/src/js/project_task_kanban_examples.js"></script>
|
||||||
<script type="text/javascript" src="/project/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/project/static/src/js/tours/project.js"></script>
|
||||||
<link rel="stylesheet" type="text/scss" href="/project/static/src/scss/project_dashboard.scss"/>
|
<link rel="stylesheet" type="text/scss" href="/project/static/src/scss/project_dashboard.scss"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
<a t-attf-href="/my/project/#{project.id}?{{ keep_query() }}"><span t-field="project.name"/></a>
|
<a t-attf-href="/my/project/#{project.id}?{{ keep_query() }}"><span t-field="project.name"/></a>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<a t-attf-href="/my/tasks?{{keep_query('debug', filterby=project.id)}}">
|
<a t-attf-href="/my/tasks?{{keep_query(filterby=project.id)}}">
|
||||||
<t t-esc="project.task_count" />
|
<t t-esc="project.task_count" />
|
||||||
<t t-esc="project.label_tasks" />
|
<t t-esc="project.label_tasks" />
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="script[last()]" position="after">
|
<xpath expr="script[last()]" position="after">
|
||||||
<script type="text/javascript" src="/sale/static/src/js/sale.js"></script>
|
<script type="text/javascript" src="/sale/static/src/js/sale.js"></script>
|
||||||
<script type="text/javascript" src="/sale/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/sale/static/src/js/tours/sale.js"></script>
|
||||||
<script type="text/javascript" src="/sale/static/src/js/account_reconciliation.js"></script>
|
<script type="text/javascript" src="/sale/static/src/js/account_reconciliation.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
@@ -17,7 +17,11 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="script[last()]" position="after">
|
<xpath expr="script[last()]" position="after">
|
||||||
<script type="text/javascript" src="/sale/static/src/js/sale_portal_sidebar.js"></script>
|
<script type="text/javascript" src="/sale/static/src/js/sale_portal_sidebar.js"></script>
|
||||||
<script type="text/javascript" src="/sale/static/src/js/sale_tour_sale_signature.js"></script>
|
</xpath>
|
||||||
|
</template>
|
||||||
|
<template id="assets_tests" name="Sale Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/sale/static/tests/tours/sale_signature.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
<template id="qunit_suite" name="sale_tests" inherit_id="web.qunit_suite">
|
<template id="qunit_suite" name="sale_tests" inherit_id="web.qunit_suite">
|
||||||
|
|||||||
@@ -5,19 +5,23 @@
|
|||||||
<link rel="stylesheet" type="text/scss" href="/sale_product_configurator/static/src/scss/product_configurator_widget.scss"/>
|
<link rel="stylesheet" type="text/scss" href="/sale_product_configurator/static/src/scss/product_configurator_widget.scss"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="script[last()]" position="after">
|
<xpath expr="script[last()]" position="after">
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/tour.js"></script>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/tours/sale_product_configurator.js"></script>
|
||||||
<script type="text/javascript" src="/sale/static/src/js/variant_mixin.js"></script>
|
<script type="text/javascript" src="/sale/static/src/js/variant_mixin.js"></script>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_renderer.js"></script>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_renderer.js"></script>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_controller.js"></script>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_controller.js"></script>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_view.js"></script>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_view.js"></script>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_widget.js"/>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_widget.js"/>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_modal.js"></script>
|
<script type="text/javascript" src="/sale_product_configurator/static/src/js/product_configurator_modal.js"></script>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_test_ui.js"/>
|
</xpath>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_advanced_test_ui.js"/>
|
</template>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_edition_test_ui.js"/>
|
<template id="assets_tests" name="Sale Product Configurator Assets Tests" inherit_id="web.assets_tests">
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_single_custom_attribute_test_ui.js"/>
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_pricelist_test_ui.js"/>
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_ui.js"/>
|
||||||
<script type="text/javascript" src="/sale_product_configurator/static/tests/product_configurator_optional_products_test_ui.js"/>
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_advanced_ui.js"/>
|
||||||
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_edition_ui.js"/>
|
||||||
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_single_custom_attribute_ui.js"/>
|
||||||
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_pricelist_ui.js"/>
|
||||||
|
<script type="text/javascript" src="/sale_product_configurator/static/tests/tours/product_configurator_optional_products_ui.js"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
<template id="qunit_suite" inherit_id="web.qunit_suite" name="sale_product_configurator_tests">
|
<template id="qunit_suite" inherit_id="web.qunit_suite" name="sale_product_configurator_tests">
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import json
|
|||||||
class BarcodeController(http.Controller):
|
class BarcodeController(http.Controller):
|
||||||
|
|
||||||
@http.route(['/stock/barcode/'], type='http', auth='user')
|
@http.route(['/stock/barcode/'], type='http', auth='user')
|
||||||
def a(self, debug=False, **k):
|
def a(self, **k):
|
||||||
if not request.session.uid:
|
if not request.session.uid:
|
||||||
return http.local_redirect('/web/login?redirect=/stock/barcode/')
|
return http.local_redirect('/web/login?redirect=/stock/barcode/')
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ var tour = require('web_tour.tour');
|
|||||||
|
|
||||||
tour.register('stock', {
|
tour.register('stock', {
|
||||||
test: true,
|
test: true,
|
||||||
url: '/web?debug=assets#action=stock.action_stock_config_settings',
|
url: '/web#action=stock.action_stock_config_settings',
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
<template id="stock_assets_backend" name="mrp_workorder assets" inherit_id="web.assets_backend">
|
<template id="stock_assets_backend" name="mrp_workorder assets" inherit_id="web.assets_backend">
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/stock/static/tests/route_tour.js"></script>
|
|
||||||
<script type="text/javascript" src="/stock/static/src/js/inventory_singleton_list_controller.js"></script>
|
<script type="text/javascript" src="/stock/static/src/js/inventory_singleton_list_controller.js"></script>
|
||||||
<script type="text/javascript" src="/stock/static/src/js/inventory_singleton_list_view.js"></script>
|
<script type="text/javascript" src="/stock/static/src/js/inventory_singleton_list_view.js"></script>
|
||||||
<script type="text/javascript" src="/stock/static/src/js/inventory_validate_button_controller.js"></script>
|
<script type="text/javascript" src="/stock/static/src/js/inventory_validate_button_controller.js"></script>
|
||||||
@@ -20,6 +19,12 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Stock Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/stock/static/tests/tours/route.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template id="message_head">
|
<template id="message_head">
|
||||||
<t t-if="move.state != 'done'">
|
<t t-if="move.state != 'done'">
|
||||||
<strong>The initial demand has been updated.</strong>
|
<strong>The initial demand has been updated.</strong>
|
||||||
|
|||||||
@@ -10,10 +10,6 @@
|
|||||||
<script type="text/javascript" src="/survey/static/src/js/survey_result.js" />
|
<script type="text/javascript" src="/survey/static/src/js/survey_result.js" />
|
||||||
<script type="text/javascript" src="/survey/static/src/js/survey.js" />
|
<script type="text/javascript" src="/survey/static/src/js/survey.js" />
|
||||||
<script type="text/javascript" src="/survey/static/src/js/survey_timer.js" />
|
<script type="text/javascript" src="/survey/static/src/js/survey_timer.js" />
|
||||||
<script type="text/javascript" src="/survey/static/src/js/tour_test_survey.js"></script>
|
|
||||||
<script type="text/javascript" src="/survey/static/src/js/tour_test_certification_success.js"></script>
|
|
||||||
<script type="text/javascript" src="/survey/static/src/js/tour_test_certification_failure.js"></script>
|
|
||||||
<script type="text/javascript" src="/survey/static/src/js/tour_test_survey_prefill.js"></script>
|
|
||||||
|
|
||||||
<link href="/survey/static/src/css/survey_print.css" rel="stylesheet" type="text/css"/>
|
<link href="/survey/static/src/css/survey_print.css" rel="stylesheet" type="text/css"/>
|
||||||
<link href="/survey/static/src/css/survey_result.css" rel="stylesheet" type="text/css"></link>
|
<link href="/survey/static/src/css/survey_result.css" rel="stylesheet" type="text/css"></link>
|
||||||
@@ -36,5 +32,14 @@
|
|||||||
<link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_views.scss"/>
|
<link rel="stylesheet" type="text/scss" href="/survey/static/src/scss/survey_views.scss"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="assets_tests" name="Survey Assets Tests" inherit_id="web.assets_tests">
|
||||||
|
<xpath expr="." position="inside">
|
||||||
|
<script type="text/javascript" src="/survey/static/tests/tours/certification_failure.js"></script>
|
||||||
|
<script type="text/javascript" src="/survey/static/tests/tours/certification_success.js"></script>
|
||||||
|
<script type="text/javascript" src="/survey/static/tests/tours/survey.js"></script>
|
||||||
|
<script type="text/javascript" src="/survey/static/tests/tours/survey_prefill.js"></script>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_frontend" inherit_id="website.assets_frontend">
|
<template id="assets_tests" name="Test Website Assets Tests" inherit_id="web.assets_tests">
|
||||||
<xpath expr="script[last()]" position="after">
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/test_website/static/src/js/reset_views.test.js"></script>
|
<script type="text/javascript" src="/test_website/static/tests/tours/reset_views.js"></script>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ class Home(http.Controller):
|
|||||||
:param unique: this parameters is not used, but mandatory: it is used by the HTTP stack to make a unique request
|
:param unique: this parameters is not used, but mandatory: it is used by the HTTP stack to make a unique request
|
||||||
:return: the menus (including the images in Base64)
|
:return: the menus (including the images in Base64)
|
||||||
"""
|
"""
|
||||||
menus = request.env["ir.ui.menu"].load_menus(request.debug)
|
menus = request.env["ir.ui.menu"].load_menus(request.session.debug)
|
||||||
body = json.dumps(menus, default=ustr)
|
body = json.dumps(menus, default=ustr)
|
||||||
response = request.make_response(body, [
|
response = request.make_response(body, [
|
||||||
# this method must specify a content-type application/json instead of using the default text/html set because
|
# this method must specify a content-type application/json instead of using the default text/html set because
|
||||||
@@ -542,12 +542,6 @@ class Home(http.Controller):
|
|||||||
if not odoo.tools.config['list_db']:
|
if not odoo.tools.config['list_db']:
|
||||||
values['disable_database_manager'] = True
|
values['disable_database_manager'] = True
|
||||||
|
|
||||||
# otherwise no real way to test debug mode in template as ?debug =>
|
|
||||||
# values['debug'] = '' but that's also the fallback value when
|
|
||||||
# missing variables in qweb
|
|
||||||
if 'debug' in values:
|
|
||||||
values['debug'] = True
|
|
||||||
|
|
||||||
response = request.render('web.login', values)
|
response = request.render('web.login', values)
|
||||||
response.headers['X-Frame-Options'] = 'DENY'
|
response.headers['X-Frame-Options'] = 'DENY'
|
||||||
return response
|
return response
|
||||||
@@ -1590,8 +1584,7 @@ class Apps(http.Controller):
|
|||||||
action['views'] = [(False, u'form')]
|
action['views'] = [(False, u'form')]
|
||||||
|
|
||||||
sakey = Session().save_session_action(action)
|
sakey = Session().save_session_action(action)
|
||||||
debug = '?debug' if req.debug else ''
|
return werkzeug.utils.redirect('/web#sa={0}'.format(sakey))
|
||||||
return werkzeug.utils.redirect('/web{0}#sa={1}'.format(debug, sakey))
|
|
||||||
|
|
||||||
|
|
||||||
class ReportController(http.Controller):
|
class ReportController(http.Controller):
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Http(models.AbstractModel):
|
|||||||
|
|
||||||
def webclient_rendering_context(self):
|
def webclient_rendering_context(self):
|
||||||
return {
|
return {
|
||||||
'menu_data': request.env['ir.ui.menu'].load_menus(request.debug),
|
'menu_data': request.env['ir.ui.menu'].load_menus(request.session.debug),
|
||||||
'session_info': json.dumps(self.session_info()),
|
'session_info': json.dumps(self.session_info()),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ class Http(models.AbstractModel):
|
|||||||
lang = user_context.get("lang")
|
lang = user_context.get("lang")
|
||||||
translations_per_module, _ = request.env['ir.translation'].get_translations_for_webclient(mods, lang)
|
translations_per_module, _ = request.env['ir.translation'].get_translations_for_webclient(mods, lang)
|
||||||
|
|
||||||
menu_json_utf8 = json.dumps(request.env['ir.ui.menu'].load_menus(request.debug), default=ustr, sort_keys=True).encode()
|
menu_json_utf8 = json.dumps(request.env['ir.ui.menu'].load_menus(request.session.debug), default=ustr, sort_keys=True).encode()
|
||||||
translations_json_utf8 = json.dumps(translations_per_module, sort_keys=True).encode()
|
translations_json_utf8 = json.dumps(translations_per_module, sort_keys=True).encode()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ odoo.define('web.Apps', function (require) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AbstractAction = require('web.AbstractAction');
|
var AbstractAction = require('web.AbstractAction');
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var framework = require('web.framework');
|
var framework = require('web.framework');
|
||||||
var session = require('web.session');
|
var session = require('web.session');
|
||||||
@@ -111,8 +112,8 @@ var Apps = AbstractAction.extend({
|
|||||||
self.client = client;
|
self.client = client;
|
||||||
|
|
||||||
var qs = {db: client.dbname};
|
var qs = {db: client.dbname};
|
||||||
if (session.debug) {
|
if (config.isDebug()) {
|
||||||
qs.debug = session.debug;
|
qs.debug = odoo.debug;
|
||||||
}
|
}
|
||||||
var u = $.param.querystring(client.origin + "/apps/embed/client", qs);
|
var u = $.param.querystring(client.origin + "/apps/embed/client", qs);
|
||||||
var css = {width: '100%', height: '750px'};
|
var css = {width: '100%', height: '750px'};
|
||||||
|
|||||||
@@ -38,8 +38,6 @@
|
|||||||
var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;
|
var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;
|
||||||
var cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g;
|
var cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g;
|
||||||
|
|
||||||
var debug = /\bdebug\b/.test(window.location.search);
|
|
||||||
|
|
||||||
if (!window.odoo) {
|
if (!window.odoo) {
|
||||||
window.odoo = {};
|
window.odoo = {};
|
||||||
}
|
}
|
||||||
@@ -51,7 +49,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
odoo.testing = typeof QUnit === 'object';
|
odoo.testing = typeof QUnit === 'object';
|
||||||
odoo.debug = debug;
|
|
||||||
odoo.remainingJobs = jobs;
|
odoo.remainingJobs = jobs;
|
||||||
odoo.__DEBUG__ = {
|
odoo.__DEBUG__ = {
|
||||||
didLogInfo: didLogInfoPromise,
|
didLogInfo: didLogInfoPromise,
|
||||||
|
|||||||
@@ -527,9 +527,6 @@ var ActionManager = Widget.extend({
|
|||||||
*/
|
*/
|
||||||
_executeURLAction: function (action, options) {
|
_executeURLAction: function (action, options) {
|
||||||
var url = action.url;
|
var url = action.url;
|
||||||
if (config.debug && url && url.length && url[0] === '/') {
|
|
||||||
url = $.param.querystring(url, {debug: config.debug});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.target === 'self') {
|
if (action.target === 'self') {
|
||||||
framework.redirect(url);
|
framework.redirect(url);
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ ActionManager.include({
|
|||||||
viewID: view[0],
|
viewID: view[0],
|
||||||
Widget: View,
|
Widget: View,
|
||||||
});
|
});
|
||||||
} else if (config.debug === 'assets') {
|
} else if (config.isDebug('assets')) {
|
||||||
console.error("View type '" + viewType + "' is not present in the view registry.");
|
console.error("View type '" + viewType + "' is not present in the view registry.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ odoo.define('web.Loading', function (require) {
|
|||||||
* After a delay of 3s, if a rpc is still not completed, we also block the UI.
|
* After a delay of 3s, if a rpc is still not completed, we also block the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var framework = require('web.framework');
|
var framework = require('web.framework');
|
||||||
var session = require('web.session');
|
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
|
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
@@ -54,7 +54,7 @@ var Loading = Widget.extend({
|
|||||||
|
|
||||||
this.count += increment;
|
this.count += increment;
|
||||||
if (this.count > 0) {
|
if (this.count > 0) {
|
||||||
if (session.debug) {
|
if (config.isDebug()) {
|
||||||
this.$el.text(_.str.sprintf( _t("Loading (%d)"), this.count));
|
this.$el.text(_.str.sprintf( _t("Loading (%d)"), this.count));
|
||||||
} else {
|
} else {
|
||||||
this.$el.text(_t("Loading"));
|
this.$el.text(_t("Loading"));
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ odoo.define('web.UserMenu', function (require) {
|
|||||||
* editing its preferences, accessing the documentation, logging out...
|
* editing its preferences, accessing the documentation, logging out...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var framework = require('web.framework');
|
var framework = require('web.framework');
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
@@ -39,7 +40,7 @@ var UserMenu = Widget.extend({
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
var topbar_name = session.name;
|
var topbar_name = session.name;
|
||||||
if (session.debug) {
|
if (config.isDebug()) {
|
||||||
topbar_name = _.str.sprintf("%s (%s)", topbar_name, session.db);
|
topbar_name = _.str.sprintf("%s (%s)", topbar_name, session.db);
|
||||||
}
|
}
|
||||||
self.$('.oe_topbar_name').text(topbar_name);
|
self.$('.oe_topbar_name').text(topbar_name);
|
||||||
|
|||||||
@@ -435,7 +435,7 @@ var loadAsset = (function () {
|
|||||||
}
|
}
|
||||||
var params = {
|
var params = {
|
||||||
args: [xmlId, {
|
args: [xmlId, {
|
||||||
debug: config.debug
|
debug: config.isDebug()
|
||||||
}],
|
}],
|
||||||
kwargs: {
|
kwargs: {
|
||||||
context: odoo.session_info.user_context,
|
context: odoo.session_info.user_context,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ odoo.define('web.Session', function (require) {
|
|||||||
|
|
||||||
var ajax = require('web.ajax');
|
var ajax = require('web.ajax');
|
||||||
var concurrency = require('web.concurrency');
|
var concurrency = require('web.concurrency');
|
||||||
var config = require('web.config');
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var local_storage = require('web.local_storage');
|
var local_storage = require('web.local_storage');
|
||||||
var mixins = require('web.mixins');
|
var mixins = require('web.mixins');
|
||||||
@@ -35,7 +34,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
|||||||
this.avoid_recursion = false;
|
this.avoid_recursion = false;
|
||||||
this.use_cors = options.use_cors || false;
|
this.use_cors = options.use_cors || false;
|
||||||
this.setup(origin);
|
this.setup(origin);
|
||||||
this.debug = config.debug;
|
|
||||||
|
|
||||||
// for historic reasons, the session requires a name to properly work
|
// for historic reasons, the session requires a name to properly work
|
||||||
// (see the methods get_cookie and set_cookie). We should perhaps
|
// (see the methods get_cookie and set_cookie). We should perhaps
|
||||||
@@ -305,9 +303,6 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
|
|||||||
var self = this;
|
var self = this;
|
||||||
options = _.clone(options || {});
|
options = _.clone(options || {});
|
||||||
options.headers = _.extend({}, options.headers);
|
options.headers = _.extend({}, options.headers);
|
||||||
if (odoo.debug) {
|
|
||||||
options.headers["X-Debug-Mode"] = $.deparam($.param.querystring()).debug;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we add here the user context for ALL queries, mainly to pass
|
// we add here the user context for ALL queries, mainly to pass
|
||||||
// the allowed_company_ids key
|
// the allowed_company_ids key
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ odoo.define('web.basic_fields', function (require) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var AbstractField = require('web.AbstractField');
|
var AbstractField = require('web.AbstractField');
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var crash_manager = require('web.crash_manager');
|
var crash_manager = require('web.crash_manager');
|
||||||
var datepicker = require('web.datepicker');
|
var datepicker = require('web.datepicker');
|
||||||
@@ -2770,7 +2771,7 @@ var FieldDomain = AbstractField.extend({
|
|||||||
this.domainSelector = new DomainSelector(this, this._domainModel, value, {
|
this.domainSelector = new DomainSelector(this, this._domainModel, value, {
|
||||||
readonly: this.mode === "readonly" || this.inDialog,
|
readonly: this.mode === "readonly" || this.inDialog,
|
||||||
filters: this.fsFilters,
|
filters: this.fsFilters,
|
||||||
debugMode: session.debug,
|
debugMode: config.isDebug(),
|
||||||
});
|
});
|
||||||
def = this.domainSelector.prependTo(this.$el);
|
def = this.domainSelector.prependTo(this.$el);
|
||||||
} else {
|
} else {
|
||||||
@@ -2859,7 +2860,7 @@ var FieldDomain = AbstractField.extend({
|
|||||||
new DomainSelectorDialog(this, this._domainModel, this.value || "[]", {
|
new DomainSelectorDialog(this, this._domainModel, this.value || "[]", {
|
||||||
readonly: this.mode === "readonly",
|
readonly: this.mode === "readonly",
|
||||||
filters: this.fsFilters,
|
filters: this.fsFilters,
|
||||||
debugMode: session.debug,
|
debugMode: config.isDebug(),
|
||||||
}).open();
|
}).open();
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,19 +10,7 @@ odoo.define('web.config', function () {
|
|||||||
* this file someday.
|
* this file someday.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var debugParam = $.deparam($.param.querystring()).debug;
|
|
||||||
var debug = false;
|
|
||||||
if (debugParam !== undefined) {
|
|
||||||
debug = debugParam === 'assets' ? 'assets' : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
/**
|
|
||||||
* debug can be either a boolean, or the special value 'assets'
|
|
||||||
*
|
|
||||||
* @type boolean|string
|
|
||||||
*/
|
|
||||||
debug: debug,
|
|
||||||
device: {
|
device: {
|
||||||
/**
|
/**
|
||||||
* touch is a boolean, true if the device supports touch interaction
|
* touch is a boolean, true if the device supports touch interaction
|
||||||
@@ -51,6 +39,18 @@ var config = {
|
|||||||
*/
|
*/
|
||||||
SIZES: { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 },
|
SIZES: { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 },
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* States whether the current environment is in debug or not.
|
||||||
|
*
|
||||||
|
* @param debugMode the debug mode to check, empty for simple debug mode
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isDebug: function (debugMode) {
|
||||||
|
if (debugMode) {
|
||||||
|
return odoo.debug && odoo.debug.indexOf(debugMode) !== -1;
|
||||||
|
}
|
||||||
|
return odoo.debug;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ odoo.define('web.core', function (require) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Bus = require('web.Bus');
|
var Bus = require('web.Bus');
|
||||||
var Class = require('web.Class');
|
|
||||||
var config = require('web.config');
|
var config = require('web.config');
|
||||||
|
var Class = require('web.Class');
|
||||||
var QWeb = require('web.QWeb');
|
var QWeb = require('web.QWeb');
|
||||||
var Registry = require('web.Registry');
|
var Registry = require('web.Registry');
|
||||||
var translation = require('web.translation');
|
var translation = require('web.translation');
|
||||||
@@ -27,7 +27,7 @@ _.each('resize,scroll'.split(','), function (evtype) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
qweb: new QWeb(config.debug),
|
qweb: new QWeb(config.isDebug()),
|
||||||
|
|
||||||
// core classes and functions
|
// core classes and functions
|
||||||
Class: Class,
|
Class: Class,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ return core.Class.extend({
|
|||||||
var self = this;
|
var self = this;
|
||||||
var key = this._gen_key(action_id, additional_context || {});
|
var key = this._gen_key(action_id, additional_context || {});
|
||||||
|
|
||||||
if (config.debug === 'assets' || !this._cache.actions[key]) {
|
if (config.isDebug('assets') || !this._cache.actions[key]) {
|
||||||
this._cache.actions[key] = rpc.query({
|
this._cache.actions[key] = rpc.query({
|
||||||
route: "/web/action/load",
|
route: "/web/action/load",
|
||||||
params: {
|
params: {
|
||||||
@@ -82,7 +82,7 @@ return core.Class.extend({
|
|||||||
var views_descr = params.views_descr;
|
var views_descr = params.views_descr;
|
||||||
var key = this._gen_key(model, views_descr, options || {}, context);
|
var key = this._gen_key(model, views_descr, options || {}, context);
|
||||||
|
|
||||||
if (config.debug === 'assets' || !this._cache.views[key]) {
|
if (config.isDebug('assets') || !this._cache.views[key]) {
|
||||||
// Don't load filters if already in cache
|
// Don't load filters if already in cache
|
||||||
var filters_key;
|
var filters_key;
|
||||||
if (options.load_filters) {
|
if (options.load_filters) {
|
||||||
@@ -137,7 +137,7 @@ return core.Class.extend({
|
|||||||
*/
|
*/
|
||||||
load_filters: function (params) {
|
load_filters: function (params) {
|
||||||
var key = this._gen_key(params.modelName, params.actionId);
|
var key = this._gen_key(params.modelName, params.actionId);
|
||||||
if (config.debug === 'assets' || !this._cache.filters[key]) {
|
if (config.isDebug('assets') || !this._cache.filters[key]) {
|
||||||
this._cache.filters[key] = rpc.query({
|
this._cache.filters[key] = rpc.query({
|
||||||
args: [params.modelName, params.actionId],
|
args: [params.modelName, params.actionId],
|
||||||
kwargs: {
|
kwargs: {
|
||||||
|
|||||||
@@ -1,91 +1,43 @@
|
|||||||
odoo.define('web.DebugManager', function (require) {
|
odoo.define('web.DebugManager', function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var ActionManager = require('web.ActionManager');
|
|
||||||
var dialogs = require('web.view_dialogs');
|
|
||||||
var startClickEverywhere = require('web.clickEverywhere');
|
|
||||||
var config = require('web.config');
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var Dialog = require('web.Dialog');
|
|
||||||
var field_utils = require('web.field_utils');
|
|
||||||
var session = require('web.session');
|
var session = require('web.session');
|
||||||
var SystrayMenu = require('web.SystrayMenu');
|
|
||||||
var utils = require('web.utils');
|
|
||||||
var WebClient = require('web.WebClient');
|
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
|
|
||||||
var QWeb = core.qweb;
|
var QWeb = core.qweb;
|
||||||
var _t = core._t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DebugManager base + general features (applicable to any context)
|
* DebugManager base + general features (applicable to any context)
|
||||||
*/
|
*/
|
||||||
var DebugManager = Widget.extend({
|
var DebugManager = Widget.extend({
|
||||||
template: "WebClient.DebugManager",
|
template: "WebClient.DebugManager",
|
||||||
|
xmlDependencies: ['/web/static/src/xml/debug.xml'],
|
||||||
events: {
|
events: {
|
||||||
"click a[data-action]": "perform_callback",
|
"click a[data-action]": "perform_callback",
|
||||||
"mouseover .o_debug_dropdowns > li:not(.show)": function(e) {
|
|
||||||
// Open other dropdowns on mouseover
|
|
||||||
var $opened = this.$('.o_debug_dropdowns > li.show');
|
|
||||||
if($opened.length) {
|
|
||||||
$opened.removeClass('show');
|
|
||||||
$(e.currentTarget).addClass('show').find('> a').focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
init: function () {
|
init: function () {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
// 15 fps, only actually call after sequences of queries
|
|
||||||
this._update_stats = _.throttle(
|
|
||||||
this._update_stats.bind(this),
|
|
||||||
1000/15, {leading: false});
|
|
||||||
this._events = null;
|
this._events = null;
|
||||||
if (document.querySelector('meta[name=debug]')) {
|
var debug = odoo.debug;
|
||||||
this._events = [];
|
this.debug_mode = debug;
|
||||||
}
|
this.debug_mode_help = debug && debug !== '1' ? ' (' + debug + ')' : '';
|
||||||
},
|
},
|
||||||
start: function () {
|
start: function () {
|
||||||
core.bus.on('rpc:result', this, function (req, resp) {
|
core.bus.on('rpc:result', this, function (req, resp) {
|
||||||
this._debug_events(resp.debug);
|
this._debug_events(resp.debug);
|
||||||
});
|
});
|
||||||
this.on('update-stats', this, this._update_stats);
|
|
||||||
var init;
|
|
||||||
if ((init = document.querySelector('meta[name=debug]'))) {
|
|
||||||
this._debug_events(JSON.parse(init.getAttribute('value')));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$dropdown = this.$(".o_debug_dropdown");
|
this.$dropdown = this.$(".o_debug_dropdown");
|
||||||
// falsy if can't write to user or couldn't find technical features
|
|
||||||
// group, otherwise features group id
|
|
||||||
this._features_group = null;
|
|
||||||
// whether group is currently enabled for current user
|
|
||||||
this._has_features = false;
|
|
||||||
// whether the current user is an administrator
|
// whether the current user is an administrator
|
||||||
this._is_admin = session.is_system;
|
this._is_admin = session.is_system;
|
||||||
return Promise.resolve(
|
return Promise.resolve(
|
||||||
this._rpc({
|
|
||||||
model: 'res.users',
|
|
||||||
method: 'check_access_rights',
|
|
||||||
kwargs: {operation: 'write', raise_exception: false},
|
|
||||||
}),
|
|
||||||
session.user_has_group('base.group_no_one'),
|
|
||||||
this._rpc({
|
|
||||||
model: 'ir.model.data',
|
|
||||||
method: 'xmlid_to_res_id',
|
|
||||||
kwargs: {xmlid: 'base.group_no_one'},
|
|
||||||
}),
|
|
||||||
this._super()
|
this._super()
|
||||||
).then(function (can_write_user, has_group_no_one, group_no_one_id) {
|
).then(function () {
|
||||||
this._features_group = can_write_user && group_no_one_id;
|
|
||||||
this._has_features = has_group_no_one;
|
|
||||||
return this.update();
|
return this.update();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
leave_debug_mode: function () {
|
/**
|
||||||
var qs = $.deparam.querystring();
|
|
||||||
delete qs.debug;
|
|
||||||
window.location.search = '?' + $.param(qs);
|
|
||||||
}, /**
|
|
||||||
* Calls the appropriate callback when clicking on a Debug option
|
* Calls the appropriate callback when clicking on a Debug option
|
||||||
*/
|
*/
|
||||||
perform_callback: function (evt) {
|
perform_callback: function (evt) {
|
||||||
@@ -102,54 +54,14 @@ var DebugManager = Widget.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_debug_events: function (events) {
|
_debug_events: function (events) {
|
||||||
if (!this._events) { return; }
|
if (!this._events) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (events && events.length) {
|
if (events && events.length) {
|
||||||
this._events.push(events);
|
this._events.push(events);
|
||||||
}
|
}
|
||||||
this.trigger('update-stats', this._events);
|
this.trigger('update-stats', this._events);
|
||||||
},
|
},
|
||||||
requests_clear: function () {
|
|
||||||
if (!this._events) { return; }
|
|
||||||
this._events = [];
|
|
||||||
this.trigger('update-stats', this._events);
|
|
||||||
},
|
|
||||||
_update_stats: function (rqs) {
|
|
||||||
var requests = 0, rtime = 0, queries = 0, qtime = 0;
|
|
||||||
for(var r = 0; r < rqs.length; ++r) {
|
|
||||||
for (var i = 0; i < rqs[r].length; i++) {
|
|
||||||
var event = rqs[r][i];
|
|
||||||
var query_start, request_start;
|
|
||||||
switch (event[0]) {
|
|
||||||
case 'request-start':
|
|
||||||
request_start = event[3] * 1e3;
|
|
||||||
break;
|
|
||||||
case 'request-end':
|
|
||||||
++requests;
|
|
||||||
rtime += (event[3] * 1e3 - request_start) | 0;
|
|
||||||
break;
|
|
||||||
case 'sql-start':
|
|
||||||
query_start = event[3] * 1e3;
|
|
||||||
break;
|
|
||||||
case 'sql-end':
|
|
||||||
++queries;
|
|
||||||
qtime += (event[3] * 1e3 - query_start) | 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$('#debugmanager_requests_stats').text(
|
|
||||||
_.str.sprintf(_t("%d requests (%d ms) %d queries (%d ms)"),
|
|
||||||
requests, rtime, queries, qtime));
|
|
||||||
},
|
|
||||||
show_timelines: function () {
|
|
||||||
if (this._overlay) {
|
|
||||||
this._overlay.destroy();
|
|
||||||
this._overlay = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._overlay = new RequestsOverlay(this);
|
|
||||||
this._overlay.appendTo(document.body);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the debug manager: reinserts all "universal" controls
|
* Update the debug manager: reinserts all "universal" controls
|
||||||
@@ -162,64 +74,13 @@ var DebugManager = Widget.extend({
|
|||||||
}));
|
}));
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
},
|
},
|
||||||
select_view: function () {
|
split_assets: function () {
|
||||||
var self = this;
|
|
||||||
new dialogs.SelectCreateDialog(this, {
|
|
||||||
res_model: 'ir.ui.view',
|
|
||||||
title: _t('Select a view'),
|
|
||||||
disable_multiple_selection: true,
|
|
||||||
domain: [['type', '!=', 'qweb'], ['type', '!=', 'search']],
|
|
||||||
on_selected: function (records) {
|
|
||||||
self._rpc({
|
|
||||||
model: 'ir.ui.view',
|
|
||||||
method: 'search_read',
|
|
||||||
domain: [['id', '=', records[0].id]],
|
|
||||||
fields: ['name', 'model', 'type'],
|
|
||||||
limit: 1,
|
|
||||||
})
|
|
||||||
.then(function (views) {
|
|
||||||
var view = views[0];
|
|
||||||
view.type = view.type === 'tree' ? 'list' : view.type; // ignore tree view
|
|
||||||
self.do_action({
|
|
||||||
type: 'ir.actions.act_window',
|
|
||||||
name: view.name,
|
|
||||||
res_model: view.model,
|
|
||||||
views: [[view.id, view.type]]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).open();
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Runs the JS (desktop) tests
|
|
||||||
*/
|
|
||||||
perform_js_tests: function () {
|
|
||||||
this.do_action({
|
|
||||||
name: _t("JS Tests"),
|
|
||||||
target: 'new',
|
|
||||||
type: 'ir.actions.act_url',
|
|
||||||
url: '/web/tests?mod=*'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Runs the JS mobile tests
|
|
||||||
*/
|
|
||||||
perform_js_mobile_tests: function () {
|
|
||||||
this.do_action({
|
|
||||||
name: _t("JS Mobile Tests"),
|
|
||||||
target: 'new',
|
|
||||||
type: 'ir.actions.act_url',
|
|
||||||
url: '/web/tests/mobile?mod=*'
|
|
||||||
});
|
|
||||||
},
|
|
||||||
perform_click_everywhere_test: function () {
|
|
||||||
var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th");
|
|
||||||
$homeMenu.click();
|
|
||||||
startClickEverywhere();
|
|
||||||
},
|
|
||||||
split_assets: function() {
|
|
||||||
window.location = $.param.querystring(window.location.href, 'debug=assets');
|
window.location = $.param.querystring(window.location.href, 'debug=assets');
|
||||||
},
|
},
|
||||||
|
tests_assets: function () {
|
||||||
|
// Enable also 'assets' to see non minimized assets
|
||||||
|
window.location = $.param.querystring(window.location.href, 'debug=assets,tests');
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Delete assets bundles to force their regeneration
|
* Delete assets bundles to force their regeneration
|
||||||
*
|
*
|
||||||
@@ -240,667 +101,15 @@ var DebugManager = Widget.extend({
|
|||||||
model: 'ir.attachment',
|
model: 'ir.attachment',
|
||||||
method: 'unlink',
|
method: 'unlink',
|
||||||
args: [ids],
|
args: [ids],
|
||||||
}).then(self.do_action('reload'));
|
}).then(window.location.reload());
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DebugManager features depending on having an action, and possibly a model
|
|
||||||
* (window action)
|
|
||||||
*/
|
|
||||||
DebugManager.include({
|
|
||||||
/**
|
|
||||||
* Updates current action (action descriptor) on tag = action,
|
|
||||||
*/
|
|
||||||
update: function (tag, descriptor) {
|
|
||||||
if (tag === 'action') {
|
|
||||||
this._action = descriptor;
|
|
||||||
}
|
|
||||||
return this._super().then(function () {
|
|
||||||
this.$dropdown.find(".o_debug_leave_section").before(QWeb.render('WebClient.DebugManager.Action', {
|
|
||||||
manager: this,
|
|
||||||
action: this._action
|
|
||||||
}));
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
edit: function (params, evt) {
|
|
||||||
this.do_action({
|
|
||||||
res_model: params.model,
|
|
||||||
res_id: params.id,
|
|
||||||
name: evt.target.text,
|
|
||||||
type: 'ir.actions.act_window',
|
|
||||||
views: [[false, 'form']],
|
|
||||||
view_mode: 'form',
|
|
||||||
target: 'new',
|
|
||||||
flags: {action_buttons: true, headless: true}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get_view_fields: function () {
|
leave_debug_mode: function () {
|
||||||
var model = this._action.res_model,
|
var qs = $.deparam.querystring();
|
||||||
self = this;
|
qs.debug = '';
|
||||||
this._rpc({
|
window.location.search = '?' + $.param(qs);
|
||||||
model: 'ir.model',
|
|
||||||
method: 'search',
|
|
||||||
args: [[['model', '=', model]]]
|
|
||||||
}).then(function (ids) {
|
|
||||||
self.do_action({
|
|
||||||
res_model: 'ir.model.fields',
|
|
||||||
name: _t('View Fields'),
|
|
||||||
views: [[false, 'list'], [false, 'form']],
|
|
||||||
domain: [['model_id', '=', model]],
|
|
||||||
type: 'ir.actions.act_window',
|
|
||||||
context: {
|
|
||||||
'default_model_id': ids[0]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
manage_filters: function () {
|
|
||||||
this.do_action({
|
|
||||||
res_model: 'ir.filters',
|
|
||||||
name: _t('Manage Filters'),
|
|
||||||
views: [[false, 'list'], [false, 'form']],
|
|
||||||
type: 'ir.actions.act_window',
|
|
||||||
context: {
|
|
||||||
search_default_my_filters: true,
|
|
||||||
search_default_model_id: this._action.res_model
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
translate: function() {
|
|
||||||
this._rpc({
|
|
||||||
model: 'ir.translation',
|
|
||||||
method: 'get_technical_translations',
|
|
||||||
args: [this._action.res_model],
|
|
||||||
})
|
|
||||||
.then(this.do_action);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DebugManager features depending on having a form view or single record.
|
|
||||||
* These could theoretically be split, but for now they'll be considered one
|
|
||||||
* and the same.
|
|
||||||
*/
|
|
||||||
DebugManager.include({
|
|
||||||
start: function () {
|
|
||||||
this._can_edit_views = false;
|
|
||||||
return Promise.all([
|
|
||||||
this._super(),
|
|
||||||
this._rpc({
|
|
||||||
model: 'ir.ui.view',
|
|
||||||
method: 'check_access_rights',
|
|
||||||
kwargs: {operation: 'write', raise_exception: false},
|
|
||||||
})
|
|
||||||
.then(function (ar) {
|
|
||||||
this._can_edit_views = ar;
|
|
||||||
}.bind(this))
|
|
||||||
]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
update: function (tag, descriptor, widget) {
|
|
||||||
if (tag === 'action' || tag === 'view') {
|
|
||||||
this._controller = widget;
|
|
||||||
}
|
|
||||||
return this._super(tag, descriptor).then(function () {
|
|
||||||
this.$dropdown.find(".o_debug_leave_section").before(QWeb.render('WebClient.DebugManager.View', {
|
|
||||||
action: this._action,
|
|
||||||
can_edit: this._can_edit_views,
|
|
||||||
controller: this._controller,
|
|
||||||
controlPanelView: this._controller && this._controller._controlPanel,
|
|
||||||
manager: this,
|
|
||||||
view: this._controller && _.findWhere(this._action.views, {
|
|
||||||
type: this._controller.viewType,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
get_attachments: function() {
|
|
||||||
var selectedIDs = this._controller.getSelectedIds();
|
|
||||||
if (!selectedIDs.length) {
|
|
||||||
console.warn(_t("No attachment available"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.do_action({
|
|
||||||
res_model: 'ir.attachment',
|
|
||||||
name: _t('Manage Attachments'),
|
|
||||||
views: [[false, 'list'], [false, 'form']],
|
|
||||||
type: 'ir.actions.act_window',
|
|
||||||
domain: [['res_model', '=', this._action.res_model], ['res_id', '=', selectedIDs[0]]],
|
|
||||||
context: {
|
|
||||||
default_res_model: this._action.res_model,
|
|
||||||
default_res_id: selectedIDs[0],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
get_metadata: function() {
|
|
||||||
var self = this;
|
|
||||||
var selectedIDs = this._controller.getSelectedIds();
|
|
||||||
if (!selectedIDs.length) {
|
|
||||||
console.warn(_t("No metadata available"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._rpc({
|
|
||||||
model: this._action.res_model,
|
|
||||||
method: 'get_metadata',
|
|
||||||
args: [selectedIDs],
|
|
||||||
}).then(function(result) {
|
|
||||||
var metadata = result[0];
|
|
||||||
metadata.creator = field_utils.format.many2one(metadata.create_uid);
|
|
||||||
metadata.lastModifiedBy = field_utils.format.many2one(metadata.write_uid);
|
|
||||||
var createDate = field_utils.parse.datetime(metadata.create_date);
|
|
||||||
metadata.create_date = field_utils.format.datetime(createDate);
|
|
||||||
var modificationDate = field_utils.parse.datetime(metadata.write_date);
|
|
||||||
metadata.write_date = field_utils.format.datetime(modificationDate);
|
|
||||||
var dialog = new Dialog(this, {
|
|
||||||
title: _.str.sprintf(_t("Metadata (%s)"), self._action.res_model),
|
|
||||||
size: 'medium',
|
|
||||||
$content: QWeb.render('WebClient.DebugViewLog', {
|
|
||||||
perm : metadata,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
dialog.open().opened(function () {
|
|
||||||
dialog.$el.on('click', 'a[data-action="toggle_noupdate"]', function (ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
self._rpc({
|
|
||||||
model: 'ir.model.data',
|
|
||||||
method: 'toggle_noupdate',
|
|
||||||
args: [self._action.res_model, metadata.id]
|
|
||||||
}).then(function (res) {
|
|
||||||
dialog.close();
|
|
||||||
self.get_metadata();
|
|
||||||
})
|
|
||||||
});
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
|
||||||
set_defaults: function() {
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
var display = function (fieldInfo, value) {
|
|
||||||
var displayed = value;
|
|
||||||
if (value && fieldInfo.type === 'many2one') {
|
|
||||||
displayed = value.data.display_name;
|
|
||||||
value = value.data.id;
|
|
||||||
} else if (value && fieldInfo.type === 'selection') {
|
|
||||||
displayed = _.find(fieldInfo.selection, function (option) {
|
|
||||||
return option[0] === value;
|
|
||||||
})[1];
|
|
||||||
}
|
|
||||||
return [value, displayed];
|
|
||||||
};
|
|
||||||
|
|
||||||
var renderer = this._controller.renderer;
|
|
||||||
var state = renderer.state;
|
|
||||||
var fields = state.fields;
|
|
||||||
var fieldsInfo = state.fieldsInfo.form;
|
|
||||||
var fieldNamesInView = state.getFieldNames();
|
|
||||||
var fieldNamesOnlyOnView = ['message_attachment_count'];
|
|
||||||
var fieldsValues = state.data;
|
|
||||||
var modifierDatas = {};
|
|
||||||
_.each(fieldNamesInView, function (fieldName) {
|
|
||||||
modifierDatas[fieldName] = _.find(renderer.allModifiersData, function (modifierdata) {
|
|
||||||
return modifierdata.node.attrs.name === fieldName;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
this.fields = _.chain(fieldNamesInView)
|
|
||||||
.difference(fieldNamesOnlyOnView)
|
|
||||||
.map(function (fieldName) {
|
|
||||||
var modifierData = modifierDatas[fieldName];
|
|
||||||
var invisibleOrReadOnly;
|
|
||||||
if (modifierData) {
|
|
||||||
var evaluatedModifiers = modifierData.evaluatedModifiers[state.id];
|
|
||||||
invisibleOrReadOnly = evaluatedModifiers.invisible || evaluatedModifiers.readonly;
|
|
||||||
}
|
|
||||||
var fieldInfo = fields[fieldName];
|
|
||||||
var valueDisplayed = display(fieldInfo, fieldsValues[fieldName]);
|
|
||||||
var value = valueDisplayed[0];
|
|
||||||
var displayed = valueDisplayed[1];
|
|
||||||
// ignore fields which are empty, invisible, readonly, o2m
|
|
||||||
// or m2m
|
|
||||||
if (!value || invisibleOrReadOnly || fieldInfo.type === 'one2many' ||
|
|
||||||
fieldInfo.type === 'many2many' || fieldInfo.type === 'binary' ||
|
|
||||||
fieldsInfo[fieldName].options.isPassword || !_.isEmpty(fieldInfo.depends)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
name: fieldName,
|
|
||||||
string: fieldInfo.string,
|
|
||||||
value: value,
|
|
||||||
displayed: displayed,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.compact()
|
|
||||||
.sortBy(function (field) { return field.string; })
|
|
||||||
.value();
|
|
||||||
|
|
||||||
var conditions = _.chain(fieldNamesInView)
|
|
||||||
.filter(function (fieldName) {
|
|
||||||
var fieldInfo = fields[fieldName];
|
|
||||||
return fieldInfo.change_default;
|
|
||||||
})
|
|
||||||
.map(function (fieldName) {
|
|
||||||
var fieldInfo = fields[fieldName];
|
|
||||||
var valueDisplayed = display(fieldInfo, fieldsValues[fieldName]);
|
|
||||||
var value = valueDisplayed[0];
|
|
||||||
var displayed = valueDisplayed[1];
|
|
||||||
return {
|
|
||||||
name: fieldName,
|
|
||||||
string: fieldInfo.string,
|
|
||||||
value: value,
|
|
||||||
displayed: displayed,
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.value();
|
|
||||||
var d = new Dialog(this, {
|
|
||||||
title: _t("Set Default"),
|
|
||||||
buttons: [
|
|
||||||
{text: _t("Close"), close: true},
|
|
||||||
{text: _t("Save default"), click: function () {
|
|
||||||
var $defaults = d.$el.find('#formview_default_fields');
|
|
||||||
var fieldToSet = $defaults.val();
|
|
||||||
if (!fieldToSet) {
|
|
||||||
$defaults.parent().addClass('o_form_invalid');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var selfUser = d.$el.find('#formview_default_self').is(':checked');
|
|
||||||
var condition = d.$el.find('#formview_default_conditions').val();
|
|
||||||
var value = _.find(self.fields, function (field) {
|
|
||||||
return field.name === fieldToSet;
|
|
||||||
}).value;
|
|
||||||
self._rpc({
|
|
||||||
model: 'ir.default',
|
|
||||||
method: 'set',
|
|
||||||
args: [
|
|
||||||
self._action.res_model,
|
|
||||||
fieldToSet,
|
|
||||||
value,
|
|
||||||
selfUser,
|
|
||||||
true,
|
|
||||||
condition || false,
|
|
||||||
],
|
|
||||||
}).then(function () { d.close(); });
|
|
||||||
}}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
d.args = {
|
|
||||||
fields: this.fields,
|
|
||||||
conditions: conditions,
|
|
||||||
};
|
|
||||||
d.template = 'FormView.set_default';
|
|
||||||
d.open();
|
|
||||||
},
|
|
||||||
fvg: function() {
|
|
||||||
var self = this;
|
|
||||||
var dialog = new Dialog(this, { title: _t("Fields View Get") });
|
|
||||||
dialog.opened().then(function () {
|
|
||||||
$('<pre>').text(utils.json_node_to_xml(
|
|
||||||
self._controller.renderer.arch, true)
|
|
||||||
).appendTo(dialog.$el);
|
|
||||||
});
|
|
||||||
dialog.open();
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
function make_context(width, height, fn) {
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = width;
|
|
||||||
canvas.height = height;
|
|
||||||
// make e.layerX/e.layerY imitate e.offsetX/e.offsetY.
|
|
||||||
canvas.style.position = 'relative';
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
ctx.imageSmoothingEnabled = false;
|
|
||||||
ctx.mozImageSmoothingEnabled = false;
|
|
||||||
ctx.oImageSmoothingEnabled = false;
|
|
||||||
ctx.webkitImageSmoothingEnabled = false;
|
|
||||||
fn && fn(ctx);
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
var RequestsOverlay = Widget.extend({
|
|
||||||
template: 'WebClient.DebugManager.RequestsOverlay',
|
|
||||||
TRACKS: 8,
|
|
||||||
TRACK_WIDTH: 9,
|
|
||||||
events: {
|
|
||||||
mousemove: function (e) {
|
|
||||||
this.$tooltip.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
init: function () {
|
|
||||||
this._super.apply(this, arguments);
|
|
||||||
this._render = _.throttle(
|
|
||||||
this._render.bind(this),
|
|
||||||
1000/15, {leading: false}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
start: function () {
|
|
||||||
var _super = this._super();
|
|
||||||
this.$tooltip = this.$('div.o_debug_tooltip');
|
|
||||||
this.getParent().on('update-stats', this, this._render);
|
|
||||||
this._render();
|
|
||||||
return _super;
|
|
||||||
},
|
|
||||||
tooltip: function (text, start, end, x, y) {
|
|
||||||
// x and y are hit point with respect to the viewport. To know where
|
|
||||||
// this hit point is with respect to the overlay, subtract the offset
|
|
||||||
// between viewport and overlay, then add scroll factor of overlay
|
|
||||||
// (which isn't taken in account by the viewport).
|
|
||||||
//
|
|
||||||
// Normally the viewport overlay should sum offsets of all
|
|
||||||
// offsetParents until we reach `null` but in this case the overlay
|
|
||||||
// should have been added directly to the body, which should have an
|
|
||||||
// offset of 0.
|
|
||||||
|
|
||||||
var top = y - this.el.offsetTop + this.el.scrollTop + 1;
|
|
||||||
var left = x - this.el.offsetLeft + this.el.scrollLeft + 1;
|
|
||||||
this.$tooltip.css({top: top, left: left}).show()[0].innerHTML = ['<p>', text, ' (', (end - start), 'ms)', '</p>'].join('');
|
|
||||||
},
|
|
||||||
|
|
||||||
_render: function () {
|
|
||||||
var $summary = this.$('header'),
|
|
||||||
w = $summary[0].clientWidth,
|
|
||||||
$requests = this.$('.o_debug_requests');
|
|
||||||
$summary.find('canvas').attr('width', w);
|
|
||||||
var tracks = document.getElementById('o_debug_requests_summary');
|
|
||||||
|
|
||||||
_.invoke(this.getChildren(), 'destroy');
|
|
||||||
|
|
||||||
var requests = this.getParent()._events;
|
|
||||||
var bounds = this._get_bounds(requests);
|
|
||||||
// horizontal scaling factor for summary
|
|
||||||
var scale = w / (bounds.high - bounds.low);
|
|
||||||
|
|
||||||
// store end-time of "current" requests, to find out which track a
|
|
||||||
// request should go in, just look for the first track whose end-time
|
|
||||||
// is smaller than the new request's start time.
|
|
||||||
var track_ends = _(this.TRACKS).times(_.constant(-Infinity));
|
|
||||||
|
|
||||||
var ctx = tracks.getContext('2d');
|
|
||||||
ctx.lineWidth = this.TRACK_WIDTH;
|
|
||||||
for (var i = 0; i < requests.length; i++) {
|
|
||||||
var request = requests[i];
|
|
||||||
// FIXME: is it certain that events in the request are sorted by timestamp?
|
|
||||||
var rstart = Math.floor(request[0][3] * 1e3);
|
|
||||||
var rend = Math.ceil(request[request.length - 1][3] * 1e3);
|
|
||||||
// find free track for current request
|
|
||||||
for(var track=0; track < track_ends.length; ++track) {
|
|
||||||
if (track_ends[track] < rstart) { break; }
|
|
||||||
}
|
|
||||||
// FIXME: display error message of some sort? Re-render with larger area? Something?
|
|
||||||
if (track >= track_ends.length) {
|
|
||||||
console.warn("could not find an empty summary track");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// set new track end
|
|
||||||
track_ends[track] = rend;
|
|
||||||
ctx.save();
|
|
||||||
ctx.translate(Math.floor((rstart - bounds.low) * scale), track * (this.TRACK_WIDTH + 1));
|
|
||||||
this._draw_request(request, ctx, 0, scale);
|
|
||||||
ctx.restore();
|
|
||||||
new RequestDetails(this, request, scale).appendTo($requests);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_draw_request: function (request, to_context, step, hscale, handle_event) {
|
|
||||||
// have one draw surface for each event type:
|
|
||||||
// * no need to alter context from one event to the next, each surface
|
|
||||||
// gets its own color for all its lifetime
|
|
||||||
// * surfaces can be blended in a specified order, which means events
|
|
||||||
// can be drawn in any order, no need to care about z-index while
|
|
||||||
// serializing events to the surfaces
|
|
||||||
var surfaces = {
|
|
||||||
request: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
|
||||||
ctx.strokeStyle = 'blue';
|
|
||||||
ctx.fillStyle = '#88f';
|
|
||||||
ctx.lineJoin = 'round';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
}),
|
|
||||||
//func: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
|
||||||
// ctx.strokeStyle = 'gray';
|
|
||||||
// ctx.lineWidth = to_context.lineWidth;
|
|
||||||
// ctx.translate(0, initial_offset);
|
|
||||||
//}),
|
|
||||||
sql: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
|
||||||
ctx.strokeStyle = 'red';
|
|
||||||
ctx.fillStyle = '#f88';
|
|
||||||
ctx.lineJoin = 'round';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
}),
|
|
||||||
template: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
|
||||||
ctx.strokeStyle = 'green';
|
|
||||||
ctx.fillStyle = '#8f8';
|
|
||||||
ctx.lineJoin = 'round';
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
})
|
|
||||||
};
|
|
||||||
// apply scaling manually so zooming in improves display precision
|
|
||||||
var stacks = {}, start = Math.floor(request[0][3] * 1e3 * hscale);
|
|
||||||
var event_idx = 0;
|
|
||||||
|
|
||||||
var rect_width = to_context.lineWidth;
|
|
||||||
for (var i = 0; i < request.length; i++) {
|
|
||||||
var type, m, event = request[i];
|
|
||||||
var tag = event[0], timestamp = Math.floor(event[3] * 1e3 * hscale) - start;
|
|
||||||
|
|
||||||
if (m = /(\w+)-start/.exec(tag)) {
|
|
||||||
type = m[1];
|
|
||||||
if (!(type in stacks)) { stacks[type] = []; }
|
|
||||||
handle_event && handle_event(event_idx, timestamp, event);
|
|
||||||
stacks[type].push({
|
|
||||||
timestamp: timestamp,
|
|
||||||
idx: event_idx++
|
|
||||||
});
|
|
||||||
} else if (m = /(\w+)-end/.exec(tag)) {
|
|
||||||
type = m[1];
|
|
||||||
var stack = stacks[type];
|
|
||||||
var estart = stack.pop(), duration = Math.ceil(timestamp - estart.timestamp);
|
|
||||||
handle_event && handle_event(estart.idx, timestamp, event);
|
|
||||||
|
|
||||||
var surface = surfaces[type];
|
|
||||||
if (!surface) { continue; } // FIXME: support for unknown event types
|
|
||||||
|
|
||||||
var y = step * estart.idx;
|
|
||||||
// path rectangle for the current event on the relevant surface
|
|
||||||
surface.rect(estart.timestamp + 0.5, y + 0.5, duration || 1, rect_width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// add each layer to the main canvas
|
|
||||||
var keys = ['request', /*'func', */'template', 'sql'];
|
|
||||||
for (var j = 0; j < keys.length; ++j) {
|
|
||||||
// stroke and fill all rectangles for the relevant surface/context
|
|
||||||
var ctx = surfaces[keys[j]];
|
|
||||||
ctx.fill();
|
|
||||||
ctx.stroke();
|
|
||||||
to_context.drawImage(ctx.canvas, 0, 0);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Returns first and last events in milliseconds
|
|
||||||
*
|
|
||||||
* @param requests
|
|
||||||
* @returns {{low: number, high: number}}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
_get_bounds: function (requests) {
|
|
||||||
var low = +Infinity;
|
|
||||||
var high =-+Infinity;
|
|
||||||
|
|
||||||
for (var i = 0; i < requests.length; i++) {
|
|
||||||
var request = requests[i];
|
|
||||||
for (var j = 0; j < request.length; j++) {
|
|
||||||
var event = request[j];
|
|
||||||
var timestamp = event[3];
|
|
||||||
low = Math.min(low, timestamp);
|
|
||||||
high = Math.max(high, timestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {low: Math.floor(low * 1e3), high: Math.ceil(high * 1e3)};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var RequestDetails = Widget.extend({
|
|
||||||
events: {
|
|
||||||
click: function () {
|
|
||||||
this._open = !this._open;
|
|
||||||
this.render();
|
|
||||||
},
|
|
||||||
'mousemove canvas': function (e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
var y = e.y || e.offsetY || e.layerY;
|
|
||||||
if (!y) { return; }
|
|
||||||
var event = this._payloads[Math.floor(y / this._REQ_HEIGHT)];
|
|
||||||
if (!event) { return; }
|
|
||||||
|
|
||||||
this.getParent().tooltip(event.payload, event.start, event.stop, e.clientX, e.clientY);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
init: function (parent, request, scale) {
|
|
||||||
this._super.apply(this, arguments);
|
|
||||||
this._request = request;
|
|
||||||
this._open = false;
|
|
||||||
this._scale = scale;
|
|
||||||
this._REQ_HEIGHT = 20;
|
|
||||||
},
|
|
||||||
start: function () {
|
|
||||||
this.el.style.borderBottom = '1px solid black';
|
|
||||||
this.render();
|
|
||||||
return this._super();
|
|
||||||
},
|
|
||||||
render: function () {
|
|
||||||
var request_cell_height = this._REQ_HEIGHT, TITLE_WIDTH = 200;
|
|
||||||
var request = this._request;
|
|
||||||
var req_start = request[0][3] * 1e3;
|
|
||||||
var req_duration = request[request.length - 1][3] * 1e3 - req_start;
|
|
||||||
var height = request_cell_height * (this._open ? request.length / 2 : 1);
|
|
||||||
var cell_center = request_cell_height / 2;
|
|
||||||
var ctx = make_context(210 + Math.ceil(req_duration * this._scale), height, function (ctx) {
|
|
||||||
ctx.lineWidth = cell_center;
|
|
||||||
});
|
|
||||||
this.$el.empty().append(ctx.canvas);
|
|
||||||
var payloads = this._payloads = [];
|
|
||||||
|
|
||||||
// lazy version: if the render is single-line (!this._open), the extra
|
|
||||||
// content will be discarded when the text canvas gets pasted onto the
|
|
||||||
// main canvas. An improvement would be to not do text rendering
|
|
||||||
// beyond the first event for "closed" requests events… then again
|
|
||||||
// that makes for more regular rendering profile?
|
|
||||||
var text_ctx = make_context(TITLE_WIDTH, height, function (ctx) {
|
|
||||||
ctx.font = '12px sans-serif';
|
|
||||||
ctx.textAlign = 'right';
|
|
||||||
ctx.textBaseline = 'middle';
|
|
||||||
ctx.translate(0, cell_center);
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.save();
|
|
||||||
ctx.translate(TITLE_WIDTH + 10, ((request_cell_height/4)|0));
|
|
||||||
|
|
||||||
this.getParent()._draw_request(request, ctx, this._open ? request_cell_height : 0, this._scale, function (idx, timestamp, event) {
|
|
||||||
if (/-start$/g.test(event[0])) {
|
|
||||||
payloads.push({
|
|
||||||
payload: event[2],
|
|
||||||
start: timestamp,
|
|
||||||
stop: null
|
|
||||||
});
|
|
||||||
|
|
||||||
// we want ~200px wide, assume the average character is at
|
|
||||||
// least 4px wide => there can be *at most* 49 characters
|
|
||||||
var title = event[2];
|
|
||||||
title = title.replace(/\s+$/, '');
|
|
||||||
title = title.length <= 50 ? title : ('…' + title.slice(-49));
|
|
||||||
while (text_ctx.measureText(title).width > 200) {
|
|
||||||
title = '…' + title.slice(2);
|
|
||||||
}
|
|
||||||
text_ctx.fillText(title, TITLE_WIDTH, request_cell_height * idx);
|
|
||||||
} else if (/-end$/g.test(event[0])) {
|
|
||||||
payloads[idx].stop = timestamp;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ctx.restore();
|
|
||||||
// add the text layer to the main canvas
|
|
||||||
ctx.drawImage(text_ctx.canvas, 0, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (config.debug) {
|
|
||||||
SystrayMenu.Items.push(DebugManager);
|
|
||||||
|
|
||||||
WebClient.include({
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// Public
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
current_action_updated: function (action, controller) {
|
|
||||||
this._super.apply(this, arguments);
|
|
||||||
var debugManager = _.find(this.menu.systray_menu.widgets, function(item) {
|
|
||||||
return item instanceof DebugManager;
|
|
||||||
});
|
|
||||||
debugManager.update('action', action, controller && controller.widget);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
ActionManager.include({
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
// Public
|
|
||||||
//----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the action of the controller currently opened in a dialog,
|
|
||||||
* i.e. a target='new' action, if any.
|
|
||||||
*
|
|
||||||
* @returns {Object|null}
|
|
||||||
*/
|
|
||||||
getCurrentActionInDialog: function () {
|
|
||||||
if (this.currentDialogController) {
|
|
||||||
return this.actions[this.currentDialogController.actionID];
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Returns the controller currently opened in a dialog, if any.
|
|
||||||
*
|
|
||||||
* @returns {Object|null}
|
|
||||||
*/
|
|
||||||
getCurrentControllerInDialog: function () {
|
|
||||||
return this.currentDialogController;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
Dialog.include({
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
// Public
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
open: function() {
|
|
||||||
var self = this;
|
|
||||||
// if the dialog is opened by the ActionManager, instantiate a
|
|
||||||
// DebugManager and insert it into the DOM once the dialog is opened
|
|
||||||
// (delay this with a setTimeout(0) to ensure that the internal
|
|
||||||
// state, i.e. the current action and controller, of the
|
|
||||||
// ActionManager is set to properly update the DebugManager)
|
|
||||||
this.opened(function() {
|
|
||||||
setTimeout(function () {
|
|
||||||
var parent = self.getParent();
|
|
||||||
if (parent instanceof ActionManager) {
|
|
||||||
var action = parent.getCurrentActionInDialog();
|
|
||||||
if (action) {
|
|
||||||
var controller = parent.getCurrentControllerInDialog();
|
|
||||||
self.debugManager = new DebugManager(self);
|
|
||||||
var $header = self.$modal.find('.modal-header:first');
|
|
||||||
return self.debugManager.prependTo($header).then(function () {
|
|
||||||
self.debugManager.update('action', action, controller.widget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._super.apply(this, arguments);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return DebugManager;
|
return DebugManager;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,766 @@
|
|||||||
|
odoo.define('web.DebugManager.Backend', function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var ActionManager = require('web.ActionManager');
|
||||||
|
var DebugManager = require('web.DebugManager');
|
||||||
|
var dialogs = require('web.view_dialogs');
|
||||||
|
var startClickEverywhere = require('web.clickEverywhere');
|
||||||
|
var config = require('web.config');
|
||||||
|
var core = require('web.core');
|
||||||
|
var Dialog = require('web.Dialog');
|
||||||
|
var SystrayMenu = require('web.SystrayMenu');
|
||||||
|
var utils = require('web.utils');
|
||||||
|
var WebClient = require('web.WebClient');
|
||||||
|
var Widget = require('web.Widget');
|
||||||
|
|
||||||
|
var QWeb = core.qweb;
|
||||||
|
var _t = core._t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DebugManager features depending on backend
|
||||||
|
*/
|
||||||
|
DebugManager.include({
|
||||||
|
requests_clear: function () {
|
||||||
|
if (!this._events) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._events = [];
|
||||||
|
this.trigger('update-stats', this._events);
|
||||||
|
},
|
||||||
|
show_timelines: function () {
|
||||||
|
if (this._overlay) {
|
||||||
|
this._overlay.destroy();
|
||||||
|
this._overlay = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._overlay = new RequestsOverlay(this);
|
||||||
|
this._overlay.appendTo(document.body);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates current action (action descriptor) on tag = action,
|
||||||
|
*/
|
||||||
|
update: function (tag, descriptor) {
|
||||||
|
return this._super().then(function () {
|
||||||
|
this.$dropdown.find(".o_debug_split_assets").before(QWeb.render('WebClient.DebugManager.Backend', {
|
||||||
|
manager: this,
|
||||||
|
}));
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
select_view: function () {
|
||||||
|
var self = this;
|
||||||
|
new dialogs.SelectCreateDialog(this, {
|
||||||
|
res_model: 'ir.ui.view',
|
||||||
|
title: _t('Select a view'),
|
||||||
|
disable_multiple_selection: true,
|
||||||
|
domain: [['type', '!=', 'qweb'], ['type', '!=', 'search']],
|
||||||
|
on_selected: function (records) {
|
||||||
|
self._rpc({
|
||||||
|
model: 'ir.ui.view',
|
||||||
|
method: 'search_read',
|
||||||
|
domain: [['id', '=', records[0].id]],
|
||||||
|
fields: ['name', 'model', 'type'],
|
||||||
|
limit: 1,
|
||||||
|
})
|
||||||
|
.then(function (views) {
|
||||||
|
var view = views[0];
|
||||||
|
view.type = view.type === 'tree' ? 'list' : view.type; // ignore tree view
|
||||||
|
self.do_action({
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
name: view.name,
|
||||||
|
res_model: view.model,
|
||||||
|
views: [[view.id, view.type]]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).open();
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Runs the JS (desktop) tests
|
||||||
|
*/
|
||||||
|
perform_js_tests: function () {
|
||||||
|
this.do_action({
|
||||||
|
name: _t("JS Tests"),
|
||||||
|
target: 'new',
|
||||||
|
type: 'ir.actions.act_url',
|
||||||
|
url: '/web/tests?mod=*'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Runs the JS mobile tests
|
||||||
|
*/
|
||||||
|
perform_js_mobile_tests: function () {
|
||||||
|
this.do_action({
|
||||||
|
name: _t("JS Mobile Tests"),
|
||||||
|
target: 'new',
|
||||||
|
type: 'ir.actions.act_url',
|
||||||
|
url: '/web/tests/mobile?mod=*'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
perform_click_everywhere_test: function () {
|
||||||
|
var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th");
|
||||||
|
$homeMenu.click();
|
||||||
|
startClickEverywhere();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DebugManager features depending on having an action, and possibly a model
|
||||||
|
* (window action)
|
||||||
|
*/
|
||||||
|
DebugManager.include({
|
||||||
|
/**
|
||||||
|
* Updates current action (action descriptor) on tag = action,
|
||||||
|
*/
|
||||||
|
update: function (tag, descriptor) {
|
||||||
|
if (tag === 'action') {
|
||||||
|
this._action = descriptor;
|
||||||
|
}
|
||||||
|
return this._super().then(function () {
|
||||||
|
this.$dropdown.find(".o_debug_leave_section").before(QWeb.render('WebClient.DebugManager.Action', {
|
||||||
|
manager: this,
|
||||||
|
action: this._action
|
||||||
|
}));
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
edit: function (params, evt) {
|
||||||
|
this.do_action({
|
||||||
|
res_model: params.model,
|
||||||
|
res_id: params.id,
|
||||||
|
name: evt.target.text,
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
views: [[false, 'form']],
|
||||||
|
view_mode: 'form',
|
||||||
|
target: 'new',
|
||||||
|
flags: {action_buttons: true, headless: true}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get_view_fields: function () {
|
||||||
|
var model = this._action.res_model,
|
||||||
|
self = this;
|
||||||
|
this._rpc({
|
||||||
|
model: 'ir.model',
|
||||||
|
method: 'search',
|
||||||
|
args: [[['model', '=', model]]]
|
||||||
|
}).then(function (ids) {
|
||||||
|
self.do_action({
|
||||||
|
res_model: 'ir.model.fields',
|
||||||
|
name: _t('View Fields'),
|
||||||
|
views: [[false, 'list'], [false, 'form']],
|
||||||
|
domain: [['model_id', '=', model]],
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
context: {
|
||||||
|
'default_model_id': ids[0]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
manage_filters: function () {
|
||||||
|
this.do_action({
|
||||||
|
res_model: 'ir.filters',
|
||||||
|
name: _t('Manage Filters'),
|
||||||
|
views: [[false, 'list'], [false, 'form']],
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
context: {
|
||||||
|
search_default_my_filters: true,
|
||||||
|
search_default_model_id: this._action.res_model
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
translate: function() {
|
||||||
|
this._rpc({
|
||||||
|
model: 'ir.translation',
|
||||||
|
method: 'get_technical_translations',
|
||||||
|
args: [this._action.res_model],
|
||||||
|
})
|
||||||
|
.then(this.do_action);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DebugManager features depending on having a form view or single record.
|
||||||
|
* These could theoretically be split, but for now they'll be considered one
|
||||||
|
* and the same.
|
||||||
|
*/
|
||||||
|
DebugManager.include({
|
||||||
|
start: function () {
|
||||||
|
this._can_edit_views = false;
|
||||||
|
return Promise.all([
|
||||||
|
this._super(),
|
||||||
|
this._rpc({
|
||||||
|
model: 'ir.ui.view',
|
||||||
|
method: 'check_access_rights',
|
||||||
|
kwargs: {operation: 'write', raise_exception: false},
|
||||||
|
})
|
||||||
|
.then(function (ar) {
|
||||||
|
this._can_edit_views = ar;
|
||||||
|
}.bind(this))
|
||||||
|
]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
update: function (tag, descriptor, widget) {
|
||||||
|
if (tag === 'action' || tag === 'view') {
|
||||||
|
this._controller = widget;
|
||||||
|
}
|
||||||
|
return this._super(tag, descriptor).then(function () {
|
||||||
|
this.$dropdown.find(".o_debug_leave_section").before(QWeb.render('WebClient.DebugManager.View', {
|
||||||
|
action: this._action,
|
||||||
|
can_edit: this._can_edit_views,
|
||||||
|
controller: this._controller,
|
||||||
|
controlPanelView: this._controller && this._controller._controlPanel,
|
||||||
|
manager: this,
|
||||||
|
view: this._controller && _.findWhere(this._action.views, {
|
||||||
|
type: this._controller.viewType,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
get_attachments: function() {
|
||||||
|
var selectedIDs = this._controller.getSelectedIds();
|
||||||
|
if (!selectedIDs.length) {
|
||||||
|
console.warn(_t("No attachment available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.do_action({
|
||||||
|
res_model: 'ir.attachment',
|
||||||
|
name: _t('Manage Attachments'),
|
||||||
|
views: [[false, 'list'], [false, 'form']],
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
domain: [['res_model', '=', this._action.res_model], ['res_id', '=', selectedIDs[0]]],
|
||||||
|
context: {
|
||||||
|
default_res_model: this._action.res_model,
|
||||||
|
default_res_id: selectedIDs[0],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get_metadata: function() {
|
||||||
|
var self = this;
|
||||||
|
var selectedIDs = this._controller.getSelectedIds();
|
||||||
|
if (!selectedIDs.length) {
|
||||||
|
console.warn(_t("No metadata available"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._rpc({
|
||||||
|
model: this._action.res_model,
|
||||||
|
method: 'get_metadata',
|
||||||
|
args: [selectedIDs],
|
||||||
|
}).then(function(result) {
|
||||||
|
var metadata = result[0];
|
||||||
|
metadata.creator = field_utils.format.many2one(metadata.create_uid);
|
||||||
|
metadata.lastModifiedBy = field_utils.format.many2one(metadata.write_uid);
|
||||||
|
var createDate = field_utils.parse.datetime(metadata.create_date);
|
||||||
|
metadata.create_date = field_utils.format.datetime(createDate);
|
||||||
|
var modificationDate = field_utils.parse.datetime(metadata.write_date);
|
||||||
|
metadata.write_date = field_utils.format.datetime(modificationDate);
|
||||||
|
var dialog = new Dialog(this, {
|
||||||
|
title: _.str.sprintf(_t("Metadata (%s)"), self._action.res_model),
|
||||||
|
size: 'medium',
|
||||||
|
$content: QWeb.render('WebClient.DebugViewLog', {
|
||||||
|
perm : metadata,
|
||||||
|
})
|
||||||
|
});
|
||||||
|
dialog.open().opened(function () {
|
||||||
|
dialog.$el.on('click', 'a[data-action="toggle_noupdate"]', function (ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
self._rpc({
|
||||||
|
model: 'ir.model.data',
|
||||||
|
method: 'toggle_noupdate',
|
||||||
|
args: [self._action.res_model, metadata.id]
|
||||||
|
}).then(function (res) {
|
||||||
|
dialog.close();
|
||||||
|
self.get_metadata();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
set_defaults: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var display = function (fieldInfo, value) {
|
||||||
|
var displayed = value;
|
||||||
|
if (value && fieldInfo.type === 'many2one') {
|
||||||
|
displayed = value.data.display_name;
|
||||||
|
value = value.data.id;
|
||||||
|
} else if (value && fieldInfo.type === 'selection') {
|
||||||
|
displayed = _.find(fieldInfo.selection, function (option) {
|
||||||
|
return option[0] === value;
|
||||||
|
})[1];
|
||||||
|
}
|
||||||
|
return [value, displayed];
|
||||||
|
};
|
||||||
|
|
||||||
|
var renderer = this._controller.renderer;
|
||||||
|
var state = renderer.state;
|
||||||
|
var fields = state.fields;
|
||||||
|
var fieldsInfo = state.fieldsInfo.form;
|
||||||
|
var fieldNamesInView = state.getFieldNames();
|
||||||
|
var fieldNamesOnlyOnView = ['message_attachment_count'];
|
||||||
|
var fieldsValues = state.data;
|
||||||
|
var modifierDatas = {};
|
||||||
|
_.each(fieldNamesInView, function (fieldName) {
|
||||||
|
modifierDatas[fieldName] = _.find(renderer.allModifiersData, function (modifierdata) {
|
||||||
|
return modifierdata.node.attrs.name === fieldName;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.fields = _.chain(fieldNamesInView)
|
||||||
|
.difference(fieldNamesOnlyOnView)
|
||||||
|
.map(function (fieldName) {
|
||||||
|
var modifierData = modifierDatas[fieldName];
|
||||||
|
var invisibleOrReadOnly;
|
||||||
|
if (modifierData) {
|
||||||
|
var evaluatedModifiers = modifierData.evaluatedModifiers[state.id];
|
||||||
|
invisibleOrReadOnly = evaluatedModifiers.invisible || evaluatedModifiers.readonly;
|
||||||
|
}
|
||||||
|
var fieldInfo = fields[fieldName];
|
||||||
|
var valueDisplayed = display(fieldInfo, fieldsValues[fieldName]);
|
||||||
|
var value = valueDisplayed[0];
|
||||||
|
var displayed = valueDisplayed[1];
|
||||||
|
// ignore fields which are empty, invisible, readonly, o2m
|
||||||
|
// or m2m
|
||||||
|
if (!value || invisibleOrReadOnly || fieldInfo.type === 'one2many' ||
|
||||||
|
fieldInfo.type === 'many2many' || fieldInfo.type === 'binary' ||
|
||||||
|
fieldsInfo[fieldName].options.isPassword || !_.isEmpty(fieldInfo.depends)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
name: fieldName,
|
||||||
|
string: fieldInfo.string,
|
||||||
|
value: value,
|
||||||
|
displayed: displayed,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.compact()
|
||||||
|
.sortBy(function (field) { return field.string; })
|
||||||
|
.value();
|
||||||
|
|
||||||
|
var conditions = _.chain(fieldNamesInView)
|
||||||
|
.filter(function (fieldName) {
|
||||||
|
var fieldInfo = fields[fieldName];
|
||||||
|
return fieldInfo.change_default;
|
||||||
|
})
|
||||||
|
.map(function (fieldName) {
|
||||||
|
var fieldInfo = fields[fieldName];
|
||||||
|
var valueDisplayed = display(fieldInfo, fieldsValues[fieldName]);
|
||||||
|
var value = valueDisplayed[0];
|
||||||
|
var displayed = valueDisplayed[1];
|
||||||
|
return {
|
||||||
|
name: fieldName,
|
||||||
|
string: fieldInfo.string,
|
||||||
|
value: value,
|
||||||
|
displayed: displayed,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.value();
|
||||||
|
var d = new Dialog(this, {
|
||||||
|
title: _t("Set Default"),
|
||||||
|
buttons: [
|
||||||
|
{text: _t("Close"), close: true},
|
||||||
|
{text: _t("Save default"), click: function () {
|
||||||
|
var $defaults = d.$el.find('#formview_default_fields');
|
||||||
|
var fieldToSet = $defaults.val();
|
||||||
|
if (!fieldToSet) {
|
||||||
|
$defaults.parent().addClass('o_form_invalid');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var selfUser = d.$el.find('#formview_default_self').is(':checked');
|
||||||
|
var condition = d.$el.find('#formview_default_conditions').val();
|
||||||
|
var value = _.find(self.fields, function (field) {
|
||||||
|
return field.name === fieldToSet;
|
||||||
|
}).value;
|
||||||
|
self._rpc({
|
||||||
|
model: 'ir.default',
|
||||||
|
method: 'set',
|
||||||
|
args: [
|
||||||
|
self._action.res_model,
|
||||||
|
fieldToSet,
|
||||||
|
value,
|
||||||
|
selfUser,
|
||||||
|
true,
|
||||||
|
condition || false,
|
||||||
|
],
|
||||||
|
}).then(function () { d.close(); });
|
||||||
|
}}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
d.args = {
|
||||||
|
fields: this.fields,
|
||||||
|
conditions: conditions,
|
||||||
|
};
|
||||||
|
d.template = 'FormView.set_default';
|
||||||
|
d.open();
|
||||||
|
},
|
||||||
|
fvg: function() {
|
||||||
|
var self = this;
|
||||||
|
var dialog = new Dialog(this, { title: _t("Fields View Get") });
|
||||||
|
dialog.opened().then(function () {
|
||||||
|
$('<pre>').text(utils.json_node_to_xml(
|
||||||
|
self._controller.renderer.arch, true)
|
||||||
|
).appendTo(dialog.$el);
|
||||||
|
});
|
||||||
|
dialog.open();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
function make_context(width, height, fn) {
|
||||||
|
var canvas = document.createElement('canvas');
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
// make e.layerX/e.layerY imitate e.offsetX/e.offsetY.
|
||||||
|
canvas.style.position = 'relative';
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
ctx.mozImageSmoothingEnabled = false;
|
||||||
|
ctx.oImageSmoothingEnabled = false;
|
||||||
|
ctx.webkitImageSmoothingEnabled = false;
|
||||||
|
fn && fn(ctx);
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
var RequestsOverlay = Widget.extend({
|
||||||
|
template: 'WebClient.DebugManager.RequestsOverlay',
|
||||||
|
TRACKS: 8,
|
||||||
|
TRACK_WIDTH: 9,
|
||||||
|
events: {
|
||||||
|
mousemove: function (e) {
|
||||||
|
this.$tooltip.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init: function () {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this._render = _.throttle(
|
||||||
|
this._render.bind(this),
|
||||||
|
1000/15, {leading: false}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
start: function () {
|
||||||
|
var _super = this._super();
|
||||||
|
this.$tooltip = this.$('div.o_debug_tooltip');
|
||||||
|
this.getParent().on('update-stats', this, this._render);
|
||||||
|
this._render();
|
||||||
|
return _super;
|
||||||
|
},
|
||||||
|
tooltip: function (text, start, end, x, y) {
|
||||||
|
// x and y are hit point with respect to the viewport. To know where
|
||||||
|
// this hit point is with respect to the overlay, subtract the offset
|
||||||
|
// between viewport and overlay, then add scroll factor of overlay
|
||||||
|
// (which isn't taken in account by the viewport).
|
||||||
|
//
|
||||||
|
// Normally the viewport overlay should sum offsets of all
|
||||||
|
// offsetParents until we reach `null` but in this case the overlay
|
||||||
|
// should have been added directly to the body, which should have an
|
||||||
|
// offset of 0.
|
||||||
|
|
||||||
|
var top = y - this.el.offsetTop + this.el.scrollTop + 1;
|
||||||
|
var left = x - this.el.offsetLeft + this.el.scrollLeft + 1;
|
||||||
|
this.$tooltip.css({top: top, left: left}).show()[0].innerHTML = ['<p>', text, ' (', (end - start), 'ms)', '</p>'].join('');
|
||||||
|
},
|
||||||
|
|
||||||
|
_render: function () {
|
||||||
|
var $summary = this.$('header'),
|
||||||
|
w = $summary[0].clientWidth,
|
||||||
|
$requests = this.$('.o_debug_requests');
|
||||||
|
$summary.find('canvas').attr('width', w);
|
||||||
|
var tracks = document.getElementById('o_debug_requests_summary');
|
||||||
|
|
||||||
|
_.invoke(this.getChildren(), 'destroy');
|
||||||
|
|
||||||
|
var requests = this.getParent()._events;
|
||||||
|
var bounds = this._get_bounds(requests);
|
||||||
|
// horizontal scaling factor for summary
|
||||||
|
var scale = w / (bounds.high - bounds.low);
|
||||||
|
|
||||||
|
// store end-time of "current" requests, to find out which track a
|
||||||
|
// request should go in, just look for the first track whose end-time
|
||||||
|
// is smaller than the new request's start time.
|
||||||
|
var track_ends = _(this.TRACKS).times(_.constant(-Infinity));
|
||||||
|
|
||||||
|
var ctx = tracks.getContext('2d');
|
||||||
|
ctx.lineWidth = this.TRACK_WIDTH;
|
||||||
|
for (var i = 0; i < requests.length; i++) {
|
||||||
|
var request = requests[i];
|
||||||
|
// FIXME: is it certain that events in the request are sorted by timestamp?
|
||||||
|
var rstart = Math.floor(request[0][3] * 1e3);
|
||||||
|
var rend = Math.ceil(request[request.length - 1][3] * 1e3);
|
||||||
|
// find free track for current request
|
||||||
|
for(var track=0; track < track_ends.length; ++track) {
|
||||||
|
if (track_ends[track] < rstart) { break; }
|
||||||
|
}
|
||||||
|
// FIXME: display error message of some sort? Re-render with larger area? Something?
|
||||||
|
if (track >= track_ends.length) {
|
||||||
|
console.warn("could not find an empty summary track");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// set new track end
|
||||||
|
track_ends[track] = rend;
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(Math.floor((rstart - bounds.low) * scale), track * (this.TRACK_WIDTH + 1));
|
||||||
|
this._draw_request(request, ctx, 0, scale);
|
||||||
|
ctx.restore();
|
||||||
|
new RequestDetails(this, request, scale).appendTo($requests);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_draw_request: function (request, to_context, step, hscale, handle_event) {
|
||||||
|
// have one draw surface for each event type:
|
||||||
|
// * no need to alter context from one event to the next, each surface
|
||||||
|
// gets its own color for all its lifetime
|
||||||
|
// * surfaces can be blended in a specified order, which means events
|
||||||
|
// can be drawn in any order, no need to care about z-index while
|
||||||
|
// serializing events to the surfaces
|
||||||
|
var surfaces = {
|
||||||
|
request: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
||||||
|
ctx.strokeStyle = 'blue';
|
||||||
|
ctx.fillStyle = '#88f';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
}),
|
||||||
|
//func: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
||||||
|
// ctx.strokeStyle = 'gray';
|
||||||
|
// ctx.lineWidth = to_context.lineWidth;
|
||||||
|
// ctx.translate(0, initial_offset);
|
||||||
|
//}),
|
||||||
|
sql: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
||||||
|
ctx.strokeStyle = 'red';
|
||||||
|
ctx.fillStyle = '#f88';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
}),
|
||||||
|
template: make_context(to_context.canvas.width, to_context.canvas.height, function (ctx) {
|
||||||
|
ctx.strokeStyle = 'green';
|
||||||
|
ctx.fillStyle = '#8f8';
|
||||||
|
ctx.lineJoin = 'round';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// apply scaling manually so zooming in improves display precision
|
||||||
|
var stacks = {}, start = Math.floor(request[0][3] * 1e3 * hscale);
|
||||||
|
var event_idx = 0;
|
||||||
|
|
||||||
|
var rect_width = to_context.lineWidth;
|
||||||
|
for (var i = 0; i < request.length; i++) {
|
||||||
|
var type, m, event = request[i];
|
||||||
|
var tag = event[0], timestamp = Math.floor(event[3] * 1e3 * hscale) - start;
|
||||||
|
|
||||||
|
if (m = /(\w+)-start/.exec(tag)) {
|
||||||
|
type = m[1];
|
||||||
|
if (!(type in stacks)) { stacks[type] = []; }
|
||||||
|
handle_event && handle_event(event_idx, timestamp, event);
|
||||||
|
stacks[type].push({
|
||||||
|
timestamp: timestamp,
|
||||||
|
idx: event_idx++
|
||||||
|
});
|
||||||
|
} else if (m = /(\w+)-end/.exec(tag)) {
|
||||||
|
type = m[1];
|
||||||
|
var stack = stacks[type];
|
||||||
|
var estart = stack.pop(), duration = Math.ceil(timestamp - estart.timestamp);
|
||||||
|
handle_event && handle_event(estart.idx, timestamp, event);
|
||||||
|
|
||||||
|
var surface = surfaces[type];
|
||||||
|
if (!surface) { continue; } // FIXME: support for unknown event types
|
||||||
|
|
||||||
|
var y = step * estart.idx;
|
||||||
|
// path rectangle for the current event on the relevant surface
|
||||||
|
surface.rect(estart.timestamp + 0.5, y + 0.5, duration || 1, rect_width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add each layer to the main canvas
|
||||||
|
var keys = ['request', /*'func', */'template', 'sql'];
|
||||||
|
for (var j = 0; j < keys.length; ++j) {
|
||||||
|
// stroke and fill all rectangles for the relevant surface/context
|
||||||
|
var ctx = surfaces[keys[j]];
|
||||||
|
ctx.fill();
|
||||||
|
ctx.stroke();
|
||||||
|
to_context.drawImage(ctx.canvas, 0, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Returns first and last events in milliseconds
|
||||||
|
*
|
||||||
|
* @param requests
|
||||||
|
* @returns {{low: number, high: number}}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_get_bounds: function (requests) {
|
||||||
|
var low = +Infinity;
|
||||||
|
var high =-+Infinity;
|
||||||
|
|
||||||
|
for (var i = 0; i < requests.length; i++) {
|
||||||
|
var request = requests[i];
|
||||||
|
for (var j = 0; j < request.length; j++) {
|
||||||
|
var event = request[j];
|
||||||
|
var timestamp = event[3];
|
||||||
|
low = Math.min(low, timestamp);
|
||||||
|
high = Math.max(high, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {low: Math.floor(low * 1e3), high: Math.ceil(high * 1e3)};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var RequestDetails = Widget.extend({
|
||||||
|
events: {
|
||||||
|
click: function () {
|
||||||
|
this._open = !this._open;
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
'mousemove canvas': function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var y = e.y || e.offsetY || e.layerY;
|
||||||
|
if (!y) { return; }
|
||||||
|
var event = this._payloads[Math.floor(y / this._REQ_HEIGHT)];
|
||||||
|
if (!event) { return; }
|
||||||
|
|
||||||
|
this.getParent().tooltip(event.payload, event.start, event.stop, e.clientX, e.clientY);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init: function (parent, request, scale) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
this._request = request;
|
||||||
|
this._open = false;
|
||||||
|
this._scale = scale;
|
||||||
|
this._REQ_HEIGHT = 20;
|
||||||
|
},
|
||||||
|
start: function () {
|
||||||
|
this.el.style.borderBottom = '1px solid black';
|
||||||
|
this.render();
|
||||||
|
return this._super();
|
||||||
|
},
|
||||||
|
render: function () {
|
||||||
|
var request_cell_height = this._REQ_HEIGHT, TITLE_WIDTH = 200;
|
||||||
|
var request = this._request;
|
||||||
|
var req_start = request[0][3] * 1e3;
|
||||||
|
var req_duration = request[request.length - 1][3] * 1e3 - req_start;
|
||||||
|
var height = request_cell_height * (this._open ? request.length / 2 : 1);
|
||||||
|
var cell_center = request_cell_height / 2;
|
||||||
|
var ctx = make_context(210 + Math.ceil(req_duration * this._scale), height, function (ctx) {
|
||||||
|
ctx.lineWidth = cell_center;
|
||||||
|
});
|
||||||
|
this.$el.empty().append(ctx.canvas);
|
||||||
|
var payloads = this._payloads = [];
|
||||||
|
|
||||||
|
// lazy version: if the render is single-line (!this._open), the extra
|
||||||
|
// content will be discarded when the text canvas gets pasted onto the
|
||||||
|
// main canvas. An improvement would be to not do text rendering
|
||||||
|
// beyond the first event for "closed" requests events… then again
|
||||||
|
// that makes for more regular rendering profile?
|
||||||
|
var text_ctx = make_context(TITLE_WIDTH, height, function (ctx) {
|
||||||
|
ctx.font = '12px sans-serif';
|
||||||
|
ctx.textAlign = 'right';
|
||||||
|
ctx.textBaseline = 'middle';
|
||||||
|
ctx.translate(0, cell_center);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(TITLE_WIDTH + 10, ((request_cell_height/4)|0));
|
||||||
|
|
||||||
|
this.getParent()._draw_request(request, ctx, this._open ? request_cell_height : 0, this._scale, function (idx, timestamp, event) {
|
||||||
|
if (/-start$/g.test(event[0])) {
|
||||||
|
payloads.push({
|
||||||
|
payload: event[2],
|
||||||
|
start: timestamp,
|
||||||
|
stop: null
|
||||||
|
});
|
||||||
|
|
||||||
|
// we want ~200px wide, assume the average character is at
|
||||||
|
// least 4px wide => there can be *at most* 49 characters
|
||||||
|
var title = event[2];
|
||||||
|
title = title.replace(/\s+$/, '');
|
||||||
|
title = title.length <= 50 ? title : ('…' + title.slice(-49));
|
||||||
|
while (text_ctx.measureText(title).width > 200) {
|
||||||
|
title = '…' + title.slice(2);
|
||||||
|
}
|
||||||
|
text_ctx.fillText(title, TITLE_WIDTH, request_cell_height * idx);
|
||||||
|
} else if (/-end$/g.test(event[0])) {
|
||||||
|
payloads[idx].stop = timestamp;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ctx.restore();
|
||||||
|
// add the text layer to the main canvas
|
||||||
|
ctx.drawImage(text_ctx.canvas, 0, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (config.isDebug()) {
|
||||||
|
SystrayMenu.Items.push(DebugManager);
|
||||||
|
|
||||||
|
WebClient.include({
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Public
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
current_action_updated: function (action, controller) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
var debugManager = _.find(this.menu.systray_menu.widgets, function(item) {
|
||||||
|
return item instanceof DebugManager;
|
||||||
|
});
|
||||||
|
debugManager.update('action', action, controller && controller.widget);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ActionManager.include({
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Public
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the action of the controller currently opened in a dialog,
|
||||||
|
* i.e. a target='new' action, if any.
|
||||||
|
*
|
||||||
|
* @returns {Object|null}
|
||||||
|
*/
|
||||||
|
getCurrentActionInDialog: function () {
|
||||||
|
if (this.currentDialogController) {
|
||||||
|
return this.actions[this.currentDialogController.actionID];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Returns the controller currently opened in a dialog, if any.
|
||||||
|
*
|
||||||
|
* @returns {Object|null}
|
||||||
|
*/
|
||||||
|
getCurrentControllerInDialog: function () {
|
||||||
|
return this.currentDialogController;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Dialog.include({
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Public
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
open: function() {
|
||||||
|
var self = this;
|
||||||
|
// if the dialog is opened by the ActionManager, instantiate a
|
||||||
|
// DebugManager and insert it into the DOM once the dialog is opened
|
||||||
|
// (delay this with a setTimeout(0) to ensure that the internal
|
||||||
|
// state, i.e. the current action and controller, of the
|
||||||
|
// ActionManager is set to properly update the DebugManager)
|
||||||
|
this.opened(function() {
|
||||||
|
setTimeout(function () {
|
||||||
|
var parent = self.getParent();
|
||||||
|
if (parent instanceof ActionManager) {
|
||||||
|
var action = parent.getCurrentActionInDialog();
|
||||||
|
if (action) {
|
||||||
|
var controller = parent.getCurrentControllerInDialog();
|
||||||
|
self.debugManager = new DebugManager(self);
|
||||||
|
var $header = self.$modal.find('.modal-header:first');
|
||||||
|
return self.debugManager.prependTo($header).then(function () {
|
||||||
|
self.debugManager.update('action', action, controller.widget);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return DebugManager;
|
||||||
|
|
||||||
|
});
|
||||||
@@ -235,7 +235,7 @@ var BasicRenderer = AbstractRenderer.extend({
|
|||||||
$node.tooltip({
|
$node.tooltip({
|
||||||
title: function () {
|
title: function () {
|
||||||
return qweb.render('WidgetLabel.tooltip', {
|
return qweb.render('WidgetLabel.tooltip', {
|
||||||
debug: config.debug,
|
debug: config.isDebug(),
|
||||||
widget: widget,
|
widget: widget,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ return AbstractRenderer.extend({
|
|||||||
this.color_map = {};
|
this.color_map = {};
|
||||||
|
|
||||||
if (params.eventTemplate) {
|
if (params.eventTemplate) {
|
||||||
this.qweb = new QWeb(session.debug, {_s: session.origin});
|
this.qweb = new QWeb(config.isDebug(), {_s: session.origin});
|
||||||
this.qweb.add_template(utils.json_node_to_xml(params.eventTemplate));
|
this.qweb.add_template(utils.json_node_to_xml(params.eventTemplate));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -310,7 +310,7 @@ var FormRenderer = BasicRenderer.extend({
|
|||||||
$button.tooltip({
|
$button.tooltip({
|
||||||
title: function () {
|
title: function () {
|
||||||
return qweb.render('WidgetButton.tooltip', {
|
return qweb.render('WidgetButton.tooltip', {
|
||||||
debug: config.debug,
|
debug: config.isDebug(),
|
||||||
state: self.state,
|
state: self.state,
|
||||||
node: node,
|
node: node,
|
||||||
});
|
});
|
||||||
@@ -491,7 +491,7 @@ var FormRenderer = BasicRenderer.extend({
|
|||||||
this._registerModifiers(node, this.state, $button);
|
this._registerModifiers(node, this.state, $button);
|
||||||
|
|
||||||
// Display tooltip
|
// Display tooltip
|
||||||
if (config.debug || node.attrs.help) {
|
if (config.isDebug() || node.attrs.help) {
|
||||||
this._addButtonTooltip(node, $button);
|
this._addButtonTooltip(node, $button);
|
||||||
}
|
}
|
||||||
return $button;
|
return $button;
|
||||||
@@ -727,7 +727,7 @@ var FormRenderer = BasicRenderer.extend({
|
|||||||
this._registerModifiers(node, this.state, $button);
|
this._registerModifiers(node, this.state, $button);
|
||||||
|
|
||||||
// Display tooltip
|
// Display tooltip
|
||||||
if (config.debug || node.attrs.help) {
|
if (config.isDebug() || node.attrs.help) {
|
||||||
this._addButtonTooltip(node, $button);
|
this._addButtonTooltip(node, $button);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,7 +998,7 @@ var FormRenderer = BasicRenderer.extend({
|
|||||||
var $widgets = self.$('.o_field_widget[name=' + widget.name + ']');
|
var $widgets = self.$('.o_field_widget[name=' + widget.name + ']');
|
||||||
var $label = idForLabel ? self.$('.o_form_label[for=' + idForLabel + ']') : $();
|
var $label = idForLabel ? self.$('.o_form_label[for=' + idForLabel + ']') : $();
|
||||||
$label = $label.eq($widgets.index(widget.$el));
|
$label = $label.eq($widgets.index(widget.$el));
|
||||||
if (config.debug || widget.attrs.help || widget.field.help) {
|
if (config.isDebug() || widget.attrs.help || widget.field.help) {
|
||||||
self._addFieldTooltip(widget, $label);
|
self._addFieldTooltip(widget, $label);
|
||||||
}
|
}
|
||||||
if (widget.attrs.widget === 'upgrade_boolean') {
|
if (widget.attrs.widget === 'upgrade_boolean') {
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ var KanbanRecord = Widget.extend({
|
|||||||
if (Widget) {
|
if (Widget) {
|
||||||
widget = self._processWidget($field, field_name, Widget);
|
widget = self._processWidget($field, field_name, Widget);
|
||||||
self.subWidgets[field_name] = widget;
|
self.subWidgets[field_name] = widget;
|
||||||
} else if (config.debug) {
|
} else if (config.isDebug()) {
|
||||||
// the widget is not implemented
|
// the widget is not implemented
|
||||||
$field.replaceWith($('<span>', {
|
$field.replaceWith($('<span>', {
|
||||||
text: _.str.sprintf(_t('[No widget %s]'), field_widget),
|
text: _.str.sprintf(_t('[No widget %s]'), field_widget),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ odoo.define('web.KanbanRenderer', function (require) {
|
|||||||
|
|
||||||
var BasicRenderer = require('web.BasicRenderer');
|
var BasicRenderer = require('web.BasicRenderer');
|
||||||
var ColumnQuickCreate = require('web.kanban_column_quick_create');
|
var ColumnQuickCreate = require('web.kanban_column_quick_create');
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var KanbanColumn = require('web.KanbanColumn');
|
var KanbanColumn = require('web.KanbanColumn');
|
||||||
var KanbanRecord = require('web.KanbanRecord');
|
var KanbanRecord = require('web.KanbanRecord');
|
||||||
@@ -107,7 +108,7 @@ var KanbanRenderer = BasicRenderer.extend({
|
|||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
|
|
||||||
this.widgets = [];
|
this.widgets = [];
|
||||||
this.qweb = new QWeb(session.debug, {_s: session.origin}, false);
|
this.qweb = new QWeb(config.isDebug(), {_s: session.origin}, false);
|
||||||
var templates = findInNode(this.arch, function (n) { return n.tag === 'templates';});
|
var templates = findInNode(this.arch, function (n) { return n.tag === 'templates';});
|
||||||
transformQwebTemplate(templates, state.fields);
|
transformQwebTemplate(templates, state.fields);
|
||||||
this.qweb.add_template(utils.json_node_to_xml(templates));
|
this.qweb.add_template(utils.json_node_to_xml(templates));
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ var ListRenderer = BasicRenderer.extend({
|
|||||||
|
|
||||||
return _.map(this.columns, function (column) {
|
return _.map(this.columns, function (column) {
|
||||||
var $cell = $('<td>');
|
var $cell = $('<td>');
|
||||||
if (config.debug) {
|
if (config.isDebug()) {
|
||||||
$cell.addClass(column.attrs.name);
|
$cell.addClass(column.attrs.name);
|
||||||
}
|
}
|
||||||
if (column.attrs.name in aggregateValues) {
|
if (column.attrs.name in aggregateValues) {
|
||||||
@@ -742,7 +742,7 @@ var ListRenderer = BasicRenderer.extend({
|
|||||||
$th.css({ textAlign: 'right' });
|
$th.css({ textAlign: 'right' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.debug) {
|
if (config.isDebug()) {
|
||||||
var fieldDescr = {
|
var fieldDescr = {
|
||||||
field: field,
|
field: field,
|
||||||
name: name,
|
name: name,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
odoo.define('web.DataExport', function (require) {
|
odoo.define('web.DataExport', function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var config = require('web.config');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var crash_manager = require('web.crash_manager');
|
var crash_manager = require('web.crash_manager');
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
@@ -240,11 +241,11 @@ var DataExport = Dialog.extend({
|
|||||||
.find('.o_expand_parent')
|
.find('.o_expand_parent')
|
||||||
.toggleClass('fa-chevron-right fa-chevron-down')
|
.toggleClass('fa-chevron-right fa-chevron-down')
|
||||||
.next()
|
.next()
|
||||||
.after(QWeb.render('Export.TreeItems', {fields: records, debug: this.getSession().debug}));
|
.after(QWeb.render('Export.TreeItems', {fields: records, debug: config.isDebug()}));
|
||||||
} else {
|
} else {
|
||||||
this.$('.o_left_field_panel').empty().append(
|
this.$('.o_left_field_panel').empty().append(
|
||||||
$('<div/>').addClass('o_field_tree_structure')
|
$('<div/>').addClass('o_field_tree_structure')
|
||||||
.append(QWeb.render('Export.TreeItems', {fields: records, debug: this.getSession().debug}))
|
.append(QWeb.render('Export.TreeItems', {fields: records, debug: config.isDebug()}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -218,109 +218,6 @@
|
|||||||
</t>
|
</t>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
<t t-name="WebClient.DebugManager">
|
|
||||||
<li class="o_debug_manager" role="menuitem">
|
|
||||||
<a role="button" href="#" title="Open Developer Tools" aria-label="Open Developer Tools" data-toggle="dropdown" aria-expanded="false" tabindex="-1" data-display="static">
|
|
||||||
<span class="fa fa-bug"/>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu dropdown-menu-right o_debug_dropdown" role="menu"/>
|
|
||||||
</li>
|
|
||||||
</t>
|
|
||||||
<t t-name="WebClient.DebugManager.Global">
|
|
||||||
<a role="menuitem" href="#" data-action="perform_js_tests" class="dropdown-item">Run JS Tests</a>
|
|
||||||
<a role="menuitem" href="#" data-action="perform_js_mobile_tests" class="dropdown-item">Run JS Mobile Tests</a>
|
|
||||||
<a role="menuitem" href="#" data-action="perform_click_everywhere_test" class="dropdown-item">Run Click Everywhere Test</a>
|
|
||||||
<a role="menuitem" href="#" data-action="select_view" class="dropdown-item">Open View</a>
|
|
||||||
<t t-if="manager._events">
|
|
||||||
<div class="dropdown-divider" role="separator"/>
|
|
||||||
<a role="menuitem" href="#" data-action="show_timelines" class="dropdown-item">Toggle Timelines</a>
|
|
||||||
<a role="menuitem" href="#" data-action="requests_clear" class="dropdown-item">Clear Events</a>
|
|
||||||
</t>
|
|
||||||
<div class="dropdown-divider o_debug_leave_section" role="separator"/>
|
|
||||||
<a role="menuitem" href="#" data-action="split_assets" class="dropdown-item">Activate Assets Debugging</a>
|
|
||||||
<a role="menuitem" href="#" data-action="regenerateAssets" class="dropdown-item">Regenerate Assets Bundles</a>
|
|
||||||
<a t-if="manager._is_admin" role="menuitem" href="/web/become" class="dropdown-item">Become Superuser</a>
|
|
||||||
<a role="menuitem" href="#" data-action="leave_debug_mode" class="dropdown-item">Leave the Developer Tools</a>
|
|
||||||
</t>
|
|
||||||
<t t-name="WebClient.DebugManager.Action">
|
|
||||||
<t t-if="action">
|
|
||||||
<div class="dropdown-divider" role="separator"/>
|
|
||||||
<a role="menuitem" href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id" class="dropdown-item">Edit Action</a>
|
|
||||||
<t t-if="action.res_model">
|
|
||||||
<a role="menuitem" href="#" data-action="get_view_fields" class="dropdown-item">View Fields</a>
|
|
||||||
<a role="menuitem" href="#" data-action="manage_filters" class="dropdown-item">Manage Filters</a>
|
|
||||||
<a role="menuitem" href="#" data-action="translate" class="dropdown-item">Technical Translation</a>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
<t t-name="WebClient.DebugManager.View">
|
|
||||||
<t t-if="view">
|
|
||||||
<div role="separator" class="dropdown-divider"/>
|
|
||||||
<t t-if="view.type === 'form'">
|
|
||||||
<a role="menuitem" href="#" data-action="set_defaults" class="dropdown-item">Set Defaults</a>
|
|
||||||
<t t-if="controller.getSelectedIds().length === 1">
|
|
||||||
<a role="menuitem" href="#" data-action="get_metadata" class="dropdown-item">View Metadata</a>
|
|
||||||
<a role="menuitem" href="#" data-action="get_attachments" class="dropdown-item">Manage Attachments</a>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
<a role="menuitem" href="#" data-action="fvg" class="dropdown-item">Fields View Get</a>
|
|
||||||
<t t-if="can_edit">
|
|
||||||
<a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id" class="dropdown-item">
|
|
||||||
Edit View: <t t-esc="view.displayName"/>
|
|
||||||
</a>
|
|
||||||
<a t-if="controlPanelView and controlPanelView.$el.is(':visible')" role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.controlPanelFieldsView.view_id" class="dropdown-item">Edit ControlPanelView</a>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
<t t-name="WebClient.DebugViewLog">
|
|
||||||
<table class="table table-sm table-striped">
|
|
||||||
<tr>
|
|
||||||
<th>ID:</th>
|
|
||||||
<td><t t-esc="perm.id"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>XML ID:</th>
|
|
||||||
<td><t t-esc="perm.xmlid or '/'"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>No Update:</th>
|
|
||||||
<td>
|
|
||||||
<t t-esc="perm.noupdate"/>
|
|
||||||
<t t-if="perm.xmlid">
|
|
||||||
<a data-action="toggle_noupdate">(change)</a>
|
|
||||||
</t>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Creation User:</th>
|
|
||||||
<td><t t-esc="perm.creator"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Creation Date:</th>
|
|
||||||
<td><t t-esc="perm.create_date"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Latest Modification by:</th>
|
|
||||||
<td><t t-esc="perm.lastModifiedBy"/></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Latest Modification Date:</th>
|
|
||||||
<td><t t-esc="perm.write_date"/></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</t>
|
|
||||||
<div t-name="WebClient.DebugManager.RequestsOverlay" class="o_debug_manager_overlay">
|
|
||||||
<header>
|
|
||||||
<!-- enough height to display all tracks + 1px spacing between tracks -->
|
|
||||||
<t t-set="canvas_height" t-value="widget.TRACKS * (widget.TRACK_WIDTH + 1)"/>
|
|
||||||
<canvas t-att-height="canvas_height" id="o_debug_requests_summary"/>
|
|
||||||
<!-- transparent overlay to display selected range -->
|
|
||||||
<canvas t-att-height="canvas_height" id="o_debug_requests_selector"/>
|
|
||||||
</header>
|
|
||||||
<div class="o_debug_requests"/>
|
|
||||||
<div class="o_debug_tooltip"/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<t t-name="Sidebar">
|
<t t-name="Sidebar">
|
||||||
<t t-foreach="widget.sections" t-as="section">
|
<t t-foreach="widget.sections" t-as="section">
|
||||||
<div class="btn-group o_dropdown">
|
<div class="btn-group o_dropdown">
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates id="template" xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="WebClient.DebugManager">
|
||||||
|
<li class="o_debug_manager" role="menuitem">
|
||||||
|
<a role="button" href="#" class="o_debug_mode" t-attf-title="Open Developer Tools#{widget.debug_mode_help}"
|
||||||
|
t-att-data-debug-mode="widget.debug_mode" aria-label="Open Developer Tools#{widget.debug_mode_help}"
|
||||||
|
data-toggle="dropdown" aria-expanded="false" tabindex="-1" data-display="static">
|
||||||
|
<span class="fa fa-bug"/>
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-right o_debug_dropdown" role="menu"/>
|
||||||
|
</li>
|
||||||
|
</t>
|
||||||
|
<t t-name="WebClient.DebugManager.Global">
|
||||||
|
<a role="menuitem" href="#" data-action="split_assets" class="dropdown-item o_debug_split_assets">Activate Assets Debugging</a>
|
||||||
|
<a role="menuitem" href="#" data-action="tests_assets" class="dropdown-item">Activate Tests Assets Debugging</a>
|
||||||
|
<a role="menuitem" href="#" data-action="regenerateAssets" class="dropdown-item">Regenerate Assets Bundles</a>
|
||||||
|
<a t-if="manager._is_admin" role="menuitem" href="/web/become" class="dropdown-item">Become Superuser</a>
|
||||||
|
<a role="menuitem" href="#" data-action="leave_debug_mode" class="dropdown-item">Leave the Developer Tools</a>
|
||||||
|
</t>
|
||||||
|
<t t-name="WebClient.DebugManager.Backend">
|
||||||
|
<a role="menuitem" href="#" data-action="perform_js_tests" class="dropdown-item">Run JS Tests</a>
|
||||||
|
<a role="menuitem" href="#" data-action="perform_js_mobile_tests" class="dropdown-item">Run JS Mobile Tests</a>
|
||||||
|
<a role="menuitem" href="#" data-action="perform_click_everywhere_test" class="dropdown-item">Run Click Everywhere Test</a>
|
||||||
|
<a role="menuitem" href="#" data-action="select_view" class="dropdown-item">Open View</a>
|
||||||
|
<t t-if="manager._events">
|
||||||
|
<div class="dropdown-divider" role="separator"/>
|
||||||
|
<a role="menuitem" href="#" data-action="show_timelines" class="dropdown-item">Toggle Timelines</a>
|
||||||
|
<a role="menuitem" href="#" data-action="requests_clear" class="dropdown-item">Clear Events</a>
|
||||||
|
</t>
|
||||||
|
<div class="dropdown-divider o_debug_leave_section" role="separator"/>
|
||||||
|
</t>
|
||||||
|
<t t-name="WebClient.DebugManager.Action">
|
||||||
|
<t t-if="action">
|
||||||
|
<div class="dropdown-divider" role="separator"/>
|
||||||
|
<a role="menuitem" href="#" data-action="edit" t-att-data-model="action.type" t-att-data-id="action.id" class="dropdown-item">Edit Action</a>
|
||||||
|
<t t-if="action.res_model">
|
||||||
|
<a role="menuitem" href="#" data-action="get_view_fields" class="dropdown-item">View Fields</a>
|
||||||
|
<a role="menuitem" href="#" data-action="manage_filters" class="dropdown-item">Manage Filters</a>
|
||||||
|
<a role="menuitem" href="#" data-action="translate" class="dropdown-item">Technical Translation</a>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
<t t-name="WebClient.DebugManager.View">
|
||||||
|
<t t-if="view">
|
||||||
|
<div role="separator" class="dropdown-divider"/>
|
||||||
|
<t t-if="view.type === 'form'">
|
||||||
|
<a role="menuitem" href="#" data-action="set_defaults" class="dropdown-item">Set Defaults</a>
|
||||||
|
<t t-if="controller.getSelectedIds().length === 1">
|
||||||
|
<a role="menuitem" href="#" data-action="get_metadata" class="dropdown-item">View Metadata</a>
|
||||||
|
<a role="menuitem" href="#" data-action="get_attachments" class="dropdown-item">Manage Attachments</a>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
<a role="menuitem" href="#" data-action="fvg" class="dropdown-item">Fields View Get</a>
|
||||||
|
<t t-if="can_edit">
|
||||||
|
<a role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="view.fieldsView.view_id" class="dropdown-item">
|
||||||
|
Edit View: <t t-esc="view.displayName"/>
|
||||||
|
</a>
|
||||||
|
<a t-if="controlPanelView and controlPanelView.$el.is(':visible')" role="menuitem" href="#" data-action="edit" data-model="ir.ui.view" t-att-data-id="action.controlPanelFieldsView.view_id" class="dropdown-item">Edit ControlPanelView</a>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
</t>
|
||||||
|
<t t-name="WebClient.DebugViewLog">
|
||||||
|
<table class="table table-sm table-striped">
|
||||||
|
<tr>
|
||||||
|
<th>ID:</th>
|
||||||
|
<td><t t-esc="perm.id"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>XML ID:</th>
|
||||||
|
<td><t t-esc="perm.xmlid or '/'"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>No Update:</th>
|
||||||
|
<td>
|
||||||
|
<t t-esc="perm.noupdate"/>
|
||||||
|
<t t-if="perm.xmlid">
|
||||||
|
<a data-action="toggle_noupdate">(change)</a>
|
||||||
|
</t>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Creation User:</th>
|
||||||
|
<td><t t-esc="perm.creator"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Creation Date:</th>
|
||||||
|
<td><t t-esc="perm.create_date"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Latest Modification by:</th>
|
||||||
|
<td><t t-esc="perm.lastModifiedBy"/></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Latest Modification Date:</th>
|
||||||
|
<td><t t-esc="perm.write_date"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</t>
|
||||||
|
<div t-name="WebClient.DebugManager.RequestsOverlay" class="o_debug_manager_overlay">
|
||||||
|
<header>
|
||||||
|
<!-- enough height to display all tracks + 1px spacing between tracks -->
|
||||||
|
<t t-set="canvas_height" t-value="widget.TRACKS * (widget.TRACK_WIDTH + 1)"/>
|
||||||
|
<canvas t-att-height="canvas_height" id="o_debug_requests_summary"/>
|
||||||
|
<!-- transparent overlay to display selected range -->
|
||||||
|
<canvas t-att-height="canvas_height" id="o_debug_requests_selector"/>
|
||||||
|
</header>
|
||||||
|
<div class="o_debug_requests"/>
|
||||||
|
<div class="o_debug_tooltip"/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</templates>
|
||||||
@@ -14,7 +14,7 @@ var ActionManager = require('web.ActionManager');
|
|||||||
var config = require('web.config');
|
var config = require('web.config');
|
||||||
var ControlPanelView = require('web.ControlPanelView');
|
var ControlPanelView = require('web.ControlPanelView');
|
||||||
var concurrency = require('web.concurrency');
|
var concurrency = require('web.concurrency');
|
||||||
var DebugManager = require('web.DebugManager');
|
var DebugManager = require('web.DebugManager.Backend');
|
||||||
var dom = require('web.dom');
|
var dom = require('web.dom');
|
||||||
var testUtilsMock = require('web.test_utils_mock');
|
var testUtilsMock = require('web.test_utils_mock');
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ function addMockEnvironment(widget, params) {
|
|||||||
_.extend(config.device, params.config.device);
|
_.extend(config.device, params.config.device);
|
||||||
}
|
}
|
||||||
if ('debug' in params.config) {
|
if ('debug' in params.config) {
|
||||||
config.debug = params.config.debug;
|
odoo.debug = params.config.debug;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ('translateParameters' in params) {
|
if ('translateParameters' in params) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ odoo.define('web.form_tests', function (require) {
|
|||||||
|
|
||||||
var BasicModel = require('web.BasicModel');
|
var BasicModel = require('web.BasicModel');
|
||||||
var concurrency = require('web.concurrency');
|
var concurrency = require('web.concurrency');
|
||||||
var config = require('web.config');
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var fieldRegistry = require('web.field_registry');
|
var fieldRegistry = require('web.field_registry');
|
||||||
var FormView = require('web.FormView');
|
var FormView = require('web.FormView');
|
||||||
@@ -6576,8 +6575,8 @@ QUnit.module('Views', {
|
|||||||
QUnit.test('display tooltips for buttons', async function (assert) {
|
QUnit.test('display tooltips for buttons', async function (assert) {
|
||||||
assert.expect(2);
|
assert.expect(2);
|
||||||
|
|
||||||
var initialDebugMode = config.debug;
|
var initialDebugMode = odoo.debug;
|
||||||
config.debug = true;
|
odoo.debug = true;
|
||||||
|
|
||||||
var form = await createView({
|
var form = await createView({
|
||||||
View: FormView,
|
View: FormView,
|
||||||
@@ -6607,7 +6606,7 @@ QUnit.module('Views', {
|
|||||||
"should have rendered a tooltip");
|
"should have rendered a tooltip");
|
||||||
$secondButton.trigger($.Event('mouseleave'));
|
$secondButton.trigger($.Event('mouseleave'));
|
||||||
|
|
||||||
config.debug = initialDebugMode;
|
odoo.debug = initialDebugMode;
|
||||||
form.destroy();
|
form.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -6936,8 +6935,8 @@ QUnit.module('Views', {
|
|||||||
QUnit.test('proper stringification in debug mode tooltip', async function (assert) {
|
QUnit.test('proper stringification in debug mode tooltip', async function (assert) {
|
||||||
assert.expect(6);
|
assert.expect(6);
|
||||||
|
|
||||||
var initialDebugMode = config.debug;
|
var initialDebugMode = odoo.debug;
|
||||||
config.debug = true;
|
odoo.debug = true;
|
||||||
|
|
||||||
var form = await createView({
|
var form = await createView({
|
||||||
View: FormView,
|
View: FormView,
|
||||||
@@ -6970,7 +6969,7 @@ QUnit.module('Views', {
|
|||||||
assert.strictEqual($('.oe_tooltip_technical>li[data-item="widget"]')[0].lastChild.wholeText.trim(),
|
assert.strictEqual($('.oe_tooltip_technical>li[data-item="widget"]')[0].lastChild.wholeText.trim(),
|
||||||
'Many2one (many2one)', "widget description should be correct");
|
'Many2one (many2one)', "widget description should be correct");
|
||||||
|
|
||||||
config.debug = initialDebugMode;
|
odoo.debug = initialDebugMode;
|
||||||
form.destroy();
|
form.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ odoo.define('web.list_tests', function (require) {
|
|||||||
|
|
||||||
var AbstractStorageService = require('web.AbstractStorageService');
|
var AbstractStorageService = require('web.AbstractStorageService');
|
||||||
var BasicModel = require('web.BasicModel');
|
var BasicModel = require('web.BasicModel');
|
||||||
var config = require('web.config');
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var basicFields = require('web.basic_fields');
|
var basicFields = require('web.basic_fields');
|
||||||
var FormView = require('web.FormView');
|
var FormView = require('web.FormView');
|
||||||
@@ -1793,8 +1792,8 @@ QUnit.module('Views', {
|
|||||||
QUnit.test('display a tooltip on a field', async function (assert) {
|
QUnit.test('display a tooltip on a field', async function (assert) {
|
||||||
assert.expect(4);
|
assert.expect(4);
|
||||||
|
|
||||||
var initialDebugMode = config.debug;
|
var initialDebugMode = odoo.debug;
|
||||||
config.debug = false;
|
odoo.debug = false;
|
||||||
|
|
||||||
var list = await createView({
|
var list = await createView({
|
||||||
View: ListView,
|
View: ListView,
|
||||||
@@ -1813,7 +1812,7 @@ QUnit.module('Views', {
|
|||||||
list.$('th[data-name=foo]').trigger($.Event('mouseenter'));
|
list.$('th[data-name=foo]').trigger($.Event('mouseenter'));
|
||||||
assert.strictEqual($('.tooltip .oe_tooltip_string').length, 0, "should not have rendered a tooltip");
|
assert.strictEqual($('.tooltip .oe_tooltip_string').length, 0, "should not have rendered a tooltip");
|
||||||
|
|
||||||
config.debug = true;
|
odoo.debug = true;
|
||||||
// it is necessary to rerender the list so tooltips can be properly created
|
// it is necessary to rerender the list so tooltips can be properly created
|
||||||
await list.reload();
|
await list.reload();
|
||||||
list.$('th[data-name=foo]').tooltip('show', false);
|
list.$('th[data-name=foo]').tooltip('show', false);
|
||||||
@@ -1828,7 +1827,7 @@ QUnit.module('Views', {
|
|||||||
assert.strictEqual($('.oe_tooltip_technical>li[data-item="widget"]')[0].lastChild.wholeText.trim(),
|
assert.strictEqual($('.oe_tooltip_technical>li[data-item="widget"]')[0].lastChild.wholeText.trim(),
|
||||||
'Button (toggle_button)', "widget description should be correct");
|
'Button (toggle_button)', "widget description should be correct");
|
||||||
|
|
||||||
config.debug = initialDebugMode;
|
odoo.debug = initialDebugMode;
|
||||||
list.destroy();
|
list.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,8 @@
|
|||||||
<script type="text/javascript" src="/web/static/src/js/services/notification_service.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/services/notification_service.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/services/session_storage_service.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/services/session_storage_service.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/web/static/src/js/tools/debug_manager.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/name_and_signature.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/name_and_signature.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/notification.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/notification.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/rainbow_man.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/rainbow_man.js"></script>
|
||||||
@@ -248,8 +250,8 @@
|
|||||||
<script type="text/javascript" src="/web/static/src/js/services/session.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/services/session.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/auto_complete.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/auto_complete.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/change_password.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/change_password.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/tools/debug_manager.js"></script>
|
|
||||||
<script type="text/javascript" src="/web/static/src/js/tools/test_menus_loader.js"/>
|
<script type="text/javascript" src="/web/static/src/js/tools/test_menus_loader.js"/>
|
||||||
|
<script type="text/javascript" src="/web/static/src/js/tools/debug_manager_backend.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/tools/tools.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/tools/tools.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/data_export.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/data_export.js"></script>
|
||||||
<script type="text/javascript" src="/web/static/src/js/widgets/date_picker.js"></script>
|
<script type="text/javascript" src="/web/static/src/js/widgets/date_picker.js"></script>
|
||||||
@@ -387,6 +389,14 @@
|
|||||||
<xpath expr="//t[@t-call='web._assets_frontend_minimal_js']" position="replace"/>
|
<xpath expr="//t[@t-call='web._assets_frontend_minimal_js']" position="replace"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- Do not direcly call this template, call 'conditional_assets_tests' instead -->
|
||||||
|
<template id="assets_tests" name="Tests Assets">
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="conditional_assets_tests" name="Tests Assets Bundle">
|
||||||
|
<t t-call-assets="web.assets_tests" t-if="'tests' in debug" defer_load="True" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<template id="web.layout" name="Web layout"><!DOCTYPE html>
|
<template id="web.layout" name="Web layout"><!DOCTYPE html>
|
||||||
<html t-att="html_data or {}">
|
<html t-att="html_data or {}">
|
||||||
<head>
|
<head>
|
||||||
@@ -400,6 +410,7 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var odoo = {
|
var odoo = {
|
||||||
csrf_token: "<t t-esc="request.csrf_token(None)"/>",
|
csrf_token: "<t t-esc="request.csrf_token(None)"/>",
|
||||||
|
debug: "<t t-esc="debug"/>",
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -422,6 +433,7 @@
|
|||||||
</script>
|
</script>
|
||||||
<t t-call-assets="web.assets_common_minimal_js" t-css="false" defer_load="True"/>
|
<t t-call-assets="web.assets_common_minimal_js" t-css="false" defer_load="True"/>
|
||||||
<t t-call-assets="web.assets_frontend_minimal_js" t-css="false" defer_load="True"/>
|
<t t-call-assets="web.assets_frontend_minimal_js" t-css="false" defer_load="True"/>
|
||||||
|
<t t-call="web.conditional_assets_tests"/>
|
||||||
<t t-call-assets="web.assets_common_lazy" t-css="false" lazy_load="True"/>
|
<t t-call-assets="web.assets_common_lazy" t-css="false" lazy_load="True"/>
|
||||||
<t t-call-assets="web.assets_frontend_lazy" t-css="false" lazy_load="True"/>
|
<t t-call-assets="web.assets_frontend_lazy" t-css="false" lazy_load="True"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
@@ -441,6 +453,7 @@
|
|||||||
<div class="container py-3">
|
<div class="container py-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm text-center text-sm-left text-muted">
|
<div class="col-sm text-center text-sm-left text-muted">
|
||||||
|
<t t-call="web.debug_icon"/>
|
||||||
<span>Copyright &copy;</span> <span t-field="res_company.name" itemprop="name">Company name</span>
|
<span>Copyright &copy;</span> <span t-field="res_company.name" itemprop="name">Company name</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm text-center text-sm-right">
|
<div class="col-sm text-center text-sm-right">
|
||||||
@@ -488,7 +501,7 @@
|
|||||||
|
|
||||||
<template id="web.login" name="Login">
|
<template id="web.login" name="Login">
|
||||||
<t t-call="web.login_layout">
|
<t t-call="web.login_layout">
|
||||||
<form class="oe_login_form" role="form" t-attf-action="/web/login{{ '?debug' if debug else '' }}" method="post" onsubmit="this.action = this.action + location.hash">
|
<form class="oe_login_form" role="form" t-attf-action="/web/login" method="post" onsubmit="this.action = this.action + location.hash">
|
||||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||||
|
|
||||||
<div class="form-group field-db" t-if="databases and len(databases) > 1">
|
<div class="form-group field-db" t-if="databases and len(databases) > 1">
|
||||||
@@ -840,6 +853,7 @@
|
|||||||
<t t-call-assets="web.assets_backend" t-js="false"/>
|
<t t-call-assets="web.assets_backend" t-js="false"/>
|
||||||
<t t-call-assets="web.assets_common" t-css="false"/>
|
<t t-call-assets="web.assets_common" t-css="false"/>
|
||||||
<t t-call-assets="web.assets_backend" t-css="false"/>
|
<t t-call-assets="web.assets_backend" t-css="false"/>
|
||||||
|
<t t-call="web.conditional_assets_tests"/>
|
||||||
|
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
@@ -864,6 +878,14 @@
|
|||||||
</t>
|
</t>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<template id="debug_icon" name="Debug Icon">
|
||||||
|
<t t-if="debug">
|
||||||
|
<t t-set="debug_mode_help" t-value="' (%s)' % debug if debug != '1' else ''"/>
|
||||||
|
<a t-attf-href="?#{keep_query('*', debug='')}" t-attf-title="Debug mode is activated#{debug_mode_help}. Click here to exit debug mode."
|
||||||
|
class="o_debug_mode"><span class="fa fa-bug"/></a>
|
||||||
|
</t>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Optional Bundle for PDFJS lib
|
Optional Bundle for PDFJS lib
|
||||||
Since PDFJS is quite huge (40000 lines), please only load it when it is necessary.
|
Since PDFJS is quite huge (40000 lines), please only load it when it is necessary.
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ odoo.define('web_editor.ace', function (require) {
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var ajax = require('web.ajax');
|
var ajax = require('web.ajax');
|
||||||
|
var config = require('web.config');
|
||||||
var concurrency = require('web.concurrency');
|
var concurrency = require('web.concurrency');
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
var localStorage = require('web.local_storage');
|
var localStorage = require('web.local_storage');
|
||||||
var session = require('web.session');
|
|
||||||
|
|
||||||
var _t = core._t;
|
var _t = core._t;
|
||||||
|
|
||||||
@@ -716,8 +716,8 @@ var ViewEditor = Widget.extend({
|
|||||||
_.each(this.$lists, function ($list, _type) { $list.toggleClass('d-none', type !== _type); });
|
_.each(this.$lists, function ($list, _type) { $list.toggleClass('d-none', type !== _type); });
|
||||||
this.$lists[type].change();
|
this.$lists[type].change();
|
||||||
|
|
||||||
this.$includeBundlesArea.toggleClass('d-none', this.currentType !== 'xml' || !session.debug);
|
this.$includeBundlesArea.toggleClass('d-none', this.currentType !== 'xml' || !config.isDebug());
|
||||||
this.$includeAllSCSSArea.toggleClass('d-none', this.currentType !== 'scss' || !session.debug);
|
this.$includeAllSCSSArea.toggleClass('d-none', this.currentType !== 'scss' || !config.isDebug());
|
||||||
this.$includeAllSCSSArea.find('[data-value="restricted"]').toggleClass('d-none', this.options.defaultBundlesRestriction.length === 0);
|
this.$includeAllSCSSArea.find('[data-value="restricted"]').toggleClass('d-none', this.options.defaultBundlesRestriction.length === 0);
|
||||||
this.$formatButton.toggleClass('d-none', this.currentType !== 'xml');
|
this.$formatButton.toggleClass('d-none', this.currentType !== 'xml');
|
||||||
},
|
},
|
||||||
@@ -824,7 +824,7 @@ var ViewEditor = Widget.extend({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSelected && session.debug && $elem.data('debug')) {
|
if (!isSelected && config.isDebug() && $elem.data('debug')) {
|
||||||
$div.append($('<span/>', {
|
$div.append($('<span/>', {
|
||||||
text: ' (' + $elem.data('debug') + ')',
|
text: ' (' + $elem.data('debug') + ')',
|
||||||
class: 'ml4 small text-muted',
|
class: 'ml4 small text-muted',
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ var Wysiwyg = Widget.extend({
|
|||||||
wysiwyg_blur: '_onWysiwygBlur',
|
wysiwyg_blur: '_onWysiwygBlur',
|
||||||
},
|
},
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
codeview: config.debug,
|
codeview: config.isDebug(),
|
||||||
recordInfo: {
|
recordInfo: {
|
||||||
context: {},
|
context: {},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class WebSettingsDashboard(http.Controller):
|
|||||||
'share': {
|
'share': {
|
||||||
'server_version': release.version,
|
'server_version': release.version,
|
||||||
'expiration_date': expiration_date,
|
'expiration_date': expiration_date,
|
||||||
'debug': request.debug,
|
'debug': request.session.debug,
|
||||||
'demo_active': demo_active,
|
'demo_active': demo_active,
|
||||||
},
|
},
|
||||||
'company': {
|
'company': {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ odoo.define('web_settings_dashboard', function (require) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var AbstractAction = require('web.AbstractAction');
|
var AbstractAction = require('web.AbstractAction');
|
||||||
var config = require('web.config');
|
|
||||||
var core = require('web.core');
|
var core = require('web.core');
|
||||||
var framework = require('web.framework');
|
var framework = require('web.framework');
|
||||||
var Widget = require('web.Widget');
|
var Widget = require('web.Widget');
|
||||||
@@ -349,7 +348,6 @@ var DashboardShare = Widget.extend({
|
|||||||
_onClickForceDemo: function (ev) {
|
_onClickForceDemo: function (ev) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this.do_action('base.demo_force_install_action');
|
this.do_action('base.demo_force_install_action');
|
||||||
config.debug = false;
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -123,13 +123,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<a t-if="debug != true" class="oe_activate_debug_mode float-right" href="?debug" >Activate the developer mode</a>
|
<div class="text-right">
|
||||||
<br t-if="debug != true"/>
|
<a t-if="debug.indexOf('1') == -1" class="d-block" href="?debug=1">Activate the developer mode</a>
|
||||||
<a t-if="debug != 'assets'" class="oe_activate_debug_mode float-right" href="?debug=assets" >Activate the developer mode (with assets)</a>
|
<a t-if="debug.indexOf('assets') == -1" class="d-block" href="?debug=assets">Activate the developer mode (with assets)</a>
|
||||||
<br t-if="debug != 'assets'"/>
|
<a t-if="debug.indexOf('tests') == -1" class="d-block" href="?debug=assets,tests">Activate the developer mode (with tests assets)</a>
|
||||||
<a t-if="debug != false" class="oe_activate_debug_mode float-right" href="/web" >Deactivate the developer mode</a>
|
<a t-if="debug" class="d-block" href="?debug=">Deactivate the developer mode</a>
|
||||||
<br t-if="debug != false"/>
|
<a t-if="debug and !demo_active" class="o_web_settings_dashboard_force_demo" href="#">Load demo data</a>
|
||||||
<a t-if="(debug) and !(demo_active)" class="oe_activate_debug_mode float-right o_web_settings_dashboard_force_demo" href="#">Load demo data</a>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
odoo.define('web_tour.DebugManager', function (require) {
|
odoo.define('web_tour.DebugManager.Backend', function (require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var core = require("web.core");
|
var core = require("web.core");
|
||||||
var DebugManager = require('web.DebugManager');
|
var DebugManager = require('web.DebugManager.Backend');
|
||||||
var Dialog = require("web.Dialog");
|
var Dialog = require("web.Dialog");
|
||||||
|
|
||||||
var tour = require('web_tour.tour');
|
var tour = require('web_tour.tour');
|
||||||
|
|||||||
@@ -163,8 +163,7 @@ return core.Class.extend(mixins.EventDispatcherMixin, ServicesMixin, {
|
|||||||
this.update();
|
this.update();
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
|
|
||||||
var url = session.debug ? $.param.querystring(tour.url, {debug: session.debug}) : tour.url;
|
window.location.href = window.location.origin + tour.url;
|
||||||
window.location.href = window.location.origin + url;
|
|
||||||
} else {
|
} else {
|
||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<templates id="template" xml:space="preserve">
|
<templates id="template" xml:space="preserve">
|
||||||
|
|
||||||
<t t-extend="WebClient.DebugManager.Global">
|
<t t-extend="WebClient.DebugManager.Backend">
|
||||||
<t t-jquery="a[data-action='select_view']" t-operation="after">
|
<t t-jquery="a[data-action='select_view']" t-operation="after">
|
||||||
<t t-if="manager._is_admin">
|
<t t-if="manager._is_admin">
|
||||||
<a t-if="manager.consume_tours_enabled" href="#" class="dropdown-item" data-action="consume_tours">Disable Tours</a>
|
<a t-if="manager.consume_tours_enabled" href="#" class="dropdown-item" data-action="consume_tours">Disable Tours</a>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class QWeb(models.AbstractModel):
|
|||||||
atts = super(QWeb, self)._post_processing_att(tagName, atts, options)
|
atts = super(QWeb, self)._post_processing_att(tagName, atts, options)
|
||||||
|
|
||||||
if options.get('inherit_branding') or options.get('rendering_bundle') or \
|
if options.get('inherit_branding') or options.get('rendering_bundle') or \
|
||||||
options.get('edit_translations') or options.get('debug') or (request and request.debug):
|
options.get('edit_translations') or options.get('debug') or (request and request.session.debug):
|
||||||
return atts
|
return atts
|
||||||
|
|
||||||
website = request and getattr(request, 'website', None)
|
website = request and getattr(request, 'website', None)
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
odoo.define('website.debugManager', function (require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var config = require('web.config');
|
||||||
|
var DebugManager = require('web.DebugManager');
|
||||||
|
var websiteNavbarData = require('website.navbar');
|
||||||
|
|
||||||
|
var DebugManagerMenu = websiteNavbarData.WebsiteNavbar.include({
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
start: function () {
|
||||||
|
if (config.isDebug()) {
|
||||||
|
new DebugManager(this).prependTo(this.$('.o_menu_systray'));
|
||||||
|
}
|
||||||
|
return this._super.apply(this, arguments);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return DebugManagerMenu;
|
||||||
|
});
|
||||||
@@ -592,7 +592,7 @@ var ThemeCustomizeDialog = Dialog.extend({
|
|||||||
var $loading = $('<i/>', {class: 'fa fa-refresh fa-spin'});
|
var $loading = $('<i/>', {class: 'fa fa-refresh fa-spin'});
|
||||||
this.$modal.find('.modal-title').append($loading);
|
this.$modal.find('.modal-title').append($loading);
|
||||||
|
|
||||||
if (reload || config.debug === 'assets') {
|
if (reload || config.isDebug('assets')) {
|
||||||
window.location.href = $.param.querystring('/website/theme_customize_reload', {
|
window.location.href = $.param.querystring('/website/theme_customize_reload', {
|
||||||
href: window.location.href,
|
href: window.location.href,
|
||||||
enable: (enable || []).join(','),
|
enable: (enable || []).join(','),
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user