diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-01-12 19:03:00 +0100 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-01-12 19:03:00 +0100 |
| commit | 56974322f8c67ec5680654ed4bcb08ca57117c46 (patch) | |
| tree | e64c00274a47c46cf78e99b6ba62df4bc4dbbba4 /addons/web/static | |
| parent | f6ef0c776096774fc4c6821449ab42cfc2f53e62 (diff) | |
| parent | 3b80a059ff4305fe10c9b40a3118508b1b849ead (diff) | |
[MERGE] forward port branch 11.0 up to 3b80a059ff4
Diffstat (limited to 'addons/web/static')
| -rw-r--r-- | addons/web/static/src/js/core/utils.js | 18 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/abstract_field.js | 5 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/basic_fields.js | 21 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_registry.js | 1 | ||||
| -rw-r--r-- | addons/web/static/src/js/fields/field_utils.js | 10 | ||||
| -rw-r--r-- | addons/web/static/src/js/services/data_manager.js | 4 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/basic/basic_model.js | 45 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/form/form_renderer.js | 11 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_controller.js | 19 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_renderer.js | 12 | ||||
| -rw-r--r-- | addons/web/static/src/xml/base.xml | 3 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/basic_fields_tests.js | 34 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/relational_fields_tests.js | 41 | ||||
| -rw-r--r-- | addons/web/static/tests/views/basic_model_tests.js | 1 | ||||
| -rw-r--r-- | addons/web/static/tests/views/form_tests.js | 35 | ||||
| -rw-r--r-- | addons/web/static/tests/views/kanban_tests.js | 95 |
16 files changed, 266 insertions, 89 deletions
diff --git a/addons/web/static/src/js/core/utils.js b/addons/web/static/src/js/core/utils.js index 99534708a94..1bdd9e70a69 100644 --- a/addons/web/static/src/js/core/utils.js +++ b/addons/web/static/src/js/core/utils.js @@ -24,6 +24,22 @@ var utils = { } }, /** + * Check if the value is a bin_size or not. + * If not, compute an approximate size out of the base64 encoded string. + * + * @param {string} value original format + * @return {string} bin_size (human-readable) + */ + binaryToBinsize: function (value) { + if (!this.is_bin_size(value)) { + // Computing approximate size out of base64 encoded string + // http://en.wikipedia.org/wiki/Base64#MIME + return this.human_size(value.length / 1.37); + } + // already bin_size + return value; + }, + /** * Confines a value inside an interval * * @param {number} [val] the value to confine @@ -132,7 +148,7 @@ var utils = { size /= 1024; ++i; } - return size.toFixed(2) + ' ' + units[i]; + return size.toFixed(2) + ' ' + units[i].trim(); }, /** * Insert "thousands" separators in the provided number (which is actually diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js index 2534f8ae90a..8bb9afca065 100644 --- a/addons/web/static/src/js/fields/abstract_field.js +++ b/addons/web/static/src/js/fields/abstract_field.js @@ -45,6 +45,11 @@ var AbstractField = Widget.extend({ }, /** + * fields can extend the context, e.g. binary fields add {bin_size: true} + */ + context: null, + + /** * An object representing fields to be fetched by the model eventhough not present in the view * This object contains "field name" as key and an object as value. * That value object must contain the key "type" diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js index d0662fe7cef..f3e66cee421 100644 --- a/addons/web/static/src/js/fields/basic_fields.js +++ b/addons/web/static/src/js/fields/basic_fields.js @@ -1094,6 +1094,7 @@ var AbstractFieldBinary = AbstractField.extend({ }, 'click .o_clear_file_button': 'on_clear', }), + context: { bin_size: true }, init: function (parent, name, record) { this._super.apply(this, arguments); this.fields = record.fields; @@ -1312,25 +1313,6 @@ var FieldBinaryFile = AbstractFieldBinary.extend({ }, }); -var FieldBinaryDownloadLink = AbstractFieldBinary.extend({ - template: 'FieldBinaryDownloadLink', - events: _.extend({}, AbstractFieldBinary.prototype.events, { - 'click': function (ev) { - ev.stopPropagation(); - }, - }), - supportedFieldTypes: ['binary'], - init: function () { - this._super.apply(this, arguments); - this.filename = _t("Binary File"); - if (this.nodeOptions.filename && this.recordData[this.nodeOptions.filename]) { - this.filename = this.recordData[this.nodeOptions.filename]; - } - this.url = "data:application/octet-stream;base64," + this.value; - this.text = _t("Download"); - }, -}); - var PriorityWidget = AbstractField.extend({ // the current implementation of this widget makes it // only usable for fields of type selection @@ -2561,7 +2543,6 @@ return { TranslatableFieldMixin: TranslatableFieldMixin, DebouncedField: DebouncedField, FieldEmail: FieldEmail, - FieldBinaryDownloadLink: FieldBinaryDownloadLink, FieldBinaryFile: FieldBinaryFile, FieldBinaryImage: FieldBinaryImage, FieldBoolean: FieldBoolean, diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js index 85b4fc1187f..6692663d5f9 100644 --- a/addons/web/static/src/js/fields/field_registry.js +++ b/addons/web/static/src/js/fields/field_registry.js @@ -33,7 +33,6 @@ registry .add('email', basic_fields.FieldEmail) .add('phone', basic_fields.FieldPhone) .add('url', basic_fields.UrlWidget) - .add('download_link', basic_fields.FieldBinaryDownloadLink) .add('image', basic_fields.FieldBinaryImage) .add('binary', basic_fields.FieldBinaryFile) .add('monetary', basic_fields.FieldMonetary) diff --git a/addons/web/static/src/js/fields/field_utils.js b/addons/web/static/src/js/fields/field_utils.js index 812a7f380f7..5ac180b1de1 100644 --- a/addons/web/static/src/js/fields/field_utils.js +++ b/addons/web/static/src/js/fields/field_utils.js @@ -28,17 +28,17 @@ var _t = core._t; //------------------------------------------------------------------------------ /** + * Convert binary to bin_size * - * @param {string} value base64 representation of the binary + * @param {string} value base64 representation of the binary (might be already a bin_size!) * @param {Object} [field] * a description of the field (note: this parameter is ignored) * @param {Object} [options] additional options (note: this parameter is ignored) + * + * @returns {string} bin_size (which is human-readable) */ function formatBinary(value, field, options) { - if (!value) { - return ''; - } - return utils.human_size(value.length / 1.37); // base64 estimated size: http://en.wikipedia.org/wiki/Base64#MIME + return utils.binaryToBinsize(value); } /** diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js index 72ec816efdd..948d3a1c73a 100644 --- a/addons/web/static/src/js/services/data_manager.js +++ b/addons/web/static/src/js/services/data_manager.js @@ -387,6 +387,10 @@ return core.Class.extend({ attrs.fieldDependencies = attrs.Widget.prototype.fieldDependencies; } + if (attrs.Widget.prototype.context) { + attrs.context = attrs.Widget.prototype.context; + } + return attrs; }, /** 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 3621b7c1227..a6979776c99 100644 --- a/addons/web/static/src/js/views/basic/basic_model.js +++ b/addons/web/static/src/js/views/basic/basic_model.js @@ -33,7 +33,7 @@ odoo.define('web.BasicModel', function (require) { * isOpen: {boolean}, * loadMoreOffset: {integer}, * limit: {integer}, - * model: {string, + * model: {string}, * offset: {integer}, * openGroupByDefault: {boolean}, * orderedBy: {Object[]}, @@ -1854,7 +1854,7 @@ var BasicModel = AbstractModel.extend({ model: record.model, method: 'read', args: [[record.res_id], fieldNames], - context: _.extend({}, record.getContext(), {bin_size: true}), + context: record.getContext(), }) .then(function (result) { if (result.length === 0) { @@ -2374,7 +2374,7 @@ var BasicModel = AbstractModel.extend({ }); record.data[fieldName] = list.id; if (!fieldInfo.__no_fetch) { - var def = self._readUngroupedList(list).then(function () { + var def = self._readUngroupedList(list).then(function (list) { return $.when( self._fetchX2ManysBatched(list), self._fetchReferencesBatched(list) @@ -3040,10 +3040,33 @@ var BasicModel = AbstractModel.extend({ * the resource in the localData object. * * @param {Object} params + * @param {Object} [params.aggregateValues={}] + * @param {Object} [params.context={}] context of the action + * @param {integer} [params.count=0] number of record being manipulated + * @param {Object|Object[]} [params.data={}|[]] data of the record + * @param {*[]} [params.domain=[]] + * @param {Object} params.fields contains the description of each field * @param {Object} [params.fieldsInfo={}] contains the fieldInfo of each field - * @param {Array} [params.fieldNames] the name of fields to load, the list + * @param {Object[]} [params.fieldNames] the name of fields to load, the list * of all fields by default - * @param {Object} params.fields contains the description of each field + * @param {string[]} [params.groupedBy=[]] + * @param {boolean} [params.isOpen] + * @param {integer} params.limit max number of records shown on screen (pager size) + * @param {string} params.modelName + * @param {integer} [params.offset] + * @param {boolean} [params.openGroupByDefault] + * @param {Object[]} [params.orderedBy=[]] + * @param {integer[]} [params.orderedResIDs] + * @param {string} [params.parentID] model name ID of the parent model + * @param {Object} [params.rawContext] + * @param {[type]} [params.ref] + * @param {string} [params.relationField] + * @param {integer|null} [params.res_id] actual id of record in the server + * @param {integer[]} [params.res_ids] context in which the data point is used, from a list of res_id + * @param {boolean} [params.static=false] + * @param {string} [params.type='record'|'list'] + * @param {[type]} [params.value] + * @param {string} [params.viewType] the type of the view, e.g. 'list' or 'form' * @returns {Object} the resource created */ _makeDataPoint: function (params) { @@ -3069,13 +3092,23 @@ var BasicModel = AbstractModel.extend({ id: {type: 'integer'}, }, params.fields); + // datapoint context is extended by fields widgets + var context = _.extend({}, params.context); + if (params.fieldsInfo && params.viewType) { + _.each(params.fieldsInfo[params.viewType], function (field) { + if (field.context) { + _.extend(context, field.context); + } + }); + } + var dataPoint = { _cache: type === 'list' ? {} : undefined, _changes: null, _domains: {}, _rawChanges: {}, aggregateValues: params.aggregateValues || {}, - context: params.context || {}, + context: context, count: params.count || res_ids.length, data: data, domain: params.domain || [], diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js index 9409a51b7e0..779121de3e9 100644 --- a/addons/web/static/src/js/views/form/form_renderer.js +++ b/addons/web/static/src/js/views/form/form_renderer.js @@ -693,6 +693,7 @@ var FormRenderer = BasicRenderer.extend({ var self = this; var $headers = $('<ul class="nav nav-tabs">'); var $pages = $('<div class="tab-content nav nav-tabs">'); + var autofocusTab = -1; // renderedTabs is used to aggregate the generated $headers and $pages // alongside their node, so that their modifiers can be registered once // all tabs have been rendered, to ensure that the first visible tab @@ -701,9 +702,8 @@ var FormRenderer = BasicRenderer.extend({ var pageID = _.uniqueId('notebook_page_'); var $header = self._renderTabHeader(child, pageID); var $page = self._renderTabPage(child, pageID); - if (index === 0) { - $header.addClass('active'); - $page.addClass('active'); + if (autofocusTab === -1 && child.attrs.autofocus === 'autofocus') { + autofocusTab = index; } self._handleAttributes($header, child); $headers.append($header); @@ -714,6 +714,11 @@ var FormRenderer = BasicRenderer.extend({ node: child, }; }); + if (renderedTabs.length) { + var tabToFocus = renderedTabs[Math.max(0, autofocusTab)]; + tabToFocus.$header.addClass('active'); + tabToFocus.$page.addClass('active'); + } // register the modifiers for each tab _.each(renderedTabs, function (tab) { self._registerModifiers(tab.node, self.state, tab.$header, { 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 2f6f566649e..9e97ec40686 100644 --- a/addons/web/static/src/js/views/kanban/kanban_controller.js +++ b/addons/web/static/src/js/views/kanban/kanban_controller.js @@ -239,15 +239,16 @@ var KanbanController = BasicController.extend({ * @private */ _onButtonNew: function () { - var data = this.model.get(this.handle, {raw: true}); - if (data.groupedBy.length > 0 && data.count > 0 && this.on_create === 'quick_create') { + var state = this.model.get(this.handle, {raw: true}); + var hasColumns = state.groupedBy.length > 0 && state.data.length > 0; + if (hasColumns && this.on_create === 'quick_create') { // Activate the quick create in the first column this.renderer.addQuickCreate(); } else if (this.on_create && this.on_create !== 'quick_create') { // Execute the given action this.do_action(this.on_create, { on_close: this.reload.bind(this), - additional_context: data.context, + additional_context: state.context, }); } else { // Open the form view @@ -355,11 +356,13 @@ var KanbanController = BasicController.extend({ self._updateEnv(); var columnState = self.model.getColumn(db_id); - return self.renderer.updateColumn(columnState.id, columnState).then(function () { - if (event.data.openRecord) { - self.trigger_up('open_record', {id: db_id, mode: 'edit'}); - } - }); + return self.renderer + .updateColumn(columnState.id, columnState, {openQuickCreate: true}) + .then(function () { + if (event.data.openRecord) { + self.trigger_up('open_record', {id: db_id, mode: 'edit'}); + } + }); }); } }, diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js index 0f91fb2ae14..e4e37095afa 100644 --- a/addons/web/static/src/js/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js @@ -141,15 +141,23 @@ var KanbanRenderer = BasicRenderer.extend({ * * @param {string} localID the column id * @param {Object} columnState + * @param {Object} [options] + * @param {boolean} [options.openQuickCreate] if true, directly opens the + * QuickCreate widget in the updated column * * @returns {Deferred} */ - updateColumn: function (localID, columnState) { + updateColumn: function (localID, columnState, options) { var newColumn = new KanbanColumn(this, columnState, this.columnOptions, this.recordOptions); var index = _.findIndex(this.widgets, {db_id: localID}); var column = this.widgets[index]; this.widgets[index] = newColumn; - return newColumn.insertAfter(column.$el).then(column.destroy.bind(column)); + return newColumn.insertAfter(column.$el).then(function () { + if (options && options.openQuickCreate) { + newColumn.addQuickCreate(); + } + column.destroy(); + }); }, /** * Updates a given record with its new state. diff --git a/addons/web/static/src/xml/base.xml b/addons/web/static/src/xml/base.xml index 8ee6f643c51..509c03fdf4b 100644 --- a/addons/web/static/src/xml/base.xml +++ b/addons/web/static/src/xml/base.xml @@ -906,9 +906,6 @@ </t> </div> </t> -<t t-name="FieldBinaryDownloadLink"> - <a t-att-download="widget.filename" t-att-href="widget.url"><t t-esc="widget.text"/></a> -</t> <t t-name="HiddenInputFile"> <div t-attf-class="o_hidden_input_file #{fileupload_class or ''}" t-att-style="fileupload_style"> <form class="o_form_binary_form" t-att-target="fileupload_id" diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index 97601c8e6d0..4fd9d6ee84e 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -1518,40 +1518,6 @@ QUnit.module('basic_fields', { session.get_file = oldGetFile; }); - QUnit.test('download_link widget in list view', function (assert) { - assert.expect(5); - - this.data.partner.fields.filename = { string: "Filename", type: "char" }; - this.data.partner.records[0].filename = "document.txt"; - - var form = createView({ - View: ListView, - model: 'partner', - data: this.data, - arch: '<tree string="Partners">' + - '<field name="document" widget="download_link" options="{\'filename\': \'filename\'}"/>' + - '<field name="filename"/>' + - '</tree>', - res_id: 1, - }); - - assert.ok(form.$('.o_data_cell').first().hasClass("o_download_link_cell"), - "this should be a download link cell"); - assert.ok(form.$('.o_data_cell').first().find('a').eq(0), - "there should be a link in the cell"); - assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).attr('download'), - "document.txt", - "it should download a file named 'document.txt'"); - assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).attr('href').trim(), - "data:application/octet-stream;base64,coucou==", - "it should have the appropriate link of a binary"); - assert.strictEqual(form.$('.o_data_cell').first().find('a').eq(0).text(), - "Download", - "the text of the link should be 'Download'"); - - form.destroy(); - }); - QUnit.test('text field rendering in list view', function (assert) { assert.expect(1); diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index c149b5c3dba..ef5139511fe 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -6916,7 +6916,6 @@ QUnit.module('relational_fields', { if (args.method === 'read' && args.model === 'partner') { assert.deepEqual(args.kwargs.context, { active_field: 2, - bin_size: true, someKey: 'some value', }, "sent context should be correct"); } @@ -7600,6 +7599,46 @@ QUnit.module('relational_fields', { form.destroy(); }); + + QUnit.test('one2many with multiple pages and sequence field', function (assert) { + assert.expect(1); + + this.data.partner.records[0].turtles = [3, 2, 1]; + this.data.partner.onchanges.turtles = function () {}; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch:'<form string="Partners">' + + '<field name="turtles">' + + '<tree limit="2">' + + '<field name="turtle_int" widget="handle"/>' + + '<field name="turtle_foo"/>' + + '<field name="partner_ids" invisible="1"/>' + + '</tree>' + + '</field>' + + '</form>', + res_id: 1, + mockRPC: function (route, args) { + if (args.method === 'onchange') { + return $.when({value: { turtles: [ + [5], + [1, 1, {turtle_foo: "from onchange", partner_ids: [[5]]}], + ]}}); + } + return this._super(route, args); + }, + viewOptions: { + mode: 'edit', + }, + }); + form.$('span[name="delete"]').first().click(); + assert.strictEqual(form.$('.o_data_row').text(), 'from onchange', + 'onchange has been properly applied'); + form.destroy(); + }); + QUnit.module('FieldMany2Many'); QUnit.test('many2many kanban: edition', function (assert) { diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js index 492dfd4224c..72061f326e0 100644 --- a/addons/web/static/tests/views/basic_model_tests.js +++ b/addons/web/static/tests/views/basic_model_tests.js @@ -74,7 +74,6 @@ QUnit.module('Views', { mockRPC: function (route, args) { assert.deepEqual(args.kwargs.context, { active_field: 2, - bin_size: true, someKey: 'some value', }, "should have sent the correct context"); return this._super.apply(this, arguments); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 1f5e57b2202..9f2a9b68698 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -199,7 +199,7 @@ QUnit.module('Views', { }); QUnit.test('only necessary fields are fetched with correct context', function (assert) { - assert.expect(2); + assert.expect(1); var form = createView({ View: FormView, @@ -214,8 +214,6 @@ QUnit.module('Views', { // field, not sure why. Maybe this test should be modified. assert.deepEqual(args.args[1], ["foo", "display_name"], "should only fetch requested fields"); - assert.deepEqual(args.kwargs.context, {bin_size: true}, - "bin_size should always be in the context"); return this._super(route, args); } }); @@ -483,6 +481,37 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('autofocus on second notebook page', function (assert) { + assert.expect(2); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<sheet>' + + '<field name="product_id"/>' + + '<notebook>' + + '<page string="Choucroute">' + + '<field name="foo"/>' + + '</page>' + + '<page string="Cassoulet" autofocus="autofocus">' + + '<field name="bar"/>' + + '</page>' + + '</notebook>' + + '</sheet>' + + '</form>', + res_id: 1, + }); + + assert.notOk(form.$('.o_notebook .nav li:first()').hasClass('active'), + 'first tab should not active'); + assert.ok(form.$('.o_notebook .nav li:nth(1)').hasClass('active'), + 'second tab should be active'); + + form.destroy(); + }); + QUnit.test('invisible attrs on group are re-evaluated on field change', function (assert) { assert.expect(2); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 9c8361e63ae..9e6d6e9e30f 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -493,6 +493,58 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('quick create several records in a row', function (assert) { + assert.expect(6); + + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '<kanban class="o_kanban_test" on_create="quick_create">' + + '<field name="bar"/>' + + '<templates><t t-name="kanban-box">' + + '<div><field name="foo"/></div>' + + '</t></templates></kanban>', + groupBy: ['bar'], + }); + + assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + "first column should contain one record"); + + // click to add an element, fill the input and press ENTER + kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + + assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + "the quick create should be open"); + + kanban.$('.o_kanban_quick_create input') + .val('new partner 1') + .trigger($.Event('keypress', { + which: $.ui.keyCode.ENTER, + keyCode: $.ui.keyCode.ENTER, + })); + + assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + "first column should now contain two records"); + assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + "the quick create should still be open"); + + // create a second element in a row + kanban.$('.o_kanban_quick_create input') + .val('new partner 2') + .trigger($.Event('keypress', { + which: $.ui.keyCode.ENTER, + keyCode: $.ui.keyCode.ENTER, + })); + + assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, + "first column should now contain three records"); + assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + "the quick create should still be open"); + + kanban.destroy(); + }); + QUnit.test('quick create fail in grouped', function (assert) { assert.expect(7); @@ -524,7 +576,6 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - kanban.renderButtons(); assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, "there should be 2 records in first column"); @@ -556,6 +607,48 @@ QUnit.module('Views', { kanban.destroy(); }); + QUnit.test('quick create record in empty grouped kanban', function (assert) { + assert.expect(3); + + var kanban = createView({ + View: KanbanView, + model: 'partner', + data: this.data, + arch: '<kanban on_create="quick_create">' + + '<field name="product_id"/>' + + '<templates><t t-name="kanban-box">' + + '<div><field name="foo"/></div>' + + '</t></templates>' + + '</kanban>', + groupBy: ['product_id'], + mockRPC: function (route, args) { + if (args.method === 'read_group') { + // override read_group to return empty groups, as this is + // the case for several models (e.g. project.task grouped + // by stage_id) + var result = [ + {__domain: [['product_id', '=', 3]], product_id_count: 0}, + {__domain: [['product_id', '=', 5]], product_id_count: 0}, + ]; + return $.when(result); + } + return this._super.apply(this, arguments); + }, + }); + + assert.strictEqual(kanban.$('.o_kanban_group').length, 2, + "there should be 2 columns"); + assert.strictEqual(kanban.$('.o_kanban_record').length, 0, + "both columns should be empty"); + + kanban.$buttons.find('.o-kanban-button-new').click(); + + assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_quick_create').length, 1, + "should have opened the quick create in the first column"); + + kanban.destroy(); + }); + QUnit.test('many2many_tags in kanban views', function (assert) { assert.expect(12); |
