[FIX] web: adapt debug manager profiling

This commit applies [1] in the wowl branch, since [1] has been
developped in parallel of the conversion of the webclient in owl.

Note that the former implementation is still temporarily used on
the website, as it still uses the legacy DebugManager.

[1] 4c4a740e0a

closes odoo-dev/odoo#930

Signed-off-by: Géry Debongnie (ged) <ged@openerp.com>
This commit is contained in:
Aaron Bohy
2021-06-18 21:31:31 +02:00
parent 774ca5571a
commit b86a26f892
11 changed files with 264 additions and 29 deletions
-1
View File
@@ -61,7 +61,6 @@ This module provides the core of the Odoo Web Client.
'web.assets_common': [
('include', 'web._assets_helpers'),
'web/static/src/scss/debug_profiling.scss',
'web/static/lib/bootstrap/scss/_variables.scss',
('include', 'web._assets_common_styles'),
@@ -64,7 +64,10 @@ export class DebugMenu extends Component {
}
onDropdownItemSelected(ev) {
ev.detail.payload.callback();
// items of type "component" don't necessarily have a payload/callback
if (ev.detail.payload && ev.detail.payload.callback) {
ev.detail.payload.callback();
}
}
onClickOnTagA(ev) {
@@ -17,6 +17,7 @@
</DropdownItem>
</t>
<div t-if="element.type == 'separator'" role="separator" class="dropdown-divider"/>
<t t-if="element.type == 'component'" t-component="element.Component" t-props="element.props"/>
</t>
</t>
</t>
@@ -103,7 +103,6 @@ function becomeSuperuser({ env }) {
hide: !env.services.user.isAdmin,
href: becomeSuperuserULR,
callback: () => {
//TODO add /web/become
browser.open(becomeSuperuserULR, "_self");
},
sequence: 440,
@@ -0,0 +1,24 @@
/** @odoo-module **/
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useBus } from "@web/core/bus_hook";
import { useService } from "@web/core/service_hook";
const { Component } = owl;
export class ProfilingItem extends Component {
setup() {
this.profiling = useService("profiling");
this.actionService = useService("action");
useBus(this.props.bus, "UPDATE", this.render);
}
changeParam(param, ev) {
this.profiling.setParam(param, ev.target.value);
}
openProfiles() {
this.actionService.doAction("base.action_menu_ir_profile");
}
}
ProfilingItem.components = { DropdownItem };
ProfilingItem.template = "web.DebugMenu.ProfilingItem";
@@ -0,0 +1,25 @@
.o_debug_profiling_item {
.o_profiling_switch {
padding-top: 3px;
padding-bottom: 3px;
.custom-switch {
display: inline-block;
}
.custom-control-label {
cursor: pointer;
}
.o_open_profiling {
padding-top: 3px;
}
}
}
.o_debug_manager .fa-bug {
position: relative;
.o_recording {
position: absolute;
bottom: -0.1em;
right: -0.4em;
font-size: 0.8em;
}
}
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="web.DebugMenu.ProfilingItem" owl="1">
<DropdownItem class="o_debug_profiling_item" payload="{}">
<span class="o_profiling_switch">
<span class="custom-control custom-switch" t-on-click.stop.prevent="profiling.toggleProfiling()">
<input type="checkbox" class="custom-control-input" id="enable_profiling" t-att-checked="profiling.state.isEnabled"/>
<label class="custom-control-label">
Enable profiling
<span t-if="profiling.state.isEnabled" class="profiling_items text-danger fa fa-circle"></span>
</label>
</span>
<i class="o_open_profiling float-right fa fa-list fa-lg" t-on-click="openProfiles"/>
</span>
<t t-if="profiling.state.isEnabled">
<span class="o_profiling_switch custom-control custom-switch" t-on-click.stop.prevent="profiling.toggleCollector('sql')">
<input type="checkbox" class="custom-control-input" id="profile_sql"
t-att-checked="profiling.isCollectorEnabled('sql')"/>
<label class="custom-control-label" for="profile_sql">Record sql</label>
</span>
<span t-if="profiling.state.isEnabled" class="o_profiling_switch custom-control custom-switch" t-on-click.stop.prevent="profiling.toggleCollector('traces_async')">
<input type="checkbox" class="custom-control-input" id="profile_traces_async"
t-att-checked="profiling.isCollectorEnabled('traces_async')"/>
<label class="custom-control-label" for="profile_traces_async">Record traces</label>
</span>
<div t-if="profiling.isCollectorEnabled('traces_async')" class="input-group input-group-sm" t-on-click.stop.prevent="">
<div class="input-group-prepend">
<div class="input-group-text">Interval</div>
</div>
<select class="profile_param form-control" t-on-change="changeParam('traces_async_interval')">
<t t-set="interval" t-value="profiling.state.params.traces_async_interval"/>
<option value="">Default</option>
<option value="0.001" t-att-selected="interval === '0.001'">0.001</option>
<option value="0.01" t-att-selected="interval === '0.01'">0.01</option>
<option value="0.1" t-att-selected="interval === '0.1'">0.1</option>
<option value="1" t-att-selected="interval === '1'">1</option>
</select>
</div>
</t>
</DropdownItem>
</t>
</templates>
@@ -0,0 +1,104 @@
/** @odoo-module **/
import { registry } from "@web/core/registry";
import { ProfilingItem } from "./profiling_item";
const { core } = owl;
const profilingService = {
dependencies: ["orm"],
start(env, { orm }) {
const sessionInfo = odoo.session_info;
const state = {
session: sessionInfo.profile_session || false,
collectors: sessionInfo.profile_collectors || ["sql", "traces_async"],
params: sessionInfo.profile_params || {},
get isEnabled() {
return Boolean(state.session);
},
};
const bus = new core.EventBus();
let recordingIcon = null;
function updateDebugIcon() {
const debugItem = document.querySelector(".o_main_navbar .o_debug_manager .fa-bug");
if (state.isEnabled) {
recordingIcon = document.createElement("span");
recordingIcon.classList.add("o_recording", "text-danger", "fa", "fa-circle");
debugItem.appendChild(recordingIcon);
} else if (recordingIcon) {
debugItem.removeChild(recordingIcon);
recordingIcon = null;
}
}
if (env.debug) {
env.bus.on("WEB_CLIENT_READY", null, updateDebugIcon);
}
async function setProfiling(params) {
const kwargs = Object.assign(
{
collectors: state.collectors,
params: state.params,
profile: state.isEnabled,
},
params
);
const resp = await orm.call("ir.profile", "set_profiling", [], kwargs);
state.session = resp.session;
state.collectors = resp.collectors;
state.params = resp.params;
bus.trigger("UPDATE");
updateDebugIcon();
}
function profilingSeparator() {
return {
type: "separator",
sequence: 500,
};
}
function profilingItem() {
return {
type: "component",
Component: ProfilingItem,
props: { bus },
sequence: 510,
};
}
registry
.category("debug")
.add("profilingSeparator", profilingSeparator)
.add("profilingItem", profilingItem);
return {
state,
async toggleProfiling() {
await setProfiling({ profile: !state.isEnabled });
},
async toggleCollector(collector) {
let nextCollectors = state.collectors.slice();
const index = nextCollectors.indexOf(collector);
if (index >= 0) {
nextCollectors.splice(index, 1);
} else {
nextCollectors.push(collector);
}
await setProfiling({ collectors: nextCollectors });
},
async setParam(key, value) {
const nextParams = Object.assign({}, state.params);
nextParams[key] = value;
await setProfiling({ params: nextParams });
},
isCollectorEnabled(collector) {
return state.collectors.includes(collector);
},
};
},
};
registry.category("services").add("profiling", profilingService);
+17 -24
View File
@@ -401,9 +401,7 @@ export function editView({ accessRights, action, component, env }) {
return null;
}
const { viewId, viewType } = component.widget;
const displayName = action.views
.find((v) => v.type === viewType)
.name.toString();
const displayName = action.views.find((v) => v.type === viewType).name.toString();
const description = env._t("Edit View: ") + displayName;
return {
type: "item",
@@ -424,12 +422,7 @@ function editControlPanelView({ accessRights, component, env }) {
type: "item",
description,
callback: () => {
editModelDebug(
env,
description,
"ir.ui.view",
component.props.viewInfo.view_id
);
editModelDebug(env, description, "ir.ui.view", component.props.viewInfo.view_id);
},
sequence: 360,
};
@@ -506,24 +499,24 @@ const debugRegistry = registry.category("debug");
debugRegistry
.category("action")
.add("actionSeparator", actionSeparator)
.add("editAction", editAction)
.add("viewFields", viewFields)
.add("manageFilters", manageFilters)
.add("technicalTranslation", technicalTranslation)
.add("accessSeparator", accessSeparator)
.add("viewAccessRights", viewAccessRights)
.add("viewRecordRules", viewRecordRules)
.add("actionSeparator", actionSeparator)
.add("editAction", editAction)
.add("viewFields", viewFields)
.add("manageFilters", manageFilters)
.add("technicalTranslation", technicalTranslation)
.add("accessSeparator", accessSeparator)
.add("viewAccessRights", viewAccessRights)
.add("viewRecordRules", viewRecordRules);
debugRegistry
.category("view")
.add("viewSeparator", viewSeparator)
.add("fieldsViewGet", fieldsViewGet)
.add("editView", editView)
.add("editControlPanelView", editControlPanelView)
.add("viewSeparator", viewSeparator)
.add("fieldsViewGet", fieldsViewGet)
.add("editView", editView)
.add("editControlPanelView", editControlPanelView);
debugRegistry
.category("form")
.add("setDefaults", setDefaults)
.add("viewMetadata", viewMetadata)
.add("manageAttachments", manageAttachments);
.add("setDefaults", setDefaults)
.add("viewMetadata", viewMetadata)
.add("manageAttachments", manageAttachments);
@@ -9,7 +9,9 @@
t-att-aria-label="_devtool_button_title + widget.debug_mode_help"
t-att-data-debug-mode="widget.debug_mode"
data-toggle="dropdown" aria-expanded="false" tabindex="-1" data-display="static">
<span class="fa fa-bug"/>
<span class="fa fa-bug">
<span class="profiling_items text-danger fa fa-circle"></span>
</span>
</a>
<div class="dropdown-menu dropdown-menu-right o_debug_dropdown" role="menu"/>
</li>
@@ -20,6 +22,48 @@
<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>
<div class="dropdown-divider" role="separator"/>
<span role="menuitem" class="dropdown-item profiling">
<span class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="enable_profiling"/>
<label class="custom-control-label" for="enable_profiling">
Enable profiling
<span class="profiling_items text-danger fa fa-circle"></span>
</label>
<i id="open_profiling_button" class="open_profiling float-right fa fa-list fa-lg"></i>
</span>
</span>
<span class="profiling_items">
<span role="menuitem" class="dropdown-item profiling">
<span class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input profile_switch" id="profile_sql"/>
<label class="custom-control-label" for="profile_sql">Record sql</label>
</span>
</span>
<span role="menuitem" class="dropdown-item profiling">
<span class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input profile_switch" id="profile_traces_async"/>
<label class="custom-control-label" for="profile_traces_async">Record traces</label>
</span>
</span>
<span role="menuitem" class="dropdown-item profiling profile_traces_async">
<span class="">
<div class="input-group input-group-sm">
<div class="input-group-prepend">
<div class="input-group-text">Interval</div>
</div>
<select id="profile_traces_async_interval" class="profile_param form-control">
<option value="">Default</option>
<option value="0.001">0.001</option>
<option value="0.01">0.01</option>
<option value="0.1">0.1</option>
<option value="1">1</option>
</select>
<!--input type="number" step="any" min="0.001" max="10" value="0.001" /-->
</div>
</span>
</span>
</span>
</t>
</templates>
@@ -1,4 +1,3 @@
.o_debug_mode .fa { /* Active profiling red dot should be overed on the bottom right corner of the bug icon*/
position: relative;
.fa {