diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js index 4aeb5404130..8cab25c31ab 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column.js +++ b/addons/web/static/src/js/views/kanban/kanban_column.js @@ -64,7 +64,8 @@ var KanbanColumn = Widget.extend({ this.recordsDraggable = options.recordsDraggable; this.relation = options.relation; this.offset = 0; - this.remaining = data.count - this.data_records.length; + this.loadMoreCount = data.loadMoreCount; + this.loadMoreOffset = data.loadMoreOffset; this.canBeFolded = this.folded; if (options.hasProgressBar) { @@ -162,7 +163,7 @@ var KanbanColumn = Widget.extend({ if (this.tooltipInfo) { this.$header.find('.o_kanban_header_title').tooltip({}).attr('data-original-title', this.tooltipInfo); } - if (!this.remaining) { + if (!this.loadMoreCount) { this.$('.o_kanban_load_more').remove(); } else { this.$('.o_kanban_load_more').html(QWeb.render('KanbanView.LoadMore', {widget: this})); @@ -349,7 +350,7 @@ var KanbanColumn = Widget.extend({ */ _onLoadMore: function (event) { event.preventDefault(); - this.trigger_up('kanban_load_more'); + this.trigger_up('kanban_load_column_records', { loadMoreOffset: this.loadMoreOffset }); }, /** * @private diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js index 752d2b2dc6c..1639f7c34a3 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js @@ -11,7 +11,6 @@ const _t = core._t; var KanbanColumnProgressBar = Widget.extend({ template: 'KanbanView.ColumnProgressBar', events: { - 'click .o_kanban_counter_progress': '_onProgressBarParentClick', 'click .progress-bar': '_onProgressBarClick', }, /** @@ -28,6 +27,7 @@ var KanbanColumnProgressBar = Widget.extend({ this.columnID = options.columnID; this.columnState = columnState; + this.activeFilter = {}; // attributes this.fieldName = columnState.progressBarValues.field; @@ -90,16 +90,13 @@ var KanbanColumnProgressBar = Widget.extend({ */ computeCounters() { const subgroupCounts = {}; - let allSubgroupCount = 0; for (const key of Object.keys(this.colors)) { const subgroupCount = this.columnState.progressBarValues.counts[key] || 0; - if (this.activeFilter === key && subgroupCount === 0) { - this.activeFilter = false; + if (this.activeFilter.value === key && subgroupCount === 0) { + this.activeFilter = {}; } subgroupCounts[key] = subgroupCount; - allSubgroupCount += subgroupCount; - }; - subgroupCounts.__false = this.columnState.count - allSubgroupCount; + } this.groupCount = this.columnState.count; this.subgroupCounts = subgroupCounts; @@ -127,8 +124,8 @@ var KanbanColumnProgressBar = Widget.extend({ _.each(self.colors, function (val, key) { $el.removeClass('o_kanban_group_show_' + val); }); - if (self.activeFilter) { - $el.addClass('o_kanban_group_show o_kanban_group_show_' + self.colors[self.activeFilter]); + if (self.activeFilter.value) { + $el.addClass('o_kanban_group_show o_kanban_group_show_' + self.colors[self.activeFilter.value]); } }, }); @@ -171,7 +168,7 @@ var KanbanColumnProgressBar = Widget.extend({ }); // Adapt active state - $bar.toggleClass('progress-bar-animated progress-bar-striped', key === self.activeFilter); + $bar.toggleClass('progress-bar-animated progress-bar-striped', key === self.activeFilter.value); // Adapt width $bar.removeClass('o_bar_has_records transition-off'); @@ -198,24 +195,24 @@ var KanbanColumnProgressBar = Widget.extend({ var start = this.prevTotalCounterValue; var end = this.totalCounterValue; - if (this.activeFilter) { + if (this.activeFilter.value) { if (this.sumField) { end = 0; _.each(self.columnState.data, function (record) { var recordData = record.data; - if (self.activeFilter === recordData[self.fieldName] || - (self.activeFilter === '__false' && !recordData[self.fieldName])) { + if (self.activeFilter.value === recordData[self.fieldName] || + (self.activeFilter.value === '__false' && !recordData[self.fieldName])) { end += parseFloat(recordData[self.sumField]); } }); } else { - end = this.subgroupCounts[this.activeFilter]; + end = this.subgroupCounts[this.activeFilter.value]; } } this.prevTotalCounterValue = end; var animationClass = start > 999 ? 'o_kanban_grow' : 'o_kanban_grow_huge'; - if (start !== undefined && (end > start || this.activeFilter) && this.ANIMATE) { + if (start !== undefined && (end > start || this.activeFilter.value) && this.ANIMATE) { $({currentValue: start}).animate({currentValue: end}, { duration: 1000, start: function () { @@ -255,33 +252,47 @@ var KanbanColumnProgressBar = Widget.extend({ }, }); }, + /** + * Toggles the active filter on this progressbar. + * It also computes the corresponding domain extension. + * + * @private + * @param {string} value + */ + _toggleActiveFilter(value) { + const activeFilter = Object.assign({}, this.activeFilter); + if (activeFilter.value === value) { + // If the filter was active and we click again on the same one, deactivate. + activeFilter.domain = []; + activeFilter.value = false; + } else { + const field = this.fieldName; + if (value === '__false') { + const values = Object.keys(this.colors).filter(el => el !== value); + activeFilter.domain = ['!', [field, 'in', values]]; + } else { + activeFilter.domain = [[field, '=', value]]; + } + activeFilter.value = value; + } + this.activeFilter = activeFilter; + }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- - /** * @private * @param {Event} ev */ _onProgressBarClick: function (ev) { this.$clickedBar = $(ev.currentTarget); - var filter = this.$clickedBar.data('filter'); - this.activeFilter = (this.activeFilter === filter ? false : filter); + const filterValue = this.$clickedBar.data('filter'); + this._toggleActiveFilter(filterValue); this._notifyState(); - this._render(); - }, - /** - * @private - * @param {Event} ev - */ - _onProgressBarParentClick: function (ev) { - if (ev.target !== ev.currentTarget) { - return; - } - this.activeFilter = false; - this._notifyState(); - this._render(); + this.trigger_up('kanban_load_column_records', { + activeFilter: this.activeFilter + }); }, }); return KanbanColumnProgressBar; 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 1b6e6301906..fc43324a906 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -31,7 +31,7 @@ var KanbanController = BasicController.extend({ kanban_column_delete: '_onDeleteColumn', kanban_column_add_record: '_onAddRecordToColumn', kanban_column_resequence: '_onColumnResequence', - kanban_load_more: '_onLoadMore', + kanban_load_column_records: '_onLoadColumnRecords', column_toggle_fold: '_onToggleColumn', kanban_column_records_toggle_active: '_onToggleActiveRecords', }), @@ -389,14 +389,15 @@ var KanbanController = BasicController.extend({ /** * @private * @param {OdooEvent} ev + * @param {Object} ev.data see model.reload options */ - _onLoadMore: function (ev) { - var self = this; - var column = ev.target; - this.model.loadMore(column.db_id).then(function (db_id) { - var data = self.model.get(db_id); - self.renderer.updateColumn(db_id, data); - }); + async _onLoadColumnRecords(ev) { + const column = ev.target; + const id = column.columnID || column.db_id; + const options = ev.data; + const dbID = await this.model.reload(id, options); + const data = this.model.get(dbID); + return this.renderer.updateColumn(dbID, data); }, /** * @private @@ -520,9 +521,11 @@ var KanbanController = BasicController.extend({ this.model.actionArchive(recordIds, column.db_id) : this.model.actionUnarchive(recordIds, column.db_id); prom.then(function (dbID) { - var data = self.model.get(dbID); + let data = self.model.get(dbID); if (data) { // Could be null if a wizard is returned for example self.model.reload(self.handle).then(function () { + // Retrieve fresher data as the reload may have changed it. + data = self.model.get(dbID); const state = self.model.get(self.handle); self.renderer.updateColumn(dbID, data, { state }); }); diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js index 7dcfe4081aa..52c420872f7 100644 --- a/addons/web/static/src/js/views/kanban/kanban_model.js +++ b/addons/web/static/src/js/views/kanban/kanban_model.js @@ -143,8 +143,10 @@ var KanbanModel = BasicModel.extend({ * Add the following (kanban specific) keys when performing a `get`: * * - tooltipData - * - progressBarValues * - isGroupedByM2ONoColumn + * - progressBarValues + * - loadMoreCount + * - loadMoreOffset * * @override * @see _readTooltipFields @@ -154,18 +156,47 @@ var KanbanModel = BasicModel.extend({ var result = this._super.apply(this, arguments); var dp = result && this.localData[result.id]; if (dp) { + // Add tooltipData key if (dp.tooltipData) { result.tooltipData = $.extend(true, {}, dp.tooltipData); } - if (dp.progressBarValues) { - result.progressBarValues = $.extend(true, {}, dp.progressBarValues); - } + // Add isGroupedByM2ONoColumn key if (dp.fields[dp.groupedBy[0]]) { var groupedByM2O = dp.fields[dp.groupedBy[0]].type === 'many2one'; result.isGroupedByM2ONoColumn = !dp.data.length && groupedByM2O; } else { result.isGroupedByM2ONoColumn = false; } + // Add progressBarValues, loadMoreCount and loadMoreOffset key + let loadMoreCount = result.count - result.data.length; + let loadMoreOffset = result.data.length; + if (dp.progressBarValues) { + result.progressBarValues = $.extend(true, {}, dp.progressBarValues); + if (dp.activeFilter && dp.activeFilter.value) { + // A progressbar filter is in an activated state? + // Then set loadMoreCount and loadMoreOffset accordingly. + // These computations are needed because there might be + // records that doesn't match the current filter, e.g.: + // - newly created records + // - records dragged in the column + const barValues = dp.progressBarValues; + const barField = barValues.field; + const definedBarFieldValues = Object.keys(barValues.colors); + const filterValue = dp.activeFilter.value; + + const filteredRecordsTotal = barValues.counts[filterValue]; + const filteredRecords = result.data.filter(element => { + const elementBarFieldValue = element.data[barField]; + return (filterValue === elementBarFieldValue) + || (filterValue === '__false' + && !definedBarFieldValues.includes(elementBarFieldValue)); + }); + loadMoreCount = filteredRecordsTotal - filteredRecords.length; + loadMoreOffset = filteredRecords.length; + } + } + result.loadMoreCount = loadMoreCount; + result.loadMoreOffset = loadMoreOffset; } return result; }, @@ -190,19 +221,6 @@ var KanbanModel = BasicModel.extend({ params.groupedBy = (params.groupedBy && params.groupedBy.length) ? params.groupedBy : this.defaultGroupedBy; return this._super(params); }, - /** - * Load more records in a group. - * - * @param {string} groupID localID of the group - * @returns {Promise} resolves to the localID of the group - */ - loadMore: function (groupID) { - var group = this.localData[groupID]; - var offset = group.loadMoreOffset + group.limit; - return this.reload(group.id, { - loadMoreOffset: offset, - }); - }, /** * Moves a record from a group to another. * @@ -262,8 +280,24 @@ var KanbanModel = BasicModel.extend({ }, /** * @override + * @param {Object} options.activeFilter */ reload: function (id, options) { + const element = this.localData[id]; + // Reset the limit right before reloading a group as a reload + // of a kanban view may update the limit of a group. @see BasicModel._readGroup() + // (e.g. if we are coming back to the kanban view from a form view) + // As this mechanism may only affect grouped kanban views, only reset + // the limit if the current element is a group (and thus, has a parent). + if (element.parentID) { + element.limit = this.loadParams.limit; + } + // Register the domain extension in the element. + if (options && options.activeFilter) { + element.activeFilter = options.activeFilter || element.activeFilter; + // Cleanup as this option is not used further + delete options.activeFilter; + } // if the groupBy is given in the options and if it is an empty array, // fallback on the default groupBy if (options && options.groupBy && !options.groupBy.length) { @@ -293,6 +327,23 @@ var KanbanModel = BasicModel.extend({ // Private //-------------------------------------------------------------------------- + /** + * @override + */ + _getGroupedListPropsToKeep(list, options) { + const propsToKeep = this._super(...arguments); + if (list.activeFilter) { + propsToKeep.activeFilter = list.activeFilter; + } + return propsToKeep; + }, + /** + * @override + */ + _getUngroupedListDomain(list) { + const domainExtension = (list.activeFilter && list.activeFilter.domain) || []; + return [...this._super(...arguments), ...domainExtension]; + }, /** * @override */ @@ -334,10 +385,36 @@ var KanbanModel = BasicModel.extend({ * @param {Object} dataPoint * @returns {Promise} */ - _readProgressBarGroup: function (list, options) { - var self = this; - var groupsDef = this._readGroup(list, options); - var progressBarDef = this._rpc({ + async _readProgressBarGroup(list, options) { + const groupsDef = this._readGroup(list, options); + const progressBarDef = this._readProgressBar(list); + const [groups, progressBar] = await Promise.all([groupsDef, progressBarDef]); + list.data.forEach(groupId => { + const group = this.localData[groupId]; + + const valuesCount = progressBar[group.value] || {}; + const valuesCountTotal = Object.keys(valuesCount).reduce((sum, key) => { + return sum + valuesCount[key]; + }, 0); + + // Compute records count for progressbar field values + // not specified in the progressbar attributes + const counts = Object.assign({ + __false: group.count - valuesCountTotal + }, valuesCount); + + group.progressBarValues = Object.assign({ + counts, + }, list.progressBar); + }); + return list; + }, + /** + * @param {Object} list valid resource object + * @returns {Promise} + */ + _readProgressBar: function (list) { + return this._rpc({ model: list.model, method: 'read_progress_bar', kwargs: { @@ -347,16 +424,6 @@ var KanbanModel = BasicModel.extend({ context: list.context, }, }); - return Promise.all([groupsDef, progressBarDef]).then(function (results) { - var data = results[1]; - _.each(list.data, function (groupID) { - var group = self.localData[groupID]; - group.progressBarValues = _.extend({ - counts: data[group.value] || {}, - }, list.progressBar); - }); - return list; - }); }, /** * Fetches tooltip specific fields on the group by relation and stores it in @@ -407,34 +474,37 @@ var KanbanModel = BasicModel.extend({ }, /** * Reloads all progressbar data. This is done after given promise and - * insures that the given promise's result is not lost. + * ensures that the given promise's result is not lost. * * @private * @param {string} recordID * @param {Promise} def * @returns {Promise} */ - _reloadProgressBarGroupFromRecord: function (recordID, def) { - var element = this.localData[recordID]; - if (element.type === 'list' && !element.parentID) { - // we are reloading the whole view, so there is no need to manually - // reload the progressbars - return def; - } - + async _reloadProgressBarGroupFromRecord(recordID, def) { + let element = this.localData[recordID]; + if (element.type === 'list') { + if (!element.parentID) { + // we are reloading the whole view, so there is no need to manually + // reload the progressbars + return def; + } + if (element.activeFilter) { + // We must not read_group when an active filter (and thus + // a domain extension) is applied to the list datapoint. + return def; + } + } // If we updated a record, then we must potentially update columns' // progressbars, so we need to load groups info again - var self = this; while (element) { if (element.progressBar) { - return def.then(function (data) { - return self._load(element, { - keepEmptyGroups: true, - onlyGroups: true, - }).then(function () { - return data; - }); + const data = await def; + await this._load(element, { + keepEmptyGroups: true, + onlyGroups: true, }); + return data; } element = this.localData[element.parentID]; } diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml index 2fd7f8ca211..7678f124c6b 100644 --- a/addons/web/static/src/xml/kanban.xml +++ b/addons/web/static/src/xml/kanban.xml @@ -32,14 +32,14 @@ -
+
- Load more... ( remaining) + Load more... ( remaining) diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index d483bdc8418..df56a7024b1 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -5937,6 +5937,50 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('column progressbars with an active filter are working with load more', async function (assert) { + assert.expect(2); + + this.data.partner.records.push( + { id: 5, bar: true, foo: "blork" }, + { id: 6, bar: true, foo: "blork" }, + { id: 7, bar: true, foo: "blork" } + ); + + const kanban = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + domain: [['bar', '=', true]], + arch: + ` + + + +
+
+
`, + groupBy: ['bar'], + }); + + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_counter_progress .progress-bar[data-filter="blork"]')); + + // we should have 1 record shown + assert.deepEqual( + [...kanban.el.querySelectorAll('.o_kanban_record')].map(el => parseInt(el.innerText)), + [5] + ); + + // load 2 more and check it worked + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group .o_kanban_load_more')); + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group .o_kanban_load_more')); + assert.deepEqual( + [...kanban.el.querySelectorAll('.o_kanban_record')].map(el => parseInt(el.innerText)), + [5, 6, 7] + ); + + kanban.destroy(); + }); + QUnit.test('column progressbars on archiving records update counter', async function (assert) { assert.expect(4); @@ -6088,6 +6132,54 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('RPCs when (de)activating kanban view progressbar filters', async function (assert) { + assert.expect(8); + + const kanban = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: ` + + + + + +
+
+
+ `, + groupBy: ['bar'], + mockRPC(route, args) { + assert.step(args.method || route); + return this._super.apply(this, arguments); + }, + }); + + // Activate "yop" on second column + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group:nth-child(2) .progress-bar[data-filter="yop"]')); + // Activate "gnap" on second column + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group:nth-child(2) .progress-bar[data-filter="gnap"]')); + // Deactivate "gnap" on second column + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group:nth-child(2) .progress-bar[data-filter="gnap"]')); + + assert.verifySteps([ + // initial load + 'web_read_group', + 'read_progress_bar', + '/web/dataset/search_read', + '/web/dataset/search_read', + // activate filter + '/web/dataset/search_read', + // activate another filter (switching) + '/web/dataset/search_read', + // deactivate active filter + '/web/dataset/search_read', + ]); + + kanban.destroy(); + }); + QUnit.test('drag & drop records grouped by m2o with progressbar', async function (assert) { assert.expect(4); @@ -6139,34 +6231,152 @@ QUnit.module('Views', { QUnit.test('progress bar subgroup count recompute', async function (assert) { assert.expect(2); - var kanban = await createView({ + const kanban = await createView({ View: KanbanView, model: 'partner', data: this.data, arch: - '' + - '' + - '' + - '
' + - '' + - '
' + - '
' + - '
', + ` + + +
+ +
+
+
`, groupBy: ['bar'], }); - var $secondGroup = kanban.$('.o_kanban_group:eq(1)'); - var initialCount = parseInt($secondGroup.find('.o_kanban_counter_side').text()); - assert.strictEqual(initialCount, 3, + let secondCounter = kanban.el.querySelector('.o_kanban_group:nth-child(2) .o_kanban_counter_side'); + assert.strictEqual(parseInt(secondCounter.innerText), 3, "Initial count should be Three"); - await testUtils.dom.click($secondGroup.find('.bg-success-full')); - var lastCount = parseInt($secondGroup.find('.o_kanban_counter_side').text()); - assert.strictEqual(lastCount, 1, + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group:nth-child(2) .bg-success-full')); + + secondCounter = kanban.el.querySelector('.o_kanban_group:nth-child(2) .o_kanban_counter_side'); + assert.strictEqual(parseInt(secondCounter.innerText), 1, "kanban counters should vary according to what subgroup is selected"); kanban.destroy(); }); + QUnit.test('progress bar recompute after drag&drop to and from other column', async function (assert) { + assert.expect(4); + + const view = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: + ` + + +
+ +
+
+
`, + groupBy: ['bar'], + }); + + assert.deepEqual( + [...view.el.querySelectorAll('.progress-bar')].map(el => el.getAttribute('data-original-title')), + ['0 yop', '0 gnap', '1 blip', '0 __false', '1 yop', '1 gnap', '1 blip', '0 __false'] + ); + + assert.deepEqual( + [...view.el.querySelectorAll('.o_kanban_counter_side')].map(el => parseInt(el.innerText)), + [1, 3] + ); + + // Drag the last kanban record to the first column + await testUtils.dom.dragAndDrop( + [...view.el.querySelectorAll('.o_kanban_record')].pop(), + [...view.el.querySelectorAll('.o_kanban_group')].shift() + ); + + assert.deepEqual( + [...view.el.querySelectorAll('.progress-bar')].map(el => el.getAttribute('data-original-title')), + ['0 yop', '1 gnap', '1 blip', '0 __false', '1 yop', '0 gnap', '1 blip', '0 __false'] + ); + + assert.deepEqual( + [...view.el.querySelectorAll('.o_kanban_counter_side')].map(el => parseInt(el.innerText)), + [2, 2] + ); + + view.destroy(); + }); + + QUnit.test('load more should load correct records after drag&drop event', async function (assert) { + assert.expect(3); + + // Add a sequence number and initialize + this.data.partner.fields = Object.assign(this.data.partner.fields, { + sequence: { type: 'integer' } + }); + this.data.partner.records.forEach((el, i) => { + el.sequence = i; + }); + + const view = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: + ` + + + + +
+ +
+
+
`, + groupBy: ['bar'], + favoriteFilters: [ + { + domain: '[]', + is_default: true, + sort: '["sequence asc"]', + }, + ], + }); + + assert.deepEqual( + [...view.el.querySelectorAll('.o_kanban_group:nth-child(1) .o_kanban_record span')] + .map(el => parseInt(el.innerText))[0], + 4, + "first column's first record must be id 4" + ); + + assert.deepEqual( + [...view.el.querySelectorAll('.o_kanban_group:nth-child(2) .o_kanban_record span')] + .map(el => parseInt(el.innerText)), + [1], + "second column's records should be only the id 1" + ); + + // Drag the first kanban record on top of the last + await testUtils.dom.dragAndDrop( + [...view.el.querySelectorAll('.o_kanban_record')].shift(), + [...view.el.querySelectorAll('.o_kanban_record')].pop(), + { position: 'top' } + ); + + // load more twice to load all records of second column + await testUtils.dom.click(view.el.querySelector('.o_kanban_group:nth-child(2) .o_kanban_load_more')); + await testUtils.dom.click(view.el.querySelector('.o_kanban_group:nth-child(2) .o_kanban_load_more')); + + // Check records of the second column + assert.deepEqual( + [...view.el.querySelectorAll('.o_kanban_group:nth-child(2) .o_kanban_record span')].map(el => parseInt(el.innerText)), + [4, 1, 2, 3] + ); + + view.destroy(); + }); + QUnit.test('column progressbars on quick create with quick_create_view are updated', async function (assert) { assert.expect(1); @@ -6206,6 +6416,61 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('column progressbars and active filter on quick create with quick_create_view are updated', async function (assert) { + assert.expect(2); + + const kanban = await createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: ` + + + + + +
+
+
+ `, + archs: { + 'partner,some_view_ref,form': ` +
+ + + + `, + }, + groupBy: ['bar'], + }); + + await testUtils.dom.click(kanban.el.querySelector('.o_kanban_group:nth-child(1) .progress-bar[data-filter="blip"]')); + const initialCount = parseInt(kanban.el.querySelector('.o_kanban_group:nth-child(1) .o_kanban_counter_side').innerText); + assert.strictEqual(initialCount, -4, "Initial count should be -4"); + + // open the quick create + await testUtils.kanban.clickCreate(kanban); + + // fill it with a record that satisfies the activated filter + let quickCreate = kanban.el.querySelector('.o_kanban_group:nth-child(1) .o_kanban_quick_create'); + await testUtils.fields.editInput(quickCreate.querySelector('.o_field_widget[name="int_field"]'), '44'); + await testUtils.fields.editInput(quickCreate.querySelector('.o_field_widget[name="foo"]'), 'blip'); + await testUtils.dom.click(quickCreate.querySelector('button.o_kanban_add')); + + // fill it again with another record that DOES NOT satisfies the activated filter + quickCreate = kanban.el.querySelector('.o_kanban_group:nth-child(1) .o_kanban_quick_create'); + await testUtils.fields.editInput(quickCreate.querySelector('.o_field_widget[name="int_field"]'), '1000'); + await testUtils.fields.editInput(quickCreate.querySelector('.o_field_widget[name="foo"]'), 'yop'); + await testUtils.dom.click(quickCreate.querySelector('button.o_kanban_add')); + + // check counter + const lastCount = parseInt(kanban.el.querySelector('.o_kanban_group:nth-child(1) .o_kanban_counter_side').innerText); + assert.strictEqual(lastCount, initialCount + 44, + "kanban counters should have been updated on quick create, respecting the activated filter"); + + kanban.destroy(); + }); + QUnit.test('keep adding quickcreate in first column after a record from this column was moved', async function (assert) { assert.expect(2);