[REF] web: rework env.config

The motivation of this commit comes from breadcrumbs.

Breadcrumbs work as follows: for each controller in the stack of
the ActionService, there is an entry in the breadcrumbs. Except
for the last entry (which corresponds to the currently displayed
controller), the value to display is computed by the ActionService
and stored in this.env.config.breadcrumbs. For the last entry,
we use the displayName set in this.env.config.

When a view wants to update its displayName (e.g. the form view
when we switch to another record), it updates the displayName in
the config, which thus correctly updates the breadcrumbs. However,
this doesn't change the internal values in the ActionService, so if
another controller is stacked over the current one, the penultimate
entry is wrong. To update the internal state of the ActionService,
the event 'controller-title-updated' must be triggered as well,
which is cumbersome. Note that we don't really face the issue yet
because among already converted views, none of them need to update
its displayName in the breadcrumbs.

This commit aims at uniformizing the way the (n-1) first entries
and the last one behave, by making the "breadcrumbs" key encode
all breadcrumbs entries (the n-1 first ones, and the last, current
one). We also replace the "displayName" key by "getDisplayName"
such that it uses a single source of truth, located in the
ActionService, and we provide a function "setDisplayName" to update
it. Finally, this commit introduces the notion of "default config"
which ensures that standalone views, or views in tests, have a
valid config with expected keys.

closes odoo/odoo#81031

Related: odoo/enterprise#22799
Signed-off-by: Géry Debongnie <ged@odoo.com>
This commit is contained in:
Aaron Bohy
2021-12-13 12:24:50 +00:00
parent 2cdd30d61a
commit f3e71d01ee
17 changed files with 149 additions and 81 deletions
@@ -76,8 +76,7 @@ const CTX_KEY_REGEX = /^(?:(?:default_|search_default_|show_).+|.+_view_ref|grou
// only register this template once for all dynamic classes ControllerComponent
const ControllerComponentTemplate = tags.xml`<t t-component="Component" t-props="props"
t-ref="component"
t-on-history-back="onHistoryBack"
t-on-controller-title-updated.stop="onTitleUpdated"/>`;
t-on-history-back="onHistoryBack"/>`;
function makeActionManager(env) {
const keepLast = new KeepLast();
@@ -242,7 +241,9 @@ function makeActionManager(env) {
.map((controller) => {
return {
jsId: controller.jsId,
name: controller.title || controller.action.name || env._t("Undefined"),
get name() {
return controller.displayName;
},
};
});
}
@@ -310,7 +311,7 @@ function makeActionManager(env) {
}
/**
* @param {ClientAction | ActWindowAction} action
* @param {ClientAction} action
* @param {Object} props
* @returns {{ props: ActionProps, config: Config }}
*/
@@ -319,11 +320,10 @@ function makeActionManager(env) {
props: Object.assign({}, props, { action, actionId: action.id }),
config: {
actionId: action.id,
actionType: action.type,
actionType: "ir.actions.client",
actionFlags: action.flags,
displayName: action.display_name || action.name || "",
views: action.views,
},
displayName: action.display_name || action.name || "",
};
}
@@ -449,12 +449,12 @@ function makeActionManager(env) {
props: viewProps,
config: {
actionId: action.id,
actionType: action.type,
actionType: "ir.actions.act_window",
actionFlags: action.flags,
displayName: action.display_name || action.name || "",
views: action.views,
viewSwitcherEntries,
},
displayName: action.display_name || action.name || "",
};
}
@@ -527,10 +527,15 @@ function makeActionManager(env) {
controllerArray.unshift(options.lazyController);
}
const nextStack = controllerStack.slice(0, index).concat(controllerArray);
controller.config.breadcrumbs = _getBreadcrumbs(nextStack.slice(0, -1));
if (controller.Component.isLegacy) {
controller.props.breadcrumbs = controller.config.breadcrumbs;
}
controller.config.breadcrumbs = _getBreadcrumbs(nextStack);
controller.config.getDisplayName = () => controller.displayName;
controller.config.setDisplayName = (displayName) => {
controller.displayName = displayName;
if (controller === _getCurrentController()) {
// if not mounted yet, will be done in "mounted"
env.services.title.setParts({ action: controller.displayName });
}
};
class ControllerComponent extends Component {
setup() {
@@ -632,9 +637,7 @@ function makeActionManager(env) {
// END LEGACY CODE COMPATIBILITY
controllerStack = nextStack; // the controller is mounted, commit the new stack
pushState(controller);
this.titleService.setParts({
action: controller.title || this.env.config.displayName,
});
this.titleService.setParts({ action: controller.displayName });
browser.sessionStorage.setItem("current_action", action._originalAction);
}
resolve();
@@ -654,13 +657,6 @@ function makeActionManager(env) {
_executeCloseAction();
}
}
onTitleUpdated(ev) {
controller.title = ev.detail;
if (this.isMounted) {
// if not mounted yet, will be done in "mounted"
this.titleService.setParts({ action: controller.title });
}
}
}
ControllerComponent.template = ControllerComponentTemplate;
ControllerComponent.Component = controller.Component;
@@ -1369,7 +1365,16 @@ function makeActionManager(env) {
}
export const actionService = {
dependencies: ["effect", "localization", "notification", "router", "rpc", "ui", "user"],
dependencies: [
"effect",
"localization",
"notification",
"router",
"rpc",
"title",
"ui",
"user",
],
start(env) {
return makeActionManager(env);
},