diff --git a/addons/account/static/src/js/reconciliation/reconciliation_action.js b/addons/account/static/src/js/reconciliation/reconciliation_action.js index 4b097c79d5b..e43667be0e4 100644 --- a/addons/account/static/src/js/reconciliation/reconciliation_action.js +++ b/addons/account/static/src/js/reconciliation/reconciliation_action.js @@ -4,18 +4,16 @@ odoo.define('account.ReconciliationClientAction', function (require) { var AbstractAction = require('web.AbstractAction'); var ReconciliationModel = require('account.ReconciliationModel'); var ReconciliationRenderer = require('account.ReconciliationRenderer'); -var ControlPanelMixin = require('web.ControlPanelMixin'); -var Widget = require('web.Widget'); var core = require('web.core'); -var _t = core._t; /** * Widget used as action for 'account.bank.statement' reconciliation */ -var StatementAction = AbstractAction.extend(ControlPanelMixin, { +var StatementAction = AbstractAction.extend({ + hasControlPanel: true, title: core._t('Bank Reconciliation'), - template: 'reconciliation', + contentTemplate: 'reconciliation', custom_events: { change_mode: '_onAction', change_filter: '_onAction', @@ -34,7 +32,7 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { load_more: '_onLoadMore', reload: 'reload', }, - config: { + config: _.extend({}, AbstractAction.prototype.config, { // used to instantiate the model Model: ReconciliationModel.StatementModel, // used to instantiate the action interface @@ -47,7 +45,7 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { defaultDisplayQty: 10, // number of moves lines displayed in 'match' mode limitMoveLines: 15, - }, + }), /** * @override @@ -65,9 +63,6 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { limitMoveLines: params.params && params.params.limitMoveLines || this.config.limitMoveLines, }); this.widgets = []; - if (!this.action_manager) { - this.set_cp_bus(new Widget()); - } // Adding values from the context is necessary to put this information in the url via the action manager so that // you can retrieve it if the person shares his url or presses f5 _.each(params.params, function (value, name) { @@ -90,13 +85,14 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { var self = this; var def = this.model.load(this.params.context).then(this._super.bind(this)); return def.then(function () { - self.title = self.model.bank_statement_id ? self.model.bank_statement_id.display_name : self.title; + var title = self.model.bank_statement_id && self.model.bank_statement_id.display_name; + self._setTitle(title); self.renderer = new self.config.ActionRenderer(self, self.model, { 'bank_statement_id': self.model.bank_statement_id, 'valuenow': self.model.valuenow, 'valuemax': self.model.valuemax, 'defaultDisplayQty': self.model.defaultDisplayQty, - 'title': self.title, + 'title': title, }); }); }, @@ -124,9 +120,6 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { start: function () { var self = this; - this.set("title", this.title); - this.update_control_panel({search_view_hidden: true}, {clear: true}); - this.renderer.prependTo(self.$('.o_form_sheet')); this._renderLines(); @@ -141,6 +134,8 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { this.renderer._renderNotifications(this.model.statement.notifications); this._openFirstLine(); } + + return this._super.apply(this, arguments); }, /** @@ -151,7 +146,7 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { do_show: function () { this._super.apply(this, arguments); if (this.action_manager) { - this.update_control_panel({search_view_hidden: true}, {clear: true}); + this.updateControlPanel({clear: true}); this.action_manager.do_push_state({ action: this.params.tag, active_id: this.params.res_id, @@ -354,14 +349,14 @@ var StatementAction = AbstractAction.extend(ControlPanelMixin, { */ var ManualAction = StatementAction.extend({ title: core._t('Journal Items to Reconcile'), - config: { + config: _.extend({}, StatementAction.prototype.config, { Model: ReconciliationModel.ManualModel, ActionRenderer: ReconciliationRenderer.ManualRenderer, LineRenderer: ReconciliationRenderer.ManualLineRenderer, params: ['company_ids', 'mode', 'partner_ids', 'account_ids'], defaultDisplayQty: 30, limitMoveLines: 15, - }, + }), //-------------------------------------------------------------------------- // Handlers diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index c97dd86adb3..01645d5c97e 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -700,7 +700,7 @@ QUnit.module('account', { assert.ok(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should display the 'load more' button"); assert.equal(clientAction.widgets[1].$('.match div.load-more span').text(), 3, "should display 3 items remaining"); clientAction.widgets[1].$('.match div.load-more a').trigger('click'); - assert.containsN(clientAction.widgets[1], '.mv_line', 8, "should load 3 more records"), + assert.containsN(clientAction.widgets[1], '.mv_line', 8, "should load 3 more records"); assert.notOk(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should not display the 'load more' button anymore"); assert.ok(clientAction.widgets[0].$('caption button.btn-secondary:visible').length, "should display the 'validate' button"); diff --git a/addons/base_import/static/src/js/import_action.js b/addons/base_import/static/src/js/import_action.js index c093987bc8e..83259b30252 100644 --- a/addons/base_import/static/src/js/import_action.js +++ b/addons/base_import/static/src/js/import_action.js @@ -2,7 +2,6 @@ odoo.define('base_import.import', function (require) { "use strict"; var AbstractAction = require('web.AbstractAction'); -var ControlPanelMixin = require('web.ControlPanelMixin'); var core = require('web.core'); var session = require('web.session'); var time = require('web.time'); @@ -72,8 +71,9 @@ function dataFilteredQuery(q) { q.callback({results: suggestions}); } -var DataImport = AbstractAction.extend(ControlPanelMixin, { - template: 'ImportView', +var DataImport = AbstractAction.extend({ + hasControlPanel: true, + contentTemplate: 'ImportView', opts: [ {name: 'encoding', label: _lt("Encoding:"), value: ''}, {name: 'separator', label: _lt("Separator:"), value: ''}, @@ -137,7 +137,7 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { // import object id this.id = null; this.session = session; - action.display_name = _t('Import a File'); // Displayed in the breadcrumbs + this._title = _t('Import a File'); // Displayed in the breadcrumbs this.do_not_change_match = false; }, /** @@ -145,13 +145,14 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { */ willStart: function () { var self = this; - return this._rpc({ + var def = this._rpc({ model: this.res_model, method: 'get_import_templates', context: this.parent_context, }).then(function (result) { self.importTemplates = result; }); + return $.when(this._super.apply(this, arguments), def); }, start: function () { var self = this; @@ -170,7 +171,7 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { var status = { cp_content: {$buttons: self.$buttons}, }; - self.update_control_panel(status); + self.updateControlPanel(status); }) ); }, @@ -189,7 +190,7 @@ var DataImport = AbstractAction.extend(ControlPanelMixin, { this.$buttons.filter('.o_import_import').on('click', this.import.bind(this)); this.$buttons.filter('.o_import_file_reload').on('click', this.loaded_file.bind(this)); this.$buttons.filter('.oe_import_file').on('click', function () { - self.$('.oe_import_file').click(); + self.$('.o_content .oe_import_file').click(); }); this.$buttons.filter('.o_import_cancel').on('click', function(e) { e.preventDefault(); diff --git a/addons/board/static/src/js/add_to_board_menu.js b/addons/board/static/src/js/add_to_board_menu.js new file mode 100644 index 00000000000..fb6b469d5ab --- /dev/null +++ b/addons/board/static/src/js/add_to_board_menu.js @@ -0,0 +1,205 @@ +odoo.define('board.AddToBoardMenu', function (require) { +"use strict"; + +var ActionManager = require('web.ActionManager'); +var Context = require('web.Context'); +var core = require('web.core'); +var Domain = require('web.Domain'); +var favorites_submenus_registry = require('web.favorites_submenus_registry'); +var pyUtils = require('web.py_utils'); +var Widget = require('web.Widget'); + +var _t = core._t; +var QWeb = core.qweb; + +var AddToBoardMenu = Widget.extend({ + events: _.extend({}, Widget.prototype.events, { + 'click .o_add_to_board.o_menu_header': '_onMenuHeaderClick', + 'click .o_add_to_board_confirm_button': '_onAddToBoardConfirmButtonClick', + 'click .o_add_to_board_input': '_onAddToBoardInputClick', + 'keyup .o_add_to_board_input': '_onKeyUp', + }), + /** + * @override + * @param {Object} params + * @param {Object} params.action an ir.actions description + */ + init: function (parent, params) { + this._super(parent); + this.action = params.action; + this.isOpen = false; + }, + /** + * @override + */ + start: function () { + if (this.action.id && this.action.type === 'ir.actions.act_window') { + this._render(); + } + return this._super.apply(this, arguments); + }, + + //-------------------------------------------------------------------------- + // Public + //-------------------------------------------------------------------------- + + /** + * Closes the menu and render it. + * + */ + closeMenu: function () { + this.isOpen = false; + this._render(); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * This is the main function for actually saving the dashboard. This method + * is supposed to call the route /board/add_to_dashboard with proper + * information. + * + * @private + * @returns {Deferred} + */ + _addToBoard: function () { + var self = this; + var searchQuery; + // TO DO: for now the domains in query are evaluated. + // This should be changed I think. + this.trigger_up('get_search_query', { + callback: function (query) { + searchQuery = query; + } + }); + // TO DO: replace direct reference to action manager, controller, and currentAction in code below + + // AAB: trigger_up an event that will be intercepted by the controller, + // as soon as the controller is the parent of the control panel + var actionManager = this.findAncestor(function (ancestor) { + return ancestor instanceof ActionManager; + }); + var controller = actionManager.getCurrentController(); + + var context = new Context(this.action.context); + context.add(searchQuery.context); + context.add({ + group_by: pyUtils.eval('groupbys', searchQuery.groupBys || []) + }); + + this.trigger_up('get_controller_query_params', { + callback: function (controllerContext) { + context.add(controllerContext); + } + }); + + var domain = new Domain(this.action.domain || []); + domain = Domain.prototype.normalizeArray(domain.toArray().concat(searchQuery.domain)); + + var evalutatedContext = pyUtils.eval('context', context); + for (var key in evalutatedContext) { + if (evalutatedContext.hasOwnProperty(key) && /^search_default_/.test(key)) { + delete evalutatedContext[key]; + } + } + evalutatedContext.dashboard_merge_domains_contexts = false; + + var name = this.$input.val(); + + this.closeMenu(); + + return self._rpc({ + route: '/board/add_to_dashboard', + params: { + action_id: self.action.id || false, + context_to_save: evalutatedContext, + domain: domain, + view_mode: controller.viewType, + name: name, + }, + }) + .then(function (r) { + if (r) { + self.do_notify( + _.str.sprintf(_t("'%s' added to dashboard"), name), + _t('Please refresh your browser for the changes to take effect.') + ); + } else { + self.do_warn(_t("Could not add filter to dashboard")); + } + }); + }, + /** + * Renders and focuses the unique input if it is visible. + * + * @private + */ + _render: function () { + var $el = QWeb.render('AddToBoardMenu', {widget: this}); + this._replaceElement($el); + if (this.isOpen) { + this.$input = this.$('.o_add_to_board_input'); + this.$input.val(this.action.name); + this.$input.focus(); + } + }, + /** + * Hides and displays the submenu which allows adding custom filters. + * + * @private + */ + _toggleMenu: function () { + this.isOpen = !this.isOpen; + this._render(); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @private + * @param {jQueryEvent} event + */ + _onAddToBoardInputClick: function (event) { + event.preventDefault(); + event.stopPropagation(); + this.$input.focus(); + }, + /** + * @private + * @param {jQueryEvent} event + */ + _onAddToBoardConfirmButtonClick: function (event) { + event.preventDefault(); + event.stopPropagation(); + this._addToBoard(); + }, + /** + * @private + * @param {jQueryEvent} event + */ + _onKeyUp: function (event) { + if (event.which === $.ui.keyCode.ENTER) { + this._addToBoard(); + } + }, + /** + * @private + * @param {jQueryEvent} event + */ + _onMenuHeaderClick: function (event) { + event.preventDefault(); + event.stopPropagation(); + this._toggleMenu(); + }, + +}); + +favorites_submenus_registry.add('add_to_board_menu', AddToBoardMenu, 10); + +return AddToBoardMenu; + +}); diff --git a/addons/board/static/src/js/board_view.js b/addons/board/static/src/js/board_view.js index 3f9647de510..da8384f940f 100644 --- a/addons/board/static/src/js/board_view.js +++ b/addons/board/static/src/js/board_view.js @@ -120,7 +120,6 @@ var BoardController = FormController.extend({ var BoardRenderer = FormRenderer.extend({ custom_events: _.extend({}, FormRenderer.prototype.custom_events, { do_action: '_onDoAction', - env_updated: '_onEnvUpdated', update_filters: '_onUpdateFilters', switch_view: '_onSwitchView', }), @@ -256,6 +255,8 @@ var BoardRenderer = FormRenderer.extend({ var rawContext = new Context(action.context, evalContext, {lang: session.user_context.lang}); var context = pyUtils.eval('context', rawContext, evalContext); var domain = params.domain || pyUtils.eval('domain', action.domain || '[]', action.context); + action.context = context; + action.domain = domain; var viewType = params.viewType || action.views[0][1]; var view = _.find(action.views, function (descr) { return descr[1] === viewType; @@ -266,11 +267,14 @@ var BoardRenderer = FormRenderer.extend({ var View = viewRegistry.get(viewType); var view = new View(viewInfo, { action: action, - context: context, - domain: domain, - groupBy: context.group_by || [], - modelName: action.res_model, hasSelectors: false, + modelName: action.res_model, + searchQuery: { + context: context, + domain: domain, + groupBy: context.group_by || [], + }, + withControlPanel: false, }); return view.getController(self).then(function (controller) { self._boardFormViewIDs[controller.handle] = _.first( @@ -377,29 +381,6 @@ var BoardRenderer = FormRenderer.extend({ }, }); }, - /** - * Intercepts (without stopping) 'do_action' events to force the - * 'keepSearchView' option to false, as the dashboard action has no search - * view, and thus there is no search view that could be re-used for the - * action to execute (a new one will be created instead). - * - * @private - * @param {OdooEvent} event - */ - _onDoAction: function (event) { - if (event.data.options) { - event.data.options.keepSearchView = false; - } - }, - /** - * Stops the propagation of 'env_updated' events triggered by the controllers - * instantiated by the dashboard. - * - * @private - */ - _onEnvUpdated: function (event) { - event.stopPropagation(); - }, /** * @private * @param {MouseEvent} event diff --git a/addons/board/static/src/js/favorite_menu.js b/addons/board/static/src/js/favorite_menu.js deleted file mode 100644 index a3040af44f0..00000000000 --- a/addons/board/static/src/js/favorite_menu.js +++ /dev/null @@ -1,136 +0,0 @@ -odoo.define('board.favorite_menu', function (require) { -"use strict"; - -var ActionManager = require('web.ActionManager'); -var Context = require('web.Context'); -var core = require('web.core'); -var Domain = require('web.Domain'); -var FavoriteMenu = require('web.FavoriteMenu'); -var pyUtils = require('web.py_utils'); - -var _t = core._t; -var QWeb = core.qweb; - -FavoriteMenu.include({ - /** - * We manually add the 'add to dashboard' feature in the searchview. - * - * @override - */ - start: function () { - var self = this; - if(this.action_id === undefined) { - return this._super(); - } - if (this.action.type === 'ir.actions.act_window') { - this.add_to_dashboard_available = true; - this.$('.o_favorites_menu').append(QWeb.render('SearchView.addtodashboard')); - this.$add_to_dashboard = this.$('.o_add_to_dashboard'); - this.$add_dashboard_btn = this.$add_to_dashboard.eq(1).find('button'); - this.$add_dashboard_input = this.$add_to_dashboard.eq(0).find('input'); - this.$add_dashboard_link = this.$('.o_add_to_dashboard_link'); - var title = this.searchview.get_title(); - this.$add_dashboard_input.val(title); - this.$add_dashboard_link.click(function (e) { - e.preventDefault(); - self._toggleDashboardMenu(); - }); - this.$add_dashboard_btn.click(this.proxy('_addDashboard')); - } - return this._super(); - }, - - //-------------------------------------------------------------------------- - // Private - //-------------------------------------------------------------------------- - - /** - * This is the main function for actually saving the dashboard. This method - * is supposed to call the route /board/add_to_dashboard with proper - * information. - * - * @private - * @returns {Deferred} - */ - _addDashboard: function () { - var self = this; - var search_data = this.searchview.build_search_data(); - var context = new Context(this.searchview.dataset.get_context() || []); - var domain = []; - - _.each(search_data.contexts, context.add, context); - _.each(search_data.domains, function (d) { - domain.push.apply(domain, Domain.prototype.stringToArray(d)); - }); - - context.add({ - group_by: pyUtils.eval('groupbys', search_data.groupbys || []) - }); - // AAB: trigger_up an event that will be intercepted by the controller, - // as soon as the controller is the parent of the control panel - var am = this.findAncestor(function (a) { - return a instanceof ActionManager; - }); - // with options 'keepSearchView', it may happen that the action_id of - // the searchview (received in init) is not the one of the current - // action, which corresponds to the one we want to add to dashboard - var currentAction = am.getCurrentAction(); - var controller = am.getCurrentController(); - context.add(controller.widget.getContext()); - var c = pyUtils.eval('context', context); - for (var k in c) { - if (c.hasOwnProperty(k) && /^search_default_/.test(k)) { - delete c[k]; - } - } - this._toggleDashboardMenu(false); - c.dashboard_merge_domains_contexts = false; - var name = self.$add_dashboard_input.val(); - - return self._rpc({ - route: '/board/add_to_dashboard', - params: { - action_id: currentAction.id || false, - context_to_save: c, - domain: domain, - view_mode: controller.viewType, - name: name, - }, - }) - .then(function (r) { - if (r) { - self.do_notify( - _.str.sprintf(_t("'%s' added to dashboard"), name), - _t('Please refresh your browser for the changes to take effect.') - ); - } else { - self.do_warn(_t("Could not add filter to dashboard")); - } - }); - }, - /** - * @override - * @private - */ - _closeMenus: function () { - if (this.add_to_dashboard_available) { - this._toggleDashboardMenu(false); - } - this._super(); - }, - /** - * @private - * @param {undefined|false} isOpen - */ - _toggleDashboardMenu: function (isOpen) { - this.$add_dashboard_link - .toggleClass('o_closed_menu', !(_.isUndefined(isOpen)) ? !isOpen : undefined) - .toggleClass('o_open_menu', isOpen); - this.$add_to_dashboard.toggle(isOpen); - if (this.$add_dashboard_link.hasClass('o_open_menu')) { - this.$add_dashboard_input.focus(); - } - }, -}); - -}); diff --git a/addons/board/static/src/scss/dashboard.scss b/addons/board/static/src/scss/dashboard.scss index 08cd66a09c1..ad718403495 100644 --- a/addons/board/static/src/scss/dashboard.scss +++ b/addons/board/static/src/scss/dashboard.scss @@ -123,7 +123,7 @@ } // Override height of graph. min-height doesn't do the trick - .o_graph { + .o_graph_controller { height: 500px; } } diff --git a/addons/board/static/src/xml/board.xml b/addons/board/static/src/xml/board.xml index cb907290fd1..4e6f65a7803 100644 --- a/addons/board/static/src/xml/board.xml +++ b/addons/board/static/src/xml/board.xml @@ -74,6 +74,16 @@ +