[REF] web: debug manager

We refactor some items in the debug registry. In particular, we want to
make them usable in the legacy and new contexts.

Part-of: odoo/odoo#73311
This commit is contained in:
Mathieu Duckerts-Antoine
2021-09-07 10:04:33 +00:00
committed by Aaron Bohy
parent c67b9f9907
commit e0294887ec
9 changed files with 327 additions and 295 deletions
@@ -1,4 +1,5 @@
/** @odoo-module **/
import { registry } from "../registry";
import { memoize } from "../utils/functions";
import { useEffect } from "@web/core/utils/hooks";
@@ -78,9 +79,12 @@ export function useEnvDebugContext() {
}
export function useDebugCategory(category, context = {}) {
const debugContext = useEnvDebugContext();
useEffect(
() => debugContext.activateCategory(category, context),
() => []
);
const env = useEnv();
if (env.debug) {
const debugContext = useEnvDebugContext();
useEffect(
() => debugContext.activateCategory(category, context),
() => []
);
}
}
@@ -1,8 +1,8 @@
/** @odoo-module **/
import { browser } from "../browser/browser";
import { routeToUrl } from "../browser/router_service";
import { registry } from "../registry";
import { browser } from "@web/core/browser/browser";
import { routeToUrl } from "@web/core/browser/router_service";
import { registry } from "@web/core/registry";
function activateAssetsDebugging({ env }) {
return {
@@ -0,0 +1,14 @@
/** @odoo-module **/
export function editModelDebug(env, title, model, id) {
return env.services.action.doAction({
res_model: model,
res_id: id,
name: title,
type: "ir.actions.act_window",
views: [[false, "form"]],
view_mode: "form",
target: "new",
flags: { action_buttons: true, headless: true },
});
}
+7 -284
View File
@@ -1,212 +1,15 @@
/** @odoo-module **/
import { Dialog } from "../core/dialog/dialog";
import { formatDateTime, parseDateTime } from "../core/l10n/dates";
import { _lt } from "../core/l10n/translation";
import { registry } from "../core/registry";
import { _lt } from "@web/core/l10n/translation";
import { Dialog } from "@web/core/dialog/dialog";
import { formatDateTime, parseDateTime } from "@web/core/l10n/dates";
import { formatMany2one } from "@web/fields/formatters";
import { registry } from "@web/core/registry";
const { hooks, tags } = owl;
const { hooks } = owl;
const { useState } = hooks;
function editModelDebug(env, title, model, id) {
return env.services.action.doAction({
res_model: model,
res_id: id,
name: title,
type: "ir.actions.act_window",
views: [[false, "form"]],
view_mode: "form",
target: "new",
flags: { action_buttons: true, headless: true },
});
}
// Action items
function actionSeparator() {
return {
type: "separator",
sequence: 100,
};
}
function accessSeparator({ accessRights, action }) {
const { canSeeModelAccess, canSeeRecordRules } = accessRights;
if (!action.res_model || (!canSeeModelAccess && !canSeeRecordRules)) {
return null;
}
return {
type: "separator",
sequence: 200,
};
}
function editAction({ action, env }) {
if (!action.id) {
return null;
}
const description = env._t("Edit Action");
return {
type: "item",
description,
callback: () => {
editModelDebug(env, description, action.type, action.id);
},
sequence: 110,
};
}
function viewFields({ action, env }) {
if (!action.res_model) {
return null;
}
const description = env._t("View Fields");
return {
type: "item",
description,
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.model.fields",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 120,
};
}
function manageFilters({ action, env }) {
if (!action.res_model) {
return null;
}
const description = env._t("Manage Filters");
return {
type: "item",
description,
callback: () => {
// manage_filters
env.services.action.doAction({
res_model: "ir.filters",
name: description,
views: [
[false, "list"],
[false, "form"],
],
type: "ir.actions.act_window",
context: {
search_default_my_filters: true,
search_default_model_id: action.res_model,
},
});
},
sequence: 130,
};
}
function technicalTranslation({ action, env }) {
if (!action.res_model) {
return null;
}
return {
type: "item",
description: env._t("Technical Translation"),
callback: async () => {
const result = await env.services.orm.call(
"ir.translation",
"get_technical_translations",
[action.res_model]
);
env.services.action.doAction(result);
},
sequence: 140,
};
}
function viewAccessRights({ accessRights, action, env }) {
if (!action.res_model || !accessRights.canSeeModelAccess) {
return null;
}
const description = env._t("View Access Rights");
return {
type: "item",
description,
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.model.access",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 210,
};
}
function viewRecordRules({ accessRights, action, env }) {
if (!action.res_model || !accessRights.canSeeRecordRules) {
return null;
}
const description = env._t("Model Record Rules");
return {
type: "item",
description: env._t("View Record Rules"),
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.rule",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 220,
};
}
class FieldViewGetDialog extends Dialog {}
FieldViewGetDialog.props = Object.assign({}, Dialog.props, {
arch: { type: String },
close: Function,
});
FieldViewGetDialog.bodyTemplate = tags.xml`<pre t-esc="props.arch"/>`;
FieldViewGetDialog.title = _lt("Fields View Get");
const debugRegistry = registry.category("debug");
class GetMetadataDialog extends Dialog {
setup() {
@@ -243,7 +46,6 @@ class GetMetadataDialog extends Dialog {
}
GetMetadataDialog.bodyTemplate = "web.DebugMenu.getMetadataBody";
GetMetadataDialog.title = _lt("View Metadata");
class SetDefaultDialog extends Dialog {
setup() {
super.setup();
@@ -389,66 +191,7 @@ SetDefaultDialog.bodyTemplate = "web.DebugMenu.setDefaultBody";
SetDefaultDialog.footerTemplate = "web.DebugMenu.SetDefaultFooter";
SetDefaultDialog.title = _lt("Set Default");
function viewSeparator() {
return {
type: "separator",
sequence: 300,
};
}
function fieldsViewGet({ component, env }) {
return {
type: "item",
description: env._t("Fields View Get"),
callback: () => {
const props = {
arch: component.props.viewInfo.arch,
};
env.services.dialog.add(FieldViewGetDialog, props);
},
sequence: 340,
};
}
export function editView({ accessRights, action, component, env }) {
if (!accessRights.canEditView) {
return null;
}
let { view_id: viewId, type: viewType } = component.props.viewInfo;
viewType = viewType === "tree" ? "list" : viewType;
const displayName = action.views.find((v) => v.type === viewType).name.toString();
const description = env._t("Edit View: ") + displayName;
return {
type: "item",
description,
callback: () => {
editModelDebug(env, description, "ir.ui.view", viewId);
},
sequence: 350,
};
}
export function editSearchView({ accessRights, component, env }) {
if (!accessRights.canEditView) {
return null;
}
const description = env._t("Edit SearchView");
return {
type: "item",
description,
callback: () => {
editModelDebug(
env,
description,
"ir.ui.view",
component.props.viewParams.controlPanelFieldsView.view_id
);
},
sequence: 360,
};
}
// Form view itemss
// Form view items
function setDefaults({ action, component, env }) {
return {
@@ -515,26 +258,6 @@ function manageAttachments({ action, component, env }) {
};
}
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);
debugRegistry
.category("view")
.add("viewSeparator", viewSeparator)
.add("fieldsViewGet", fieldsViewGet)
.add("editView", editView)
.add("editSearchView", editSearchView);
debugRegistry
.category("form")
.add("setDefaults", setDefaults)
@@ -0,0 +1,94 @@
/** @odoo-module **/
import { _lt } from "@web/core/l10n/translation";
import { Dialog } from "@web/core/dialog/dialog";
import { editModelDebug } from "@web/core/debug/debug_utils";
import { registry } from "@web/core/registry";
const { tags } = owl;
const debugRegistry = registry.category("debug");
class FieldViewGetDialog extends Dialog {}
FieldViewGetDialog.props = Object.assign({}, Dialog.props, {
arch: { type: String },
close: Function,
});
FieldViewGetDialog.bodyTemplate = tags.xml`<pre t-esc="props.arch"/>`;
FieldViewGetDialog.title = _lt("Fields View Get");
function viewSeparator() {
return {
type: "separator",
sequence: 300,
};
}
function fieldsViewGet({ component, env }) {
let { arch } = component.props;
if ("viewInfo" in component.props) {
//legacy
arch = component.props.viewInfo.arch;
}
return {
type: "item",
description: env._t("Fields View Get"),
callback: () => {
env.services.dialog.add(FieldViewGetDialog, { arch });
},
sequence: 340,
};
}
export function editView({ accessRights, component, env }) {
if (!accessRights.canEditView) {
return null;
}
let type;
let { viewId } = component.props.info || {}; // fallback is there for legacy
if ("viewInfo" in component.props) {
// legacy
viewId = component.props.viewInfo.view_id;
type = component.props.viewInfo.type;
type = type === "tree" ? "list" : type;
} else {
type = component.constructor.type;
}
const displayName = type[0].toUpperCase() + type.slice(1);
const description = env._t("Edit View: ") + displayName;
return {
type: "item",
description,
callback: () => {
editModelDebug(env, description, "ir.ui.view", viewId);
},
sequence: 350,
};
}
export function editSearchView({ accessRights, component, env }) {
if (!accessRights.canEditView) {
return null;
}
let { searchViewId } = component.props.info || {}; // fallback is there for legacy
if ("viewParams" in component.props) {
//legacy
searchViewId = component.props.viewParams.action.controlPanelFieldsView.view_id;
}
const description = env._t("Edit ControlPanelView");
return {
type: "item",
description,
callback: () => {
editModelDebug(env, description, "ir.ui.view", searchViewId);
},
sequence: 360,
};
}
debugRegistry
.category("view")
.add("viewSeparator", viewSeparator)
.add("fieldsViewGet", fieldsViewGet)
.add("editView", editView)
.add("editSearchView", editSearchView);
@@ -9,6 +9,7 @@ import { evaluateExpr } from "@web/core/py_js/py";
import { registry } from "@web/core/registry";
import { KeepLast } from "@web/core/utils/concurrency";
import { sprintf } from "@web/core/utils/strings";
import { useDebugCategory } from "@web/core/debug/debug_context";
import { ActionDialog } from "./action_dialog";
/** @typedef {number|false} ActionId */
@@ -465,7 +466,7 @@ function makeActionManager(env) {
setup() {
this.Component = controller.Component;
this.componentRef = hooks.useRef("component");
this.registerCallback = null;
useDebugCategory("action", { action });
if (action.target !== "new") {
let beforeLeaveFn;
this.registerCallback = (type, fn) => {
@@ -0,0 +1,196 @@
/** @odoo-module **/
import { editModelDebug } from "@web/core/debug/debug_utils";
import { registry } from "@web/core/registry";
const debugRegistry = registry.category("debug");
function actionSeparator({ action }) {
if (!action.id || !action.res_model) {
return null;
}
return {
type: "separator",
sequence: 100,
};
}
function accessSeparator({ accessRights, action }) {
const { canSeeModelAccess, canSeeRecordRules } = accessRights;
if (!action.res_model || (!canSeeModelAccess && !canSeeRecordRules)) {
return null;
}
return {
type: "separator",
sequence: 200,
};
}
function editAction({ action, env }) {
if (!action.id) {
return null;
}
const description = env._t("Edit Action");
return {
type: "item",
description,
callback: () => {
editModelDebug(env, description, action.type, action.id);
},
sequence: 110,
};
}
function viewFields({ action, env }) {
if (!action.res_model) {
return null;
}
const description = env._t("View Fields");
return {
type: "item",
description,
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.model.fields",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 120,
};
}
function manageFilters({ action, env }) {
if (!action.res_model) {
return null;
}
const description = env._t("Manage Filters");
return {
type: "item",
description,
callback: () => {
// manage_filters
env.services.action.doAction({
res_model: "ir.filters",
name: description,
views: [
[false, "list"],
[false, "form"],
],
type: "ir.actions.act_window",
context: {
search_default_my_filters: true,
search_default_model_id: action.res_model,
},
});
},
sequence: 130,
};
}
function technicalTranslation({ action, env }) {
if (!action.res_model) {
return null;
}
return {
type: "item",
description: env._t("Technical Translation"),
callback: async () => {
const result = await env.services.orm.call(
"ir.translation",
"get_technical_translations",
[action.res_model]
);
env.services.action.doAction(result);
},
sequence: 140,
};
}
function viewAccessRights({ accessRights, action, env }) {
if (!action.res_model || !accessRights.canSeeModelAccess) {
return null;
}
const description = env._t("View Access Rights");
return {
type: "item",
description,
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.model.access",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 210,
};
}
function viewRecordRules({ accessRights, action, env }) {
if (!action.res_model || !accessRights.canSeeRecordRules) {
return null;
}
const description = env._t("Model Record Rules");
return {
type: "item",
description: env._t("View Record Rules"),
callback: async () => {
const modelId = (
await env.services.orm.search("ir.model", [["model", "=", action.res_model]], {
limit: 1,
})
)[0];
env.services.action.doAction({
res_model: "ir.rule",
name: description,
views: [
[false, "list"],
[false, "form"],
],
domain: [["model_id", "=", modelId]],
type: "ir.actions.act_window",
context: {
default_model_id: modelId,
},
});
},
sequence: 220,
};
}
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);
@@ -19,7 +19,7 @@ import {
import { click, getFixture, legacyExtraNextTick, patchWithCleanup } from "../../helpers/utils";
import { createWebClient, doAction, getActionManagerServerData } from "../../webclient/helpers";
import { openViewItem } from "@web/webclient/debug_items";
import { editView, editSearchView } from "@web/legacy/debug_manager";
import { editSearchView, editView } from "@web/views/debug_items";
const { Component, mount, tags } = owl;
const { xml } = tags;
@@ -2,7 +2,7 @@
import { browser } from "@web/core/browser/browser";
import { registry } from "@web/core/registry";
import { editView } from "@web/legacy/debug_manager";
import { editView } from "@web/views/debug_items";
import { clearUncommittedChanges } from "@web/webclient/actions/action_service";
import AbstractView from "web.AbstractView";
import FormView from "web.FormView";