From 18e5416636b19b0953b1e6e26bfaeab1ebecce4c Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Wed, 11 Mar 2020 09:38:28 +0000 Subject: [REF] web: Adapt views/actions to new control panel Some web actions/controllers/viewsl have been adapted to properly instantiate the newly refactored control panel and update it accordingly. We needed to adapt the starting mechanism of actions and controllers to ensure that the control panel instantiation did not delay the loading of any widget. Part of task 2196029 Co-authored-by: Mathieu Duckerts-Antoine --- addons/web/static/src/js/chrome/abstract_action.js | 115 ++++++++++++++------- .../static/src/js/chrome/abstract_web_client.js | 14 +-- addons/web/static/src/js/chrome/action_manager.js | 2 +- .../src/js/chrome/action_manager_act_window.js | 11 +- addons/web/static/src/js/chrome/action_mixin.js | 72 +++++++------ 5 files changed, 128 insertions(+), 86 deletions(-) (limited to 'addons/web/static/src/js/chrome') diff --git a/addons/web/static/src/js/chrome/abstract_action.js b/addons/web/static/src/js/chrome/abstract_action.js index e28fd896182..b300cb22cf4 100644 --- a/addons/web/static/src/js/chrome/abstract_action.js +++ b/addons/web/static/src/js/chrome/abstract_action.js @@ -9,12 +9,14 @@ odoo.define('web.AbstractAction', function (require) { */ var ActionMixin = require('web.ActionMixin'); -var ControlPanelView = require('web.ControlPanelView'); +var ControlPanel = require('web.ControlPanel'); +var ControlPanelModel = require('web.ControlPanelModel'); var Widget = require('web.Widget'); +const { ComponentWrapper } = require('web.OwlCompatibility'); var AbstractAction = Widget.extend(ActionMixin, { config: { - ControlPanelView: ControlPanelView, + ControlPanel: ControlPanel, }, /** @@ -33,7 +35,7 @@ var AbstractAction = Widget.extend(ActionMixin, { * For example, the Discuss application adds the following line in its * constructor:: * - * this.controlPanelParams.modelName = 'mail.message'; + * this.controlPanelModelConfig.modelName = 'mail.message'; * * @type boolean */ @@ -73,15 +75,25 @@ var AbstractAction = Widget.extend(ActionMixin, { init: function (parent, action, options) { this._super(parent); this._title = action.display_name || action.name; - this.controlPanelParams = { - actionId: action.id, - context: action.context, - breadcrumbs: options && options.breadcrumbs || [], - title: this.getTitle(), - viewId: action.search_view_id && action.search_view_id[0], - withSearchBar: this.withSearchBar, - searchMenuTypes: this.searchMenuTypes, - }; + + if (this.hasControlPanel) { + this.controlPanelModelConfig = { + actionId: action.id, + actionContext: action.context || {}, + actionDomain: action.domain || [], + env: owl.Component.env, + withSearchBar: this.withSearchBar, + }; + + this.viewId = action.search_view_id && action.search_view_id[0]; + + this.controlPanelProps = { + action, + breadcrumbs: options && options.breadcrumbs, + withSearchBar: this.withSearchBar, + searchMenuTypes: this.searchMenuTypes, + }; + } }, /** * The willStart method is actually quite complicated if the client action @@ -89,40 +101,73 @@ var AbstractAction = Widget.extend(ActionMixin, { * * @override */ - willStart: function () { - var self = this; - var proms = [this._super.apply(this, arguments)]; + willStart: async function () { + const proms = [this._super(...arguments)]; if (this.hasControlPanel) { - var params = this.controlPanelParams; if (this.loadControlPanel) { - proms.push(this - .loadFieldView(params.modelName, params.context || {}, params.viewId, 'search') - .then(function (fieldsView) { - params.viewInfo = { - arch: fieldsView.arch, - fields: fieldsView.fields, - }; - })); + const { context, searchMenuTypes } = this.controlPanelProps; + const { modelName } = this.controlPanelModelConfig; + const options = { load_filters: searchMenuTypes.includes('favorite') }; + const args = [modelName, context || {}, this.viewId, 'search', options]; + const loadFieldViewPromise = this.loadFieldView(...args); + const {arch, fields, favoriteFilters } = await loadFieldViewPromise; + this.controlPanelModelConfig.viewInfo = {arch, fields, favoriteFilters }; + this.controlPanelProps.fields = fields; } - return Promise.all(proms).then(function () { - var controlPanelView = new self.config.ControlPanelView(params); - return controlPanelView.getController(self).then(function (controlPanel) { - self._controlPanel = controlPanel; - return self._controlPanel.appendTo(document.createDocumentFragment()); - }); - }); + this._controlPanelModel = new ControlPanelModel(this.controlPanelModelConfig); + this.controlPanelProps.controlPanelModel = this._controlPanelModel; + proms.push(this._controlPanelModel.isReady); } return Promise.all(proms); }, /** * @override */ - start: function () { - if (this._controlPanel) { - this._controlPanel.$el.prependTo(this.$el); + start: async function () { + await this._super(...arguments); + if (this.hasControlPanel) { + if ('title' in this.controlPanelProps) { + this._setTitle(this.controlPanelProps.title); + } + this.controlPanelProps.title = this.getTitle(); + this._controlPanelWrapper = new ComponentWrapper(this, ControlPanel, this.controlPanelProps); + await this._controlPanelWrapper.mount(this.el, { position: 'first-child' }); + } - return this._super.apply(this, arguments); }, + /** + * @override + */ + destroy: function() { + this._super.apply(this, arguments); + ActionMixin.destroy.call(this); + }, + /** + * @override + */ + on_attach_callback: function () { + ActionMixin.on_attach_callback.call(this); + if (this.hasControlPanel) { + this._controlPanelModel.on('search', this, this._onSearch); + this._controlPanelModel.on('get-controller-query-params', this, this._onGetOwnedQueryParams); + } + }, + /** + * @override + */ + on_detach_callback: function () { + ActionMixin.on_detach_callback.call(this); + if (this.hasControlPanel) { + this._controlPanelModel.off('search', this); + this._controlPanelModel.off('get-controller-query-params', this); + } + }, + + /** + * @private + * @param {Object} [searchQuery] + */ + _onSearch: function () {}, }); return AbstractAction; diff --git a/addons/web/static/src/js/chrome/abstract_web_client.js b/addons/web/static/src/js/chrome/abstract_web_client.js index 8837ffe813e..9012b7f53fd 100644 --- a/addons/web/static/src/js/chrome/abstract_web_client.js +++ b/addons/web/static/src/js/chrome/abstract_web_client.js @@ -32,9 +32,7 @@ var _t = core._t; var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, { dependencies: ['notification'], - events: _.extend({}, KeyboardNavigationMixin.events, { - 'click .o_search_options .dropdown-menu': '_onClickDropDownMenu', - }), + events: _.extend({}, KeyboardNavigationMixin.events), custom_events: { call_service: '_onCallService', clear_uncommitted_changes: function (e) { @@ -356,16 +354,6 @@ var AbstractWebClient = Widget.extend(KeyboardNavigationMixin, { const result = service[payload.method].apply(service, args); payload.callback(result); }, - /** - * When clicking inside a dropdown to modify search options - * prevents the bootstrap dropdown to close on itself - * - * @private - * @param {Event} ev - */ - _onClickDropDownMenu: function (ev) { - ev.stopPropagation(); - }, /** * Whenever the connection is lost, we need to notify the user. * diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js index ee108c94326..92c090827d8 100644 --- a/addons/web/static/src/js/chrome/action_manager.js +++ b/addons/web/static/src/js/chrome/action_manager.js @@ -877,7 +877,7 @@ var ActionManager = Widget.extend({ /** * @private * @param {OdooEvent} ev - * @param {OdooEvent} ev.data.controllerID + * @param {string} ev.data.controllerID */ _onBreadcrumbClicked: function (ev) { ev.stopPropagation(); diff --git a/addons/web/static/src/js/chrome/action_manager_act_window.js b/addons/web/static/src/js/chrome/action_manager_act_window.js index ff060153f27..f6c5661eb8e 100644 --- a/addons/web/static/src/js/chrome/action_manager_act_window.js +++ b/addons/web/static/src/js/chrome/action_manager_act_window.js @@ -546,6 +546,7 @@ ActionManager.include({ return Promise.resolve(controller.widget.willRestore()).then(function () { viewOptions = _.extend({}, viewOptions, { breadcrumbs: self._getBreadcrumbs(self.controllerStack.slice(0, index)), + shouldUpdateControlPanel: true, }); return controller.widget.reload(viewOptions).then(function () { return controller; @@ -708,15 +709,15 @@ ActionManager.include({ */ _onSwitchView: function (ev) { ev.stopPropagation(); - var viewType = ev.data.view_type; - var currentController = this.getCurrentController(); + const viewType = ev.data.view_type; + const currentController = this.getCurrentController(); if (currentController.jsID === ev.data.controllerID) { // only switch to the requested view if the controller that // triggered the request is the current controller - var action = this.actions[currentController.actionID]; - var currentControllerState = currentController.widget.exportState(); + const action = this.actions[currentController.actionID]; + const currentControllerState = currentController.widget.exportState(); action.controllerState = _.extend({}, action.controllerState, currentControllerState); - var options = { + const options = { controllerState: action.controllerState, currentId: ev.data.res_id, }; diff --git a/addons/web/static/src/js/chrome/action_mixin.js b/addons/web/static/src/js/chrome/action_mixin.js index a704e5736a0..99f45405c72 100644 --- a/addons/web/static/src/js/chrome/action_mixin.js +++ b/addons/web/static/src/js/chrome/action_mixin.js @@ -18,11 +18,13 @@ odoo.define('web.ActionMixin', function (require) { * action manager. * * @module web.ActionMixin + * @extends WidgetAdapterMixin */ const core = require('web.core'); + const { WidgetAdapterMixin } = require('web.OwlCompatibility'); - const ActionMixin = { + const ActionMixin = Object.assign({}, WidgetAdapterMixin, { template: 'Action', /** @@ -41,7 +43,7 @@ odoo.define('web.ActionMixin', function (require) { * will also implement the ParentedMixin which actually manages those */ custom_events: { - get_controller_query_params: '_onGetControllerQueryParams', + get_controller_query_params: '_onGetOwnedQueryParams', }, /** @@ -63,16 +65,6 @@ odoo.define('web.ActionMixin', function (require) { */ _title: '', - /** - * Called each time the action is attached into the DOM. - */ - on_attach_callback: function () { }, - - /** - * Called each time the action is detached from the DOM. - */ - on_detach_callback: function () { }, - /** * @override */ @@ -177,21 +169,40 @@ odoo.define('web.ActionMixin', function (require) { renderButtons: function ($node) { }, /** - * This is the main method to customize the controlpanel content. - * - * @see updateContents method in ControlPanelRenderer for more info + * Method used to update the widget buttons state. + */ + updateButtons: function () { }, + + /** + * The parameter newProps is used to update the props of + * the controlPanelWrapper before render it. The key 'cp_content' + * is not a prop of the control panel itself. One should if possible use + * the slot mechanism. * - * @param {Object} [status] - * @param {string} [status.title] - * @param {Object} [options] - * @param {boolean} [options.clear] - */ - updateControlPanel: function (status, options) { - if (this._controlPanel) { - status = status || {}; - status.title = status.title || this.getTitle(); - this._controlPanel.updateContents(status, options || {}); + * @param {Object} [newProps={}] + * @returns {Promise} + */ + updateControlPanel: async function (newProps = {}) { + if (!this.withControlPanel && !this.hasControlPanel) { + return; + } + const props = Object.assign({}, newProps); // Work with a clean new object + if ('title' in props) { + this._setTitle(props.title); + this.controlPanelProps.title = this.getTitle(); + delete props.title; + } + if ('cp_content' in props) { + // cp_content has been updated: refresh it. + this.controlPanelProps.cp_content = Object.assign({}, + this.controlPanelProps.cp_content, + props.cp_content, + ); + delete props.cp_content; } + // Update props state + Object.assign(this.controlPanelProps, props); + return this._controlPanelWrapper.update(this.controlPanelProps); }, //--------------------------------------------------------------------- @@ -204,7 +215,6 @@ odoo.define('web.ActionMixin', function (require) { */ _setTitle: function (title) { this._title = title; - this.updateControlPanel({ title: this._title }, { clear: false }); }, //--------------------------------------------------------------------- @@ -218,15 +228,13 @@ odoo.define('web.ActionMixin', function (require) { * current controller. * * @private - * @param {OdooEvent} ev - * @param {function} ev.data.callback used to send the requested state + * @param {function} callback used to send the requested state */ - _onGetControllerQueryParams: function (ev) { - ev.stopPropagation(); + _onGetOwnedQueryParams: function (callback) { const state = this.getOwnedQueryParams(); - ev.data.callback(state || {}); + callback(state || {}); }, - }; + }); return ActionMixin; }); -- cgit v1.2.3