[IMP] web,various: Add 'Remove' button to view dialogs opened from x2m fields
Currently, to remove link of x2m field from any record, sometimes there's no way. For example, if we are on mobile and open any Quotation, it's linked quotation lines are automatically converted in kanban, and there is no way to delete a line from that quotation. However, in some of the manually designed kanban, there is special 'x' for removing / unlinking x2m record, for example, Contacts of Partner. This commit makes the behavior more consistent. During edition (mobile and desktop), if a view dialog is opened on click of x2m field, it will have one 'Remove' button (based on user rights) on right side of dialog footer, allowing users to delete / unlink the record. Moreover, in mobile, the modal is opened fullscreen, with sticky header and footer. Related Task# : 31641 Closes PR #15857 Co-authored-by: Mohammed Shekha <msh@openerp.com>
This commit is contained in:
committed by
Aaron Bohy
co-authored by
Mohammed Shekha
parent
858893494f
commit
a105e5f208
@@ -19,13 +19,12 @@
|
||||
</div>
|
||||
<notebook>
|
||||
<page string="Vendors" name="vendors">
|
||||
<field name="vendors" widget="many2many_kanban">
|
||||
<field name="vendors">
|
||||
<kanban quick_create="false" create="true">
|
||||
<field name="name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div style="position: relative">
|
||||
<a t-if="! read_only_mode" type="delete" style="position: absolute; right: 0; padding: 4px; diplay: inline-block" aria-label="Delete" title="Delete"><i class="fa fa-times text-danger"/></a>
|
||||
<div style="position: relative" class="oe_kanban_global_click">
|
||||
<div class="oe_module_vignette">
|
||||
<div class="oe_module_desc o_kanban_record_title">
|
||||
<field name="name"/>
|
||||
|
||||
@@ -105,8 +105,7 @@
|
||||
<field name="name"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div>
|
||||
<a t-if="!read_only_mode" type="delete" class="fa fa-times float-right" aria-label="Delete" title="Delete"/>
|
||||
<div class="oe_kanban_global_click">
|
||||
<div class="o_kanban_image">
|
||||
<img t-att-src="kanban_image('res.users', 'image', record.id.raw_value)" alt="User"/>
|
||||
</div>
|
||||
|
||||
@@ -81,9 +81,6 @@
|
||||
<div class="o_kanban_record_headings ml8">
|
||||
<strong class="o_kanban_record_title"><field name="name"/></strong>
|
||||
</div>
|
||||
<a t-if="! read_only_mode" type="delete" class="text-danger" aria-label="Delete" title="Delete">
|
||||
<i class="fa fa-times"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -31,6 +31,8 @@ var Dialog = Widget.extend({
|
||||
* @param {string} [options.title=Odoo]
|
||||
* @param {string} [options.subtitle]
|
||||
* @param {string} [options.size=large] - 'large', 'medium' or 'small'
|
||||
* @param {boolean} [options.fullscreen=false] - whether or not the dialog
|
||||
* should be open in fullscreen mode (the main usecase is mobile)
|
||||
* @param {string} [options.dialogClass] - class to add to the modal-body
|
||||
* @param {jQuery} [options.$content]
|
||||
* Element which will be the $el, replace the .modal-body and get the
|
||||
@@ -56,6 +58,7 @@ var Dialog = Widget.extend({
|
||||
options = _.defaults(options || {}, {
|
||||
title: _t('Odoo'), subtitle: '',
|
||||
size: 'large',
|
||||
fullscreen: true,
|
||||
dialogClass: '',
|
||||
$content: false,
|
||||
buttons: [{text: _t("Ok"), close: true}],
|
||||
@@ -65,6 +68,7 @@ var Dialog = Widget.extend({
|
||||
this.$content = options.$content;
|
||||
this.title = options.title;
|
||||
this.subtitle = options.subtitle;
|
||||
this.fullscreen = options.fullscreen;
|
||||
this.dialogClass = options.dialogClass;
|
||||
this.size = options.size;
|
||||
this.buttons = options.buttons;
|
||||
@@ -81,6 +85,7 @@ var Dialog = Widget.extend({
|
||||
return this._super.apply(this, arguments).then(function () {
|
||||
// Render modal once xml dependencies are loaded
|
||||
self.$modal = $(QWeb.render('Dialog', {
|
||||
fullscreen: self.fullscreen,
|
||||
title: self.title,
|
||||
subtitle: self.subtitle,
|
||||
technical: self.technical,
|
||||
|
||||
@@ -1315,6 +1315,7 @@ var FieldOne2Many = FieldX2Many.extend({
|
||||
fields_view: this.attrs.views && this.attrs.views.form,
|
||||
parentID: this.value.id,
|
||||
viewInfo: this.view,
|
||||
deletable: this.activeActions.delete,
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -1375,9 +1376,9 @@ var FieldOne2Many = FieldX2Many.extend({
|
||||
*/
|
||||
_onOpenRecord: function (ev) {
|
||||
// we don't want interference with the components upstream.
|
||||
var self = this;
|
||||
ev.stopPropagation();
|
||||
|
||||
var self = this;
|
||||
var id = ev.data.id;
|
||||
var onSaved = function (record) {
|
||||
if (_.some(self.value.data, {id: record.id})) {
|
||||
@@ -1398,6 +1399,10 @@ var FieldOne2Many = FieldX2Many.extend({
|
||||
this._openFormDialog({
|
||||
id: id,
|
||||
on_saved: onSaved,
|
||||
on_remove: function () {
|
||||
self._setValue({operation: 'DELETE', ids: [id]});
|
||||
},
|
||||
deletable: this.activeActions.delete,
|
||||
readonly: this.mode === 'readonly',
|
||||
});
|
||||
},
|
||||
@@ -1464,7 +1469,11 @@ var FieldMany2Many = FieldX2Many.extend({
|
||||
self._setValue({operation: 'TRIGGER_ONCHANGE'}, {forceChange: true});
|
||||
self.trigger_up('reload', {db_id: ev.data.id});
|
||||
},
|
||||
on_remove: function () {
|
||||
self._setValue({operation: 'FORGET', ids: [ev.data.id]});
|
||||
},
|
||||
readonly: this.mode === 'readonly',
|
||||
deletable: this.activeActions.delete,
|
||||
string: this.string,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -597,8 +597,10 @@ var FormController = BasicController.extend({
|
||||
fields_view: data.fields_view,
|
||||
model: this.model,
|
||||
on_saved: data.on_saved,
|
||||
on_remove: data.on_remove,
|
||||
parentID: data.parentID,
|
||||
readonly: data.readonly,
|
||||
deletable: data.deletable,
|
||||
recordID: record && record.id,
|
||||
res_id: record && record.res_id,
|
||||
res_model: data.field.relation,
|
||||
@@ -620,7 +622,9 @@ var FormController = BasicController.extend({
|
||||
context: event.data.context,
|
||||
fields_view: event.data.fields_view,
|
||||
on_saved: event.data.on_saved,
|
||||
on_remove: event.data.on_remove,
|
||||
readonly: event.data.readonly,
|
||||
deletable: event.data.deletable,
|
||||
res_id: record.res_id,
|
||||
res_model: record.model,
|
||||
title: _t("Open: ") + event.data.string,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
odoo.define('web.view_dialogs', function (require) {
|
||||
"use strict";
|
||||
|
||||
var config = require('web.config');
|
||||
var core = require('web.core');
|
||||
var data = require('web.data');
|
||||
var Dialog = require('web.Dialog');
|
||||
@@ -35,6 +36,7 @@ var ViewDialog = Dialog.extend({
|
||||
*/
|
||||
init: function (parent, options) {
|
||||
options = options || {};
|
||||
options.fullscreen = config.device.isMobile;
|
||||
options.dialogClass = options.dialogClass || '' + ' o_act_window';
|
||||
|
||||
this._super(parent, $.extend(true, {}, options));
|
||||
@@ -81,9 +83,15 @@ var FormViewDialog = ViewDialog.extend({
|
||||
* @param {Object} [options.fields_view] optional form fields_view
|
||||
* @param {boolean} [options.readonly=false] only applicable when not in
|
||||
* creation mode
|
||||
* @param {boolean} [options.deletable=false] whether or not the record can
|
||||
* be deleted
|
||||
* @param {boolean} [options.disable_multiple_selection=false] set to true
|
||||
* to remove the possibility to create several records in a row
|
||||
* @param {function} [options.on_saved] callback executed after saving a
|
||||
* record. It will be called with the record data, and a boolean which
|
||||
* indicates if something was changed
|
||||
* @param {function} [options.on_remove] callback executed when the user
|
||||
* clicks on the 'Remove' button
|
||||
* @param {BasicModel} [options.model] if given, it will be used instead of
|
||||
* a new form view model
|
||||
* @param {string} [options.recordID] if given, the model has to be given as
|
||||
@@ -93,20 +101,24 @@ var FormViewDialog = ViewDialog.extend({
|
||||
*/
|
||||
init: function (parent, options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
|
||||
this.res_id = options.res_id || null;
|
||||
this.on_saved = options.on_saved || (function () {});
|
||||
this.on_remove = options.on_remove || (function () {});
|
||||
this.context = options.context;
|
||||
this.model = options.model;
|
||||
this.parentID = options.parentID;
|
||||
this.recordID = options.recordID;
|
||||
this.shouldSaveLocally = options.shouldSaveLocally;
|
||||
this.readonly = options.readonly;
|
||||
this.deletable = options.deletable;
|
||||
this.disable_multiple_selection = options.disable_multiple_selection;
|
||||
|
||||
var multi_select = !_.isNumber(options.res_id) && !options.disable_multiple_selection;
|
||||
var readonly = _.isNumber(options.res_id) && options.readonly;
|
||||
|
||||
if (!options || !options.buttons) {
|
||||
options = options || {};
|
||||
if (!options.buttons) {
|
||||
options.buttons = [{
|
||||
text: (readonly ? _t("Close") : _t("Discard")),
|
||||
classes: "btn-secondary o_form_button_cancel",
|
||||
@@ -138,6 +150,15 @@ var FormViewDialog = ViewDialog.extend({
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
var multi = options.disable_multiple_selection;
|
||||
if (!multi && this.deletable) {
|
||||
options.buttons.push({
|
||||
text: _t("Remove"),
|
||||
classes: 'btn-secondary o_btn_remove',
|
||||
click: this._remove.bind(this),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
this._super(parent, options);
|
||||
@@ -209,6 +230,7 @@ var FormViewDialog = ViewDialog.extend({
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
@@ -216,13 +238,26 @@ var FormViewDialog = ViewDialog.extend({
|
||||
this.trigger_up('form_dialog_discarded');
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_remove: function () {
|
||||
this.on_remove();
|
||||
this.close();
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @returns {Deferred}
|
||||
*/
|
||||
_save: function () {
|
||||
var self = this;
|
||||
return this.form_view.saveRecord(this.form_view.handle, {
|
||||
stayInEdit: true,
|
||||
reload: false,
|
||||
savePoint: this.shouldSaveLocally,
|
||||
viewType: 'form',
|
||||
stayInEdit: true,
|
||||
reload: false,
|
||||
savePoint: this.shouldSaveLocally,
|
||||
viewType: 'form',
|
||||
}).then(function (changedFields) {
|
||||
// record might have been changed by the save (e.g. if this was a new record, it has an
|
||||
// id now), so don't re-use the copy obtained before the save
|
||||
|
||||
@@ -83,6 +83,32 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
&.o_modal_full {
|
||||
.modal-dialog {
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
|
||||
.modal-content {
|
||||
height: 100%;
|
||||
border: none;
|
||||
|
||||
.modal-header {
|
||||
background: $o-brand-odoo;
|
||||
.modal-title, .o_subtitle, button.close {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Temporary fix for modals which are not instantiated thanks to the Dialog
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
<!-- These templates are accessible in backend and frontend -->
|
||||
|
||||
<div role="dialog" t-name="Dialog" t-attf-class="modal#{technical ? ' o_technical_modal' : ''}" tabindex="-1" data-backdrop="static" t-att-id="_.uniqueId('modal_')" aria-hidden="true">
|
||||
<div role="dialog" t-name="Dialog" t-attf-class="modal#{technical ? ' o_technical_modal' : ''}#{fullscreen ? ' o_modal_full': ''}" tabindex="-1" data-backdrop="static" t-att-id="_.uniqueId('modal_')" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<header class="modal-header">
|
||||
|
||||
@@ -4,6 +4,7 @@ odoo.define('web.relational_fields_tests', function (require) {
|
||||
var AbstractField = require('web.AbstractField');
|
||||
var BasicModel = require('web.BasicModel');
|
||||
var concurrency = require('web.concurrency');
|
||||
var config = require('web.config');
|
||||
var FormView = require('web.FormView');
|
||||
var ListRenderer = require('web.ListRenderer');
|
||||
var ListView = require('web.ListView');
|
||||
@@ -4656,9 +4657,9 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many list: unlink one record', function (assert) {
|
||||
assert.expect(6);
|
||||
this.data.partner.records[0].p = [2, 4];
|
||||
QUnit.test('one2many list: unlink two records', function (assert) {
|
||||
assert.expect(9);
|
||||
this.data.partner.records[0].p = [1, 2, 4];
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
@@ -4674,37 +4675,51 @@ QUnit.module('relational_fields', {
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/call_kw/partner/write') {
|
||||
var commands = args.args[1].p;
|
||||
assert.strictEqual(commands.length, 2,
|
||||
'should have generated two commands');
|
||||
assert.strictEqual(commands.length, 3,
|
||||
'should have generated three commands');
|
||||
assert.ok(commands[0][0] === 4 && commands[0][1] === 4,
|
||||
'should have generated the command 4 (LINK_TO) with id 4');
|
||||
assert.ok(commands[1][0] === 3 && commands[1][1] === 2,
|
||||
assert.ok(commands[1][0] === 3 && commands[1][1] === 1,
|
||||
'should have generated the command 3 (UNLINK) with id 1');
|
||||
assert.ok(commands[2][0] === 3 && commands[2][1] === 2,
|
||||
'should have generated the command 3 (UNLINK) with id 2');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
archs: {
|
||||
'partner,false,form':
|
||||
'<form string="Partner"><field name="display_name"/></form>',
|
||||
},
|
||||
});
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 2,
|
||||
"should have 2 remove buttons");
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 3,
|
||||
"should have 3 remove buttons");
|
||||
|
||||
assert.ok(form.$('td.o_list_record_remove button').first().hasClass('fa fa-times'),
|
||||
"should have X icons to remove (unlink) records");
|
||||
|
||||
form.$('td.o_list_record_remove button').first().click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 2,
|
||||
"should have 2 remove buttons (a record is supposed to have been unlinked)");
|
||||
|
||||
form.$('tr.o_data_row').first().click();
|
||||
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
|
||||
'there should be a modal having Remove Button');
|
||||
$('.modal .modal-footer .o_btn_remove').click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 1,
|
||||
"should have 1 remove button (a record is supposed to have been unlinked)");
|
||||
"should have 1 delete button (another record is supposed to have been unlinked)");
|
||||
|
||||
// save and check that the correct command has been generated
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many list: deleting one record', function (assert) {
|
||||
assert.expect(6);
|
||||
this.data.partner.records[0].p = [2, 4];
|
||||
QUnit.test('one2many list: deleting two records', function (assert) {
|
||||
assert.expect(9);
|
||||
this.data.partner.records[0].p = [1, 2, 4];
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
@@ -4720,28 +4735,42 @@ QUnit.module('relational_fields', {
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/call_kw/partner/write') {
|
||||
var commands = args.args[1].p;
|
||||
assert.strictEqual(commands.length, 2,
|
||||
'should have generated two commands');
|
||||
assert.strictEqual(commands.length, 3,
|
||||
'should have generated three commands');
|
||||
assert.ok(commands[0][0] === 4 && commands[0][1] === 4,
|
||||
'should have generated the command 4 (LINK_TO) with id 4');
|
||||
assert.ok(commands[1][0] === 2 && commands[1][1] === 2,
|
||||
assert.ok(commands[1][0] === 2 && commands[1][1] === 1,
|
||||
'should have generated the command 2 (DELETE) with id 1');
|
||||
assert.ok(commands[2][0] === 2 && commands[2][1] === 2,
|
||||
'should have generated the command 2 (DELETE) with id 2');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
archs: {
|
||||
'partner,false,form':
|
||||
'<form string="Partner"><field name="display_name"/></form>',
|
||||
},
|
||||
});
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 2,
|
||||
"should have 2 remove buttons");
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 3,
|
||||
"should have 3 remove buttons");
|
||||
|
||||
assert.ok(form.$('td.o_list_record_remove button').first().hasClass('fa fa-trash-o'),
|
||||
"should have trash bin icons to remove (delete) records");
|
||||
|
||||
form.$('td.o_list_record_remove button').first().click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 2,
|
||||
"should have 2 remove buttons (a record is supposed to have been deleted)");
|
||||
|
||||
form.$('tr.o_data_row').first().click();
|
||||
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
|
||||
'there should be a modal having Remove Button');
|
||||
$('.modal .modal-footer .o_btn_remove').click();
|
||||
|
||||
assert.strictEqual(form.$('td.o_list_record_remove button').length, 1,
|
||||
"should have 1 remove button (a record is supposed to have been deleted)");
|
||||
"should have 1 remove button (another record is supposed to have been deleted)");
|
||||
|
||||
// save and check that the correct command has been generated
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
@@ -4753,7 +4782,7 @@ QUnit.module('relational_fields', {
|
||||
});
|
||||
|
||||
QUnit.test('one2many kanban: edition', function (assert) {
|
||||
assert.expect(16);
|
||||
assert.expect(17);
|
||||
|
||||
this.data.partner.records[0].p = [2];
|
||||
var form = createView({
|
||||
@@ -4835,7 +4864,10 @@ QUnit.module('relational_fields', {
|
||||
'should contain 4 records');
|
||||
|
||||
// delete subrecords
|
||||
form.$('.o_kanban_view .delete_icon:first()').click();
|
||||
form.$('.oe_kanban_global_click').first().click();
|
||||
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
|
||||
'There should be a modal having Remove Button');
|
||||
$('.modal .modal-footer .o_btn_remove').click(); // Click Remove Button of Formview Dialog
|
||||
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3,
|
||||
'should contain 3 records');
|
||||
form.$('.o_kanban_view .delete_icon:first()').click();
|
||||
@@ -4847,7 +4879,7 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many kabnan(editable): properly handle create_text node option', function (assert) {
|
||||
QUnit.test('one2many kanban (editable): properly handle create_text node option', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var form = createView({
|
||||
@@ -4877,6 +4909,74 @@ QUnit.module('relational_fields', {
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many kanban: deletion in mobile', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
this.data.partner.records[0].p = [1, 2];
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<field name="p">' +
|
||||
'<kanban>' +
|
||||
'<templates>' +
|
||||
'<t t-name="kanban-box">' +
|
||||
'<div class="oe_kanban_global_click">' +
|
||||
'<field name="display_name"/>' +
|
||||
'</div>' +
|
||||
'</t>' +
|
||||
'</templates>' +
|
||||
'</kanban>' +
|
||||
'<form string="Partners">' +
|
||||
'<field name="display_name"/>' +
|
||||
'</form>' +
|
||||
'</field>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
mockRPC: function (route, args) {
|
||||
if (route === '/web/dataset/call_kw/partner/write') {
|
||||
var commands = args.args[1].p;
|
||||
assert.strictEqual(commands.length, 2,
|
||||
'should have generated two commands');
|
||||
assert.ok(commands[0][0] === 4 && commands[0][1] === 2,
|
||||
'should have generated the command 2 (DELETE) with id 1');
|
||||
assert.ok(commands[1][0] === 2 && commands[1][1] === 1,
|
||||
'should have generated the command 2 (DELETE) with id 2');
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
config: {
|
||||
device: {
|
||||
size_class: config.device.SIZES.XS,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 0,
|
||||
'"Create" button should not be visible in readonly');
|
||||
|
||||
form.$buttons.find('.o_form_button_edit').click();
|
||||
|
||||
assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 1,
|
||||
'"Create" button should be visible in edit');
|
||||
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2,
|
||||
"should have 2 records");
|
||||
|
||||
// open and delete record
|
||||
form.$('.oe_kanban_global_click').first().click();
|
||||
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
|
||||
'there should be a Remove button in the modal footer');
|
||||
$('.modal .modal-footer .o_btn_remove').click();
|
||||
assert.strictEqual($('.o_modal').length, 0, "there shoul be no more modal");
|
||||
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1,
|
||||
'should contain 1 records');
|
||||
|
||||
// save and check that the correct command has been generated
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('one2many kanban: create action disabled', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
@@ -10139,7 +10239,7 @@ QUnit.module('relational_fields', {
|
||||
QUnit.module('FieldMany2Many');
|
||||
|
||||
QUnit.test('many2many kanban: edition', function (assert) {
|
||||
assert.expect(29);
|
||||
assert.expect(32);
|
||||
|
||||
this.data.partner.records[0].timmy = [12, 14];
|
||||
this.data.partner_type.records.push({id: 15, display_name: "red", color: 6});
|
||||
@@ -10191,7 +10291,7 @@ QUnit.module('relational_fields', {
|
||||
var createdType = _.findWhere(this.data.partner_type.records, {
|
||||
display_name: "A new type"
|
||||
});
|
||||
var ids = _.sortBy([12, 15, 18, 21].concat(createdType.id), _.identity.bind(_));
|
||||
var ids = _.sortBy([12, 15, 18].concat(createdType.id), _.identity.bind(_));
|
||||
assert.ok(_.isEqual(_.sortBy(commands[0][2], _.identity.bind(_)), ids),
|
||||
"new value should be " + ids);
|
||||
}
|
||||
@@ -10269,12 +10369,21 @@ QUnit.module('relational_fields', {
|
||||
'the newly created type should be in the kanban');
|
||||
|
||||
// delete subrecords
|
||||
form.$('.o_kanban_record:contains(silver) .delete_icon').click();
|
||||
form.$('.o_kanban_record:contains(silver)').click();
|
||||
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
|
||||
'There should be a modal having Remove Button');
|
||||
$('.modal .modal-footer .o_btn_remove').click(); // Click Remove Button of Formview Dialog
|
||||
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5,
|
||||
'should contain 5 records');
|
||||
assert.ok(!form.$('.o_kanban_record:contains(silver)').length,
|
||||
'the removed record should not be in kanban anymore');
|
||||
|
||||
form.$('.o_kanban_record:contains(blue) .delete_icon').click();
|
||||
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4,
|
||||
'should contain 4 records');
|
||||
assert.ok(!form.$('.o_kanban_record:contains(blue)').length,
|
||||
'the removed record should not be in kanban anymore');
|
||||
|
||||
// save the record
|
||||
form.$buttons.find('.o_form_button_save').click();
|
||||
form.destroy();
|
||||
|
||||
@@ -142,7 +142,6 @@
|
||||
<span t-attf-class="o_website_sale_image_card_size badge badge-#{size_status}" t-att-title="message">
|
||||
<t t-esc="record.image.value"/>
|
||||
</span>
|
||||
<a role="button" t-if="!read_only_mode" type="delete" class="btn btn-sm btn-secondary o_website_sale_image_card_remove" aria-label="Remove" title="Remove"><i class="fa fa-trash"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -294,7 +294,6 @@
|
||||
<t t-name="kanban-box">
|
||||
<t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
|
||||
<div t-att-class="color + (record.title.raw_value == 1 ? ' oe_kanban_color_alert' : '') + ' oe_kanban_global_click'">
|
||||
<a t-if="!read_only_mode" type="delete" class="fa fa-times float-right" title="Delete" aria-label="Delete"/>
|
||||
<div class="o_kanban_image">
|
||||
<img alt="" t-if="record.image_small.raw_value" t-att-src="'data:image/png;base64,'+record.image_small.raw_value"/>
|
||||
<t t-if="!record.image_small.raw_value">
|
||||
|
||||
Reference in New Issue
Block a user