diff --git a/addons/web/static/src/views/kanban/kanban_model.js b/addons/web/static/src/views/kanban/kanban_model.js index fd65f8e43af..89f5921fafc 100644 --- a/addons/web/static/src/views/kanban/kanban_model.js +++ b/addons/web/static/src/views/kanban/kanban_model.js @@ -287,24 +287,30 @@ class KanbanGroup extends Group { * @param {number} index * @returns {Promise} */ - async validateQuickCreate() { - const record = this.list.quickCreateRecord; + async validateQuickCreate(record, mode) { let saved = false; if (record) { saved = await this.model.mutex.exec(async () => { - const saved = await record._save({ noReload: true, stayInEdition: true }); - if (saved) { - this.count++; - if (record.parentActiveFields) { - record.setActiveFields(record.parentActiveFields); - record.parentActiveFields = false; - } - await this.model.reloadRecords(record); - record.switchMode("readonly"); - this.addRecord(this.removeRecord(record), 0); - } - return saved; + return await record._save({ noReload: true, stayInEdition: true }); }); + if (saved) { + if (mode === "add") { + await this.model.root.quickCreate(this); + } else { + this.quickCreateRecord = null; + } + if (record.parentActiveFields) { + record.setActiveFields(record.parentActiveFields); + record.parentActiveFields = false; + } + await this.model.reloadRecords(record); + record.switchMode("readonly"); + this.addRecord(record, 0); + this.model.trigger("group-updated", { + group: this, + withProgressBars: true, + }); + } } return saved ? record : false; } @@ -605,9 +611,7 @@ export class KanbanModel extends RelationalModel { // example background. Return true so that we don't get sample data instead return true; } - return this.root.groups.some( - (group) => group.count > 0 || group.list.quickCreateRecord - ); + return this.root.groups.some((group) => group.count > 0 || group.quickCreateRecord); } return this.root.records.length > 0; } diff --git a/addons/web/static/src/views/kanban/kanban_renderer.js b/addons/web/static/src/views/kanban/kanban_renderer.js index bc4c62ac7e2..8df4578eba2 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/views/kanban/kanban_renderer.js @@ -378,10 +378,10 @@ export class KanbanRenderer extends Component { } async validateQuickCreate(mode, group) { - const values = group.list.quickCreateRecord.data; - let record; + const values = group.quickCreateRecord.data; + let record = group.quickCreateRecord; try { - record = await group.validateQuickCreate(); + record = await group.validateQuickCreate(record, mode); } catch (e) { // TODO: filter RPC errors more specifically (eg, for access denied, there is no point in opening a dialog) if (!(e instanceof RPCError)) { @@ -410,12 +410,8 @@ export class KanbanRenderer extends Component { ); } - if (record) { - if (mode === "edit") { - await this.props.openRecord(record, "edit"); - } else { - await this.quickCreate(group); - } + if (mode === "edit" && record) { + await this.props.openRecord(record, "edit"); } } diff --git a/addons/web/static/src/views/kanban/kanban_renderer.xml b/addons/web/static/src/views/kanban/kanban_renderer.xml index e5aa39e879c..c6c073c0aba 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.xml +++ b/addons/web/static/src/views/kanban/kanban_renderer.xml @@ -60,30 +60,28 @@ + + + - - - - - - +
diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index 435b25b7db3..41e41a2d69e 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -1893,10 +1893,6 @@ export class DynamicRecordList extends DynamicList { }; } - get quickCreateRecord() { - return this.records.find((r) => r.isInQuickCreation); - } - // ------------------------------------------------------------------------- // Public // ------------------------------------------------------------------------- @@ -1931,13 +1927,6 @@ export class DynamicRecordList extends DynamicList { return record; } - async cancelQuickCreate(force = false) { - const record = this.quickCreateRecord; - if (record && (force || !record.isDirty)) { - this.removeRecord(record); - } - } - /** * @param {Object} [params={}] * @param {boolean} [atFirstPosition] @@ -1956,8 +1945,11 @@ export class DynamicRecordList extends DynamicList { await this.model.keepLast.add(this.model.mutex.exec(() => newRecord.load())); this.editedRecord = newRecord; this.onRemoveNewRecord = await this.onCreateRecord(newRecord); - - return this.addRecord(newRecord, atFirstPosition ? 0 : this.count); + if (params.isInQuickCreation) { + return newRecord; + } else { + return this.addRecord(newRecord, atFirstPosition ? 0 : this.count); + } } /** @@ -2039,10 +2031,6 @@ export class DynamicRecordList extends DynamicList { async quickCreate(activeFields, context) { await this.model.mutex.getUnlockedDef(); - const record = this.quickCreateRecord; - if (record) { - this.removeRecord(record); - } const rawContext = { parent: this.rawContext, make: () => makeContext([context, {}]), @@ -2352,7 +2340,11 @@ export class DynamicGroupList extends DynamicList { if (isFolded) { await group.toggle(); } - await group.quickCreate(this.quickCreateInfo.activeFields, this.context); + group.quickCreateRecord = await group.quickCreate( + this.quickCreateInfo.activeFields, + this.context + ); + this.model.notify(); } /** @@ -2788,6 +2780,13 @@ export class Group extends DataPoint { return this.list.quickCreate(activeFields, ctx); } + async cancelQuickCreate(force = false) { + if (this.quickCreateRecord && (force || !this.quickCreateRecord.isDirty)) { + this.quickCreateRecord = null; + this.model.notify(); + } + } + /** * @see DynamicRecordList.removeRecord */ diff --git a/addons/web/static/tests/views/kanban_view_tests.js b/addons/web/static/tests/views/kanban_view_tests.js index 01111b16aa4..e8997a6d9a5 100644 --- a/addons/web/static/tests/views/kanban_view_tests.js +++ b/addons/web/static/tests/views/kanban_view_tests.js @@ -1544,8 +1544,8 @@ QUnit.module("Views", (hooks) => { "web_search_read", // initial search_read (second column) "onchange", // quick create "name_create", // should perform a name_create to create the record - "read", // read the created record "onchange", // reopen the quick create automatically + "read", // read the created record ]); }); @@ -1621,11 +1621,76 @@ QUnit.module("Views", (hooks) => { "get_views", // form view in quick create "onchange", // quick create "create", // should perform a create to create the record - "read", // read the created record "onchange", // new quick create + "read", // read the created record ]); }); + QUnit.test("quick create record flickering", async (assert) => { + let def; + serverData.views["partner,some_view_ref,form"] = + "
" + + '' + + '' + + '' + + ""; + + await makeView({ + type: "kanban", + resModel: "partner", + serverData, + arch: + '' + + '' + + '' + + '
' + + "
", + groupBy: ["bar"], + async mockRPC(route, args) { + if (args.method === "create") { + assert.deepEqual( + args.args[0], + { + foo: "new partner", + int_field: 4, + state: "def", + }, + "should send the correct values" + ); + } + if (args.method === "onchange") { + await def; + } + }, + }); + + // click on 'Create' -> should open the quick create in the first column + await createRecord(); + + assert.containsN(target, ".o_kanban_group:first-child .o_kanban_record", 1); + assert.containsOnce(target, ".o_kanban_group:first-child .o_kanban_quick_create"); + const quickCreate = target.querySelector( + ".o_kanban_group:first-child .o_kanban_quick_create" + ); + + assert.containsOnce(quickCreate, ".o_form_view.o_xxs_form_view"); + assert.containsN(quickCreate, "input", 2); + assert.containsN(quickCreate, ".o_field_widget", 3, "should have rendered three widgets"); + + // fill the quick create and validate + await editQuickCreateInput("foo", "new partner"); + await editQuickCreateInput("int_field", 4); + await click(quickCreate, ".o_field_widget[name=state] .o_priority_star:first-child"); + def = makeDeferred(); + await validateRecord(); + assert.containsN(target, ".o_kanban_group:first-child .o_kanban_record", 1); + assert.containsOnce(target, ".o_kanban_group:first-child .o_kanban_quick_create"); + def.resolve(); + await nextTick(); + assert.containsN(target, ".o_kanban_group:first-child .o_kanban_record", 2); + assert.containsOnce(target, ".o_kanban_group:first-child .o_kanban_quick_create"); + }); + QUnit.test( "quick create record should focus default field [REQUIRE FOCUS]", async function (assert) { @@ -1779,8 +1844,8 @@ QUnit.module("Views", (hooks) => { "web_search_read", // initial search_read (second column) "onchange", // quick create "name_create", // should perform a name_create to create the record - "read", // read the created record "onchange", // reopen the quick create automatically + "read", // read the created record ]); }); @@ -1847,8 +1912,8 @@ QUnit.module("Views", (hooks) => { "get_views", // form view in quick create "onchange", // quick create "create", // should perform a create to create the record - "read", // read the created record "onchange", // reopen the quick create automatically + "read", // read the created record ]); }); @@ -1903,9 +1968,9 @@ QUnit.module("Views", (hooks) => { "read", // read display_name of categories "onchange", // quick create "name_create", // should perform a name_create to create the record + "onchange", // reopen the quick create automatically "read", "read", // read the created record - "onchange", // reopen the quick create automatically ]); }); @@ -1963,8 +2028,8 @@ QUnit.module("Views", (hooks) => { "web_search_read", // read records when unfolding 'None' "onchange", // quick create "name_create", // should perform a name_create to create the record - "read", // read the created record "onchange", // reopen the quick create automatically + "read", // read the created record ]); }); @@ -2025,8 +2090,8 @@ QUnit.module("Views", (hooks) => { "get_views", // get form view "onchange", // quick create "create", // should perform a name_create to create the record - "read", // read the created record "onchange", // reopen the quick create automatically + "read", // read the created record ]); }); @@ -2098,9 +2163,9 @@ QUnit.module("Views", (hooks) => { "onchange", // quick create "read", "create", // should perform a create to create the record - "read", "onchange", "read", + "read", ]); }); @@ -2295,7 +2360,7 @@ QUnit.module("Views", (hooks) => { await editQuickCreateInput("foo", "new partner"); assert.verifySteps(["onchange"]); await validateRecord(); - assert.verifySteps(["create", "read", "onchange"]); + assert.verifySteps(["create", "onchange", "read"]); }); QUnit.test("quick create record and change state in grouped mode", async (assert) => {