From c4067108d5d6a03d8264d0ebc830683fee0dc8dd Mon Sep 17 00:00:00 2001 From: Mathieu Duckerts-Antoine Date: Wed, 7 Sep 2022 07:00:38 +0000 Subject: [PATCH] [FIX] web: kanban: quick create in a dialog Go to eLearning > Courses > Contents, group the kanban view by Course, then quick create a record in a column. A form view dialogs opens. Save the record: a crash occurs. Root cause: the kanban view needs some record data that are not found on the record created by the form view dialog but tries to add that record directly to the column. Solution: we create a totally new record with same resId and add that new record to the column. Part-of: odoo/odoo#99294 --- .../src/views/kanban/kanban_renderer.js | 4 +- .../web/static/src/views/relational_model.js | 32 +++++++ .../static/tests/views/kanban_view_tests.js | 92 ++++++++++++++++++- 3 files changed, 125 insertions(+), 3 deletions(-) diff --git a/addons/web/static/src/views/kanban/kanban_renderer.js b/addons/web/static/src/views/kanban/kanban_renderer.js index 03ff47a1fbb..686fb6739b7 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/views/kanban/kanban_renderer.js @@ -397,8 +397,8 @@ export class KanbanRenderer extends Component { resModel: this.props.list.resModel, context, title: this.env._t("Create"), - onRecordSaved: (record) => { - group.addRecord(record, 0); + onRecordSaved: async (record) => { + await group.addExistingRecord(record.resId, true); }, }, { diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index 4fc7371a6ab..d3ed22e7825 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -1753,6 +1753,33 @@ export class DynamicRecordList extends DynamicList { // Public // ------------------------------------------------------------------------- + /** + * @param {number} resId + * @param {boolean} [atFirstPosition] + * @returns {Promise} the newly created record + */ + async addExistingRecord(resId, atFirstPosition) { + const newRecord = this.model.createDataPoint("record", { + resModel: this.resModel, + fields: this.fields, + activeFields: this.activeFields, + parentActiveFields: this.activeFields, + onRecordWillSwitchMode: this.onRecordWillSwitchMode, + defaultContext: this.defaultContext, + rawContext: { + parent: this.rawContext, + make: () => this.context, + }, + resId, + }); + if (this.model.useSampleModel) { + this.model.useSampleModel = false; + await this.load(); + } + await this.model.keepLast.add(this.model.mutex.exec(() => newRecord.load())); + return this.addRecord(newRecord, atFirstPosition ? 0 : this.count); + } + /** * @param {Record} record * @param {number} [index] @@ -2447,6 +2474,11 @@ export class Group extends DataPoint { return this.list.addRecord(record, index); } + addExistingRecord(resId, atFirstPosition = false) { + this.count++; + return this.list.addExistingRecord(resId, atFirstPosition); + } + createRecord(params = {}, atFirstPosition = false) { this.count++; this.list.createRecord(params, atFirstPosition); diff --git a/addons/web/static/tests/views/kanban_view_tests.js b/addons/web/static/tests/views/kanban_view_tests.js index 5a7510223b9..57cf66609ff 100644 --- a/addons/web/static/tests/views/kanban_view_tests.js +++ b/addons/web/static/tests/views/kanban_view_tests.js @@ -4,6 +4,7 @@ import { makeFakeDialogService } from "@web/../tests/helpers/mock_services"; import { click, drag, + clickSave, dragAndDrop, editInput, getFixture, @@ -27,7 +28,7 @@ import { createWebClient, doAction } from "@web/../tests/webclient/helpers"; import { browser } from "@web/core/browser/browser"; import { dialogService } from "@web/core/dialog/dialog_service"; import { tooltipService } from "@web/core/tooltip/tooltip_service"; -import { makeErrorFromResponse } from "@web/core/network/rpc_service"; +import { makeErrorFromResponse, RPCError } from "@web/core/network/rpc_service"; import { registry } from "@web/core/registry"; import { nbsp } from "@web/core/utils/strings"; import { getNextTabableElement } from "@web/core/utils/ui"; @@ -11471,4 +11472,93 @@ QUnit.module("Views", (hooks) => { assert.doesNotHaveClass(getColumn(1), "o_column_folded"); assert.containsN(getColumn(1), ".o_kanban_record", 3); }); + + QUnit.test("quick create record in grouped kanban in a form view dialog", async (assert) => { + serverData.models.partner.fields.foo.default = "ABC"; + serverData.views = { + "partner,false,form": ` +
+ + + `, + }; + + await makeView({ + type: "kanban", + resModel: "partner", + serverData, + arch: ` + + + + + +
+ +
+
+
+
+ `, + groupBy: ["product_id"], + async mockRPC(route, { method }) { + assert.step(method || route); + if (method === "name_create") { + throw new RPCError(); + } + }, + }); + + assert.containsN( + target, + ".o_kanban_group:first-child .o_kanban_record", + 2, + "first column should contain two records" + ); + + assert.deepEqual( + [...target.querySelectorAll(".o_kanban_group:first-child .o_kanban_record")].map( + (el) => el.innerText + ), + ["yop", "gnap"] + ); + + assert.containsNone(target, ".modal"); + + // click on 'Create', fill the quick create and validate + await createRecord(); + await editQuickCreateInput("display_name", "new partner"); + await validateRecord(); + + assert.containsOnce(target, ".modal"); + await clickSave(target.querySelector(".modal")); + + assert.containsN( + target, + ".o_kanban_group:first-child .o_kanban_record", + 3, + "first column should contain three records" + ); + + assert.deepEqual( + [...target.querySelectorAll(".o_kanban_group:first-child .o_kanban_record")].map( + (el) => el.innerText + ), + ["ABC", "yop", "gnap"] + ); + + assert.verifySteps([ + "get_views", + "web_read_group", // initial read_group + "web_search_read", // initial search_read (first column) + "web_search_read", // initial search_read (second column) + "onchange", // quick create + "name_create", // should perform a name_create to create the record + "get_views", // load views for form view dialog + "onchange", // load of a virtual record in form view dialog + "create", // save virtual record + "read", // read the created record to get foo value + "onchange", // reopen the quick create automatically + ]); + }); });