diff options
| author | Aaron Bohy <aab@odoo.com> | 2019-03-13 15:42:52 +0000 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2019-04-02 11:55:57 +0000 |
| commit | 2be28d4d033b5930e5a16ff02407315a116e9043 (patch) | |
| tree | 0561dbbf8c127d0aea94c6766c6815fe1d1f2d83 /addons/web/static/src | |
| parent | 5895d23cbd26beb3bc3c83cc760b3cdbb64b0e85 (diff) | |
[IMP] web,board: enable pagination in grouped lists
With this rev., when there are a lot of groups in a grouped list
view, groups are displayed under several pages, whereas they were
all displayed in the same page before.
This is especially interesting with the new 'expand' attribute, to
ensure that we don't read records for a large number of groups.
By default, the groups limit is set to 80 (like records), and to 10
is the 'expand' attribute is set to true. This limit can be
overriden with the 'groups_limit' attribute.
Part of task 1915702
Diffstat (limited to 'addons/web/static/src')
7 files changed, 110 insertions, 44 deletions
diff --git a/addons/web/static/src/js/core/rpc.js b/addons/web/static/src/js/core/rpc.js index 21ec43e3d95..802f7082cad 100644 --- a/addons/web/static/src/js/core/rpc.js +++ b/addons/web/static/src/js/core/rpc.js @@ -37,6 +37,7 @@ return { buildQuery: function (options) { var route; var params = options.params || {}; + var orderBy; if (options.route) { route = options.route; } else if (options.model && options.method) { @@ -50,7 +51,7 @@ return { params.kwargs.context = options.context || params.context || params.kwargs.context; } - if (options.method === 'read_group') { + if (options.method === 'read_group' || options.method === 'web_read_group') { if (!(params.args && params.args[0] !== undefined)) { params.kwargs.domain = options.domain || params.domain || params.kwargs.domain || []; } @@ -64,7 +65,7 @@ return { params.kwargs.limit = options.limit || params.limit || params.kwargs.limit; // In kwargs, we look for "orderby" rather than "orderBy" (note the absence of capital B), // since the Python argument to the actual function is "orderby". - var orderBy = options.orderBy || params.orderBy || params.kwargs.orderby; + orderBy = options.orderBy || params.orderBy || params.kwargs.orderby; params.kwargs.orderby = orderBy ? this._serializeSort(orderBy) : orderBy; params.kwargs.lazy = 'lazy' in options ? options.lazy : params.lazy; } @@ -77,7 +78,7 @@ return { params.kwargs.limit = options.limit || params.limit || params.kwargs.limit; // In kwargs, we look for "order" rather than "orderBy" since the Python // argument to the actual function is "order". - var orderBy = options.orderBy || params.orderBy || params.kwargs.order; + orderBy = options.orderBy || params.orderBy || params.kwargs.order; params.kwargs.order = orderBy ? this._serializeSort(orderBy) : orderBy; } @@ -88,7 +89,7 @@ return { params.fields = options.fields || params.fields; params.limit = options.limit || params.limit; params.offset = options.offset || params.offset; - var orderBy = options.orderBy || params.orderBy; + orderBy = options.orderBy || params.orderBy; params.sort = orderBy ? this._serializeSort(orderBy) : orderBy; params.context = options.context || params.context || {}; } diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js index 19d2fd57892..064f7b84a52 100644 --- a/addons/web/static/src/js/views/basic/basic_controller.js +++ b/addons/web/static/src/js/views/basic/basic_controller.js @@ -148,25 +148,28 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { */ renderPager: function ($node, options) { var self = this; - var data = this.model.get(this.handle, {raw: true}); - this.pager = new Pager(this, data.count, data.offset + 1, data.limit, options); + var params = this._getPagerParams(); + this.pager = new Pager(this, params.size, params.current_min, params.limit, options); this.pager.on('pager_changed', this, function (newState) { - var self = this; this.pager.disable(); - data = this.model.get(this.handle, {raw: true}); + var data = this.model.get(this.handle, {raw: true}); var limitChanged = (data.limit !== newState.limit); - this.reload({limit: newState.limit, offset: newState.current_min - 1}) - .then(function () { - // Reset the scroll position to the top on page changed only - if (!limitChanged) { - self.trigger_up('scrollTo', {top: 0}); - } - }) - .then(this.pager.enable.bind(this.pager)); + var reloadParams; + if (data.groupedBy && data.groupedBy.length) { + reloadParams = {groupsLimit: newState.limit, groupsOffset: newState.current_min - 1}; + } else { + reloadParams = {limit: newState.limit, offset: newState.current_min - 1}; + } + this.reload(reloadParams).then(function () { + // reset the scroll position to the top on page changed only + if (!limitChanged) { + self.trigger_up('scrollTo', {top: 0}); + } + }).then(this.pager.enable.bind(this.pager)); }); - return this.pager.appendTo($node).then(function() { - self._updatePager(); // to force proper visibility + return this.pager.appendTo($node).then(function () { + self._updatePager(); // to force proper visibility }); }, /** @@ -413,6 +416,22 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { }); }, /** + * Return the params (current_min, limit and size) to pass to the pager, + * according to the current state. + * + * @private + * @returns {Object} + */ + _getPagerParams: function () { + var state = this.model.get(this.handle, {raw: true}); + var isGrouped = state.groupedBy && state.groupedBy.length; + return { + current_min: (isGrouped ? state.groupsOffset : state.offset) + 1, + limit: isGrouped ? state.groupsLimit : state.limit, + size: isGrouped ? state.groupsCount : state.count, + }; + }, + /** * Returns the new sidebar env * * @private @@ -426,6 +445,16 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { }; }, /** + * Determine whether or not the pager must be displayed (probably depending + * on the current state). Controllers must override this to implement their + * own logic. + * + * @private + */ + _isPagerVisible: function () { + return true; + }, + /** * Helper function to display a warning that some fields have an invalid * value. This is used when a save operation cannot be completed. * @@ -533,23 +562,14 @@ var BasicController = AbstractController.extend(FieldManagerMixin, { } }, /** - * Helper method, to make sure the information displayed by the pager is up - * to date. + * Update the pager with the current state. + * + * @private */ _updatePager: function () { if (this.pager) { - var data = this.model.get(this.handle, {raw: true}); - this.pager.updateState({ - current_min: data.offset + 1, - size: data.count, - }); - var isRecord = data.type === 'record'; - var hasData = !!data.count; - var isGrouped = data.groupedBy ? !!data.groupedBy.length : false; - var isNew = this.model.isNew(this.handle); - var isPagerVisible = isRecord ? !isNew : (hasData && !isGrouped); - - this.pager.do_toggle(isPagerVisible); + this.pager.updateState(this._getPagerParams()); + this.pager.do_toggle(this._isPagerVisible()); } }, diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js index 35435a3e500..d07ec61abdd 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -88,7 +88,6 @@ var concurrency = require('web.concurrency'); var Context = require('web.Context'); var core = require('web.core'); var Domain = require('web.Domain'); -var fieldUtils = require('web.field_utils'); var session = require('web.session'); var utils = require('web.utils'); var viewUtils = require('web.viewUtils'); @@ -639,6 +638,9 @@ var BasicModel = AbstractModel.extend({ getDomain: element.getDomain, getFieldNames: element.getFieldNames, groupedBy: element.groupedBy, + groupsCount: element.groupsCount, + groupsLimit: element.groupsLimit, + groupsOffset: element.groupsOffset, id: element.id, isDirty: element.isDirty, isOpen: element.isOpen, @@ -3732,6 +3734,9 @@ var BasicModel = AbstractModel.extend({ fields: fields, fieldsInfo: params.fieldsInfo, groupedBy: params.groupedBy || [], + groupsCount: 0, + groupsLimit: type === 'list' && params.groupsLimit || null, + groupsOffset: 0, id: _.uniqueId(params.modelName + '_'), isOpen: params.isOpen, limit: type === 'record' ? 1 : params.limit, @@ -4245,20 +4250,25 @@ var BasicModel = AbstractModel.extend({ var groupByField = list.groupedBy[0]; var rawGroupBy = groupByField.split(':')[0]; var fields = _.uniq(list.getFieldNames().concat(rawGroupBy)); - var orderedBy = _.filter(list.orderedBy, function(order){ + var orderedBy = _.filter(list.orderedBy, function (order) { return order.name === rawGroupBy || list.fields[order.name].group_operator !== undefined; }); + var openGroupsLimit = list.groupsLimit || self.OPEN_GROUP_LIMIT; return this._rpc({ model: list.model, - method: 'read_group', + method: 'web_read_group', fields: fields, domain: list.domain, context: list.context, groupBy: list.groupedBy, + limit: list.groupsLimit, + offset: list.groupsOffset, orderBy: orderedBy, lazy: true, }) - .then(function (groups) { + .then(function (result) { + var groups = result.groups; + list.groupsCount = result.length; var previousGroups = _.map(list.data, function (groupID) { return self.localData[groupID]; }); @@ -4321,7 +4331,7 @@ var BasicModel = AbstractModel.extend({ // form view) are reloaded newGroup.limit = oldGroup.limit + oldGroup.loadMoreOffset; self.localData[newGroup.id] = newGroup; - } else if (!newGroup.openGroupByDefault || openGroupCount >= self.OPEN_GROUP_LIMIT) { + } else if (!newGroup.openGroupByDefault || openGroupCount >= openGroupsLimit) { newGroup.isOpen = false; } else if ('__fold' in group) { newGroup.isOpen = !group.__fold; @@ -4486,6 +4496,12 @@ var BasicModel = AbstractModel.extend({ if (options.offset !== undefined) { this._setOffset(element.id, options.offset); } + if (options.groupsLimit !== undefined) { + element.groupsLimit = options.groupsLimit; + } + if (options.groupsOffset !== undefined) { + element.groupsOffset = options.groupsOffset; + } if (options.loadMoreOffset !== undefined) { element.loadMoreOffset = options.loadMoreOffset; } else { diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js index 9997e144ca3..a351c8fa04f 100644 --- a/addons/web/static/src/js/views/form/form_controller.js +++ b/addons/web/static/src/js/views/form/form_controller.js @@ -348,6 +348,15 @@ var FormController = BasicController.extend({ this.renderer.enableButtons(); }, /** + * Only display the pager if we are not on a new record. + * + * @override + * @private + */ + _isPagerVisible: function () { + return !this.model.isNew(this.handle); + }, + /** * Hook method, called when record(s) has been deleted. * * @override diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js index 58174c7812d..4ea823ed062 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -138,6 +138,16 @@ var KanbanController = BasicController.extend({ return this.renderer.updateRecord(this.model.get(id)); }, /** + * Only display the pager in the ungrouped case, with data. + * + * @override + * @private + */ + _isPagerVisible: function () { + var state = this.model.get(this.handle, {raw: true}); + return !!(state.count && !state.groupedBy.length); + }, + /** * @private * @param {Widget} kanbanRecord * @param {Object} params diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js index 217f02c8fd1..a7b71ad4cf2 100644 --- a/addons/web/static/src/js/views/list/list_controller.js +++ b/addons/web/static/src/js/views/list/list_controller.js @@ -11,7 +11,6 @@ var core = require('web.core'); var BasicController = require('web.BasicController'); var DataExport = require('web.DataExport'); var Dialog = require('web.Dialog'); -var pyUtils = require('web.py_utils'); var Sidebar = require('web.Sidebar'); var _t = core._t; @@ -343,6 +342,16 @@ var ListController = BasicController.extend({ return _.extend(env, {domain: record.getDomain()}); }, /** + * Only display the pager when there are data to display. + * + * @override + * @private + */ + _isPagerVisible: function () { + var state = this.model.get(this.handle, {raw: true}); + return !!state.count; + }, + /** * Allows to change the mode of a single row. * * @override @@ -395,11 +404,9 @@ var ListController = BasicController.extend({ * @returns {Promise} */ _update: function () { - var self = this; - return this._super.apply(this, arguments).then(function () { - self._toggleSidebar(); - self._toggleCreateButton(); - }); + return this._super.apply(this, arguments) + .then(this._toggleSidebar.bind(this)) + .then(this._toggleCreateButton.bind(this)); }, /** * This helper simply makes sure that the control panel buttons matches the diff --git a/addons/web/static/src/js/views/list/list_view.js b/addons/web/static/src/js/views/list/list_view.js index 163ac850817..e65a8c4adc4 100644 --- a/addons/web/static/src/js/views/list/list_view.js +++ b/addons/web/static/src/js/views/list/list_view.js @@ -38,6 +38,7 @@ var ListView = BasicView.extend({ var selectedRecords = []; // there is no selected records by default var mode = this.arch.attrs.editable && !params.readonly ? "edit" : "readonly"; + var expandGroups = !!JSON.parse(this.arch.attrs.expand || "0"); this.controllerParams.editable = this.arch.attrs.editable; this.controllerParams.hasSidebar = params.hasSidebar; @@ -54,8 +55,10 @@ var ListView = BasicView.extend({ this.rendererParams.addCreateLineInGroups = this.rendererParams.editable && this.controllerParams.activeActions.create; this.loadParams.limit = this.loadParams.limit || 80; - this.loadParams.openGroupByDefault = !!JSON.parse(this.arch.attrs.expand || "0"); + this.loadParams.openGroupByDefault = expandGroups; this.loadParams.type = 'list'; + var groupsLimit = parseInt(this.arch.attrs.groups_limit, 10); + this.loadParams.groupsLimit = groupsLimit || (expandGroups ? 10 : 80); }, //-------------------------------------------------------------------------- |
