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 e66601816c2..5dfcbce01c8 100644
--- a/addons/web/static/src/js/views/kanban/kanban_column.js
+++ b/addons/web/static/src/js/views/kanban/kanban_column.js
@@ -27,6 +27,8 @@ var KanbanColumn = Widget.extend({
'click .o_kanban_quick_add': '_onAddQuickCreate',
'click .o_kanban_load_more': '_onLoadMore',
'click .o_kanban_toggle_fold': '_onToggleFold',
+ 'click .o_column_archive_records': '_onArchiveRecords',
+ 'click .o_column_unarchive_records': '_onUnarchiveRecords'
},
/**
* @override
@@ -355,6 +357,28 @@ var KanbanColumn = Widget.extend({
ev.data.callback(record.$el, record.state.data);
});
},
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onArchiveRecords: function (event) {
+ event.preventDefault();
+ Dialog.confirm(this, _t("Are you sure that you want to archive all the records from this column?"), {
+ confirm_callback: this.trigger_up.bind(this, 'kanban_column_records_toggle_active', {
+ archive: true,
+ }),
+ });
+ },
+ /**
+ * @private
+ * @param {MouseEvent} event
+ */
+ _onUnarchiveRecords: function (event) {
+ event.preventDefault();
+ this.trigger_up('kanban_column_records_toggle_active', {
+ archive: false,
+ });
+ }
});
return KanbanColumn;
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 986fff3a53e..86f1cb72589 100644
--- a/addons/web/static/src/js/views/kanban/kanban_controller.js
+++ b/addons/web/static/src/js/views/kanban/kanban_controller.js
@@ -30,6 +30,7 @@ var KanbanController = BasicController.extend({
kanban_load_more: '_onLoadMore',
kanban_load_records: '_onLoadColumnRecords',
column_toggle_fold: '_onToggleColumn',
+ kanban_column_records_toggle_active: '_onToggleActiveRecords',
}),
/**
* @override
@@ -443,6 +444,27 @@ var KanbanController = BasicController.extend({
ev.data.force_save = true;
this._applyChanges(ev.target.db_id, changes, ev);
},
+ /**
+ * Allow the user to archive/restore all the records of a column.
+ *
+ * @private
+ * @param {OdooEvent} event
+ */
+ _onToggleActiveRecords: function (event) {
+ var self = this;
+ var active = !event.data.archive;
+ var column = event.target;
+ var recordIds = _.pluck(column.records, 'db_id');
+ if (recordIds.length) {
+ this.model
+ .toggleActive(recordIds, active, column.db_id)
+ .then(function (dbID) {
+ var data = self.model.get(dbID);
+ self.renderer.updateColumn(dbID, data);
+ self._updateEnv();
+ });
+ }
+ },
});
return KanbanController;
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 b42da9665ad..ae1a8f7305b 100644
--- a/addons/web/static/src/js/views/list/list_controller.js
+++ b/addons/web/static/src/js/views/list/list_controller.js
@@ -10,6 +10,7 @@ odoo.define('web.ListController', function (require) {
var core = require('web.core');
var BasicController = require('web.BasicController');
var DataExport = require('web.DataExport');
+var Dialog = require('web.Dialog');
var pyeval = require('web.pyeval');
var Sidebar = require('web.Sidebar');
@@ -136,6 +137,7 @@ var ListController = BasicController.extend({
* @param {jQuery Node} $node
*/
renderSidebar: function ($node) {
+ var self = this;
if (this.hasSidebar) {
var other = [{
label: _t("Export"),
@@ -144,7 +146,11 @@ var ListController = BasicController.extend({
if (this.archiveEnabled) {
other.push({
label: _t("Archive"),
- callback: this._onToggleArchiveState.bind(this, true)
+ callback: function () {
+ Dialog.confirm(self, _t("Are you sure that you want to archive all the selected records?"), {
+ confirm_callback: self._onToggleArchiveState.bind(self, true),
+ });
+ }
});
other.push({
label: _t("Unarchive"),
diff --git a/addons/web/static/src/xml/kanban.xml b/addons/web/static/src/xml/kanban.xml
index 23af895b8ea..9c3fac6574a 100644
--- a/addons/web/static/src/xml/kanban.xml
+++ b/addons/web/static/src/xml/kanban.xml
@@ -22,6 +22,10 @@
Edit Stage
Delete
+
+ Archive All
+ Restore All
+
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index c5e5f606f61..04003c568a3 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -97,7 +97,7 @@ QUnit.module('Views', {
});
QUnit.test('basic grouped rendering', function (assert) {
- assert.expect(11);
+ assert.expect(13);
var kanban = createView({
View: KanbanView,
@@ -135,6 +135,8 @@ QUnit.module('Views', {
"should not be able to edit the column");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_delete').length,
"should not be able to delete the column");
+ assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, "should not be able to archive all the records");
+ assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should not be able to restore all the records");
// the next line makes sure that reload works properly. It looks useless,
// but it actually test that a grouped local record can be reloaded without
@@ -145,6 +147,51 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('basic grouped rendering with active field', function (assert) {
+ assert.expect(9);
+
+ // add active field on partner model and make all records active
+ this.data.partner.fields.active = {string: 'Active', type: 'char', default: true};
+
+ var envIDs = [1, 2, 3, 4]; // the ids that should be in the environment during this test
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '' +
+ '' +
+ '' +
+ '' +
+ '
' +
+ '',
+ groupBy: ['bar'],
+ intercepts: {
+ env_updated: function (event) {
+ assert.deepEqual(event.data.env.ids, envIDs,
+ "should notify the environment with the correct ids");
+ },
+ },
+ });
+
+ // check archive/restore all actions in kanban header's config dropdown
+ assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, "should be able to archive all the records");
+ assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should be able to restore all the records");
+
+ // archive the records of the first column
+ assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3,
+ "last column should contain 3 records");
+ envIDs = [4];
+ kanban.$('.o_kanban_group:last .o_column_archive_records').click(); // Click on 'Archive All'
+ assert.ok($('.modal').length, 'a confirm modal should be displayed');
+ $('.modal .modal-footer .btn-default').click(); // Click on 'Cancel'
+ assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, "still last column should contain 3 records");
+ kanban.$('.o_kanban_group:last .o_column_archive_records').click();
+ assert.ok($('.modal').length, 'a confirm modal should be displayed');
+ $('.modal .modal-footer .btn-primary').click(); // Click on 'Ok'
+ assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0, "last column should not contain any records");
+ kanban.destroy();
+ });
+
QUnit.test('pager should be hidden in grouped mode', function (assert) {
assert.expect(1);
@@ -1684,7 +1731,7 @@ QUnit.module('Views', {
});
QUnit.test('delete a column in grouped on m2o', function (assert) {
- assert.expect(29);
+ assert.expect(33);
testUtils.patch(KanbanRenderer, {
_renderGrouped: function () {
@@ -1741,6 +1788,8 @@ QUnit.module('Views', {
"should be able to edit the column");
assert.ok(kanban.$('.o_kanban_group:first .o_column_delete').length,
"should be able to delete the column");
+ assert.ok(!kanban.$('.o_kanban_group:first .o_column_archive_records').length, "should not be able to archive all the records");
+ assert.ok(!kanban.$('.o_kanban_group:first .o_column_unarchive_records').length, "should not be able to restore all the records");
// delete second column (first cancel the confirm request, then confirm)
kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete
@@ -1763,6 +1812,8 @@ QUnit.module('Views', {
'Undefined column could not be deleted');
assert.ok(!kanban.$('.o_kanban_group:first .o_column_edit').length,
'Undefined column could not be edited');
+ assert.ok(!kanban.$('.o_kanban_group:first .o_column_archive_records').length, "Records of undefined column could not be archived");
+ assert.ok(!kanban.$('.o_kanban_group:first .o_column_unarchive_records').length, "Records of undefined column could not be restored");
assert.verifySteps(['read_group', 'unlink', 'read_group']);
assert.strictEqual(kanban.renderer.widgets.length, 2,
"the old widgets should have been correctly deleted");
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index fd2f77f068d..c948528dcc6 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -843,7 +843,7 @@ QUnit.module('Views', {
});
QUnit.test('archiving one record', function (assert) {
- assert.expect(9);
+ assert.expect(12);
// add active field on foo model and make all records active
this.data.foo.fields.active = {string: 'Active', type: 'boolean', default: true};
@@ -872,7 +872,13 @@ QUnit.module('Views', {
assert.verifySteps(['/web/dataset/search_read']);
list.sidebar.$('a:contains(Archive)').click();
+ assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
+ $('.modal .modal-footer .btn-default').click(); // Click on 'Cancel'
+ assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 4, "still should have 4 records");
+ list.sidebar.$('a:contains(Archive)').click();
+ assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
+ $('.modal .modal-footer .btn-primary').click(); // Click on 'Ok'
assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 3, "should have 3 records");
assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/write', '/web/dataset/search_read']);
list.destroy();