From 4f87c9c07f230e9e66d4e581a32ae7854b0e4456 Mon Sep 17 00:00:00 2001 From: FrancoisGe Date: Mon, 22 Aug 2022 14:52:58 +0000 Subject: [PATCH] [FIX] web: switch the record with keynav in FormView Before this commit, in a formView, if you modify an input and use the keynav (alt+n or alt+p) to change the record, then the modification is not saved. How to reproduce? - go to a form view with a pager containing more than one record - edit an input - press alt+n to move to the next record - press alt+p to go back to the previous record Result before: The record has not changed Result after: The record has saved the change. closes odoo/odoo#98602 Signed-off-by: Aaron Bohy (aab) --- .../src/views/fields/input_field_hook.js | 3 + .../static/src/views/form/form_controller.js | 4 +- .../web/static/src/views/relational_model.js | 1 - .../tests/views/form/form_view_tests.js | 73 +++++++++++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/views/fields/input_field_hook.js b/addons/web/static/src/views/fields/input_field_hook.js index f4cacbb76ad..59c0ca60a38 100644 --- a/addons/web/static/src/views/fields/input_field_hook.js +++ b/addons/web/static/src/views/fields/input_field_hook.js @@ -113,6 +113,9 @@ export function useInputField(params) { }); useBus(env.bus, "RELATIONAL_MODEL:WILL_SAVE_URGENTLY", () => commitChanges(true)); + useBus(env.bus, "RELATIONAL_MODEL:NEED_LOCAL_CHANGES", (ev) => + ev.detail.proms.push(commitChanges()) + ); /** * Roughly the same as onChange, but called at more specific / critical times. (See bus events) diff --git a/addons/web/static/src/views/form/form_controller.js b/addons/web/static/src/views/form/form_controller.js index 39ca8d4bc4d..be218821f7c 100644 --- a/addons/web/static/src/views/form/form_controller.js +++ b/addons/web/static/src/views/form/form_controller.js @@ -185,9 +185,7 @@ export class FormController extends Component { limit: 1, total: resIds.length, onUpdate: async ({ offset }) => { - if (this.model.root.isDirty) { - await this.model.root.save({ stayInEdition: true }); - } + await this.model.root.save({ stayInEdition: true }); this.model.load({ resId: resIds[offset] }); }, }; diff --git a/addons/web/static/src/views/relational_model.js b/addons/web/static/src/views/relational_model.js index b866f14d932..a240f0fae78 100644 --- a/addons/web/static/src/views/relational_model.js +++ b/addons/web/static/src/views/relational_model.js @@ -1239,7 +1239,6 @@ export class Record extends DataPoint { * @returns {Promise} */ async _save(options = { stayInEdition: false, noReload: false }) { - this.model.env.bus.trigger("RELATIONAL_MODEL:NEED_LOCAL_CHANGES"); if (!(await this._checkValidity())) { const invalidFields = [...this._invalidFields].map((fieldName) => { return `
  • ${escape(this.fields[fieldName].string || fieldName)}
  • `; diff --git a/addons/web/static/tests/views/form/form_view_tests.js b/addons/web/static/tests/views/form/form_view_tests.js index 1db846e3060..90ba5bf1830 100644 --- a/addons/web/static/tests/views/form/form_view_tests.js +++ b/addons/web/static/tests/views/form/form_view_tests.js @@ -18,6 +18,7 @@ import { patchWithCleanup, selectDropdownItem, triggerEvent, + triggerHotkey, } from "@web/../tests/helpers/utils"; import { FieldOne2Many } from "web.relational_fields"; import { FieldChar as LegacyFieldChar } from "web.basic_fields"; @@ -4254,6 +4255,78 @@ QUnit.module("Views", (hooks) => { assert.strictEqual(nbWrite, 1, "one write RPC should have been done"); }); + QUnit.test("keynav switching to another record from a dirty one", async function (assert) { + let nbWrite = 0; + await makeView({ + type: "form", + resModel: "partner", + serverData, + arch: '
    ', + resIds: [1, 2], + resId: 1, + mockRPC(route) { + if (route === "/web/dataset/call_kw/partner/write") { + nbWrite++; + } + }, + }); + + assert.strictEqual( + target.querySelector(".o_pager_value").textContent, + "1", + "pager value should be 1" + ); + assert.strictEqual( + target.querySelector(".o_pager_limit").textContent, + "2", + "pager limit should be 2" + ); + + // switch to edit mode + await click(target.querySelector(".o_form_button_edit")); + assert.strictEqual( + target.querySelector(".o_field_widget[name=foo] input").value, + "yop", + "input should contain yop" + ); + + // edit the foo field + const input = target.querySelector(".o_field_widget[name=foo] input"); + input.value = "new value"; + await triggerEvent(input, null, "input"); + + // click on the pager to switch to the next record (will save record) + triggerHotkey("alt+n"); + await nextTick(); + assert.containsNone(document.body, ".modal", "no confirm modal should be displayed"); + assert.strictEqual( + target.querySelector(".o_pager_value").textContent, + "2", + "pager value should be 2" + ); + assert.strictEqual( + target.querySelector(".o_field_widget[name=foo] input").value, + "blip", + "input should contain blip" + ); + + triggerHotkey("alt+p"); + await nextTick(); + assert.containsNone(document.body, ".modal", "no confirm modal should be displayed"); + assert.strictEqual( + target.querySelector(".o_pager_value").textContent, + "1", + "pager value should be 1" + ); + assert.strictEqual( + target.querySelector(".o_field_widget[name=foo] input").value, + "new value", + "input should contain new value" + ); + + assert.strictEqual(nbWrite, 1, "one write RPC should have been done"); + }); + QUnit.test("handling dirty state: switching to another record", async function (assert) { await makeView({ type: "form",