fields
forms
Profiling Qweb View
Odoo 19 fields — Profiling Qweb View (webclient)
Live preview
Interactive
Source excerpt
web/static/src/webclient/debug/profiling/profiling_qweb.js
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { loadBundle } from "@web/core/assets";
import { renderToString } from "@web/core/utils/render";
import { useDebounced } from "@web/core/utils/timing";
import { standardFieldProps } from "@web/views/fields/standard_field_props";
import { Component, useState, useRef, onWillStart, onMounted, onWillUnmount } from "@odoo/owl";
class MenuItem extends Component {
static template = "web.ProfilingQwebView.menuitem";
static props = {
view: Object,
};
}
function processValue(value) {
const data = JSON.parse(value);
for (const line of data[0].results.data) {
line.xpath = line.xpath.replace(/([^\]])\//g, "$1[1]/").replace(/([^\]])$/g, "$1[1]");
}
return data;
}
/**
* This widget is intended to be used on Text fields. It will provide Ace Editor
* for display XML and Python profiling.
*/
export class ProfilingQwebView extends Component {
static template = "web.ProfilingQwebView";
static components = { MenuItem };
static props = { ...standardFieldProps };
setup() {
super.setup();
this.orm = useService("orm");
this.ace = useRef("ace");
this.selector = useRef("selector");
this.value = processValue(this.props.record.data[this.props.name]);
this.state = useState({
viewID: this.profile.data.length ? this.profile.data[0].view_id : 0,
view: null,
});
this.renderProfilingInformation = useDebounced(this.renderProfilingInformation, 100);
onWillStart(async () => {
await loadBundle("web.ace_lib");
await this._fetchViewData();
this.state.view = this.viewObjects.find((view) => view.id === this.state.viewID);
});
onMounted(() => {
this._startAce(this.ace.el);
this._renderView();
});
onWillUnmount(() => {
if (this.aceEditor) {
this.aceEditor.destroy();
}
this._unmoutInfo();
});
}
/**
* Return JSON values to render the view
*
* @returns {archs, data: {template, xpath, directive, time, duration, query }[]}
*/
get profile() {
return this.value ? this.value[0].results : { archs: {}, data: [] };
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* Return association of view key, view name, query number and total delay
*
* @private
* @returns {Promise<viewObjects>}
*/
async _fetchViewData() {
const viewIDs = Array.from(new Set(this.profile.data.map((line) => line.view_id)));
const viewObjects = await this.orm.call("ir.ui.view", "search_read", [], {
fields: ["id", "display_name", "key"],
domain: [["id", "in", viewIDs]],
});
for (const view of viewObjects) {
view.delay = 0;
view.query = 0;
const lines = this.profile.data.filter((l) => l.view_id === view.id);
const root = lines.find((l) => l.xpath === "");
if (root) {
view.delay += root.delay;
view.query += root.query;
} else {
view.delay = lines.map((l) => l.delay).reduce((a, b) => a + b);
view.query = lines.map((l) => l.query).reduce((a, b) => a + b);
}
view.delay = Math.ceil(view.delay * 10) / 10;
}
this.viewObjects = viewObjects;
}
/**
* Format delay to readable.
*
* @private
* @param {number} delay
* @returns {string}
*/
_formatDelay(delay) {
return delay ? (Math.ceil(delay * 10) / 10).toFixed(1) : ".";
}
/**
* Starts the ace library on the given DOM element. This initializes the
Registry / API
- Registry name
profiling_qweb_view- Category
fields- Module
web- Slug
profiling-qweb-view- Nav group
forms