From b8d4c41331776cf2c99b8e0b7c035a844c8a8288 Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Wed, 3 Aug 2022 13:47:08 +0000 Subject: [PATCH] [FIX] web: Fix behaviors of ProgressBarField This commit fixes behavior issues in the progress bar field: - the progressbar would not write on a field if it was declared as 'readonly' on the server (it sounds counter-intuitive but this widget was supposed to write on records unless given the 'readonly' flag in the field options); - the "isEditable" prop was incorrectly computed, resulting in the field not being editable in kanban views when it should be; - when editing a value in the field, the focus should be automatically given to the first input. These issues have been fixed in this commit. closes odoo/odoo#97411 Signed-off-by: Bruno Boi (boi) --- .../progress_bar/kanban_progress_bar_field.js | 2 +- .../fields/progress_bar/progress_bar_field.js | 17 ++++---- .../progress_bar/progress_bar_field.xml | 15 +++---- .../src/views/kanban/kanban_arch_parser.js | 5 +++ .../views/fields/progress_bar_field_tests.js | 39 +++++++++++++++++++ 5 files changed, 63 insertions(+), 15 deletions(-) diff --git a/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js b/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js index 97c39bf4aa1..470d8bf67ff 100644 --- a/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js +++ b/addons/web/static/src/views/fields/progress_bar/kanban_progress_bar_field.js @@ -5,7 +5,7 @@ import { ProgressBarField } from "./progress_bar_field"; export class KanbanProgressBarField extends ProgressBarField { onClick() { - if (this.props.isEditable && !this.props.record.isReadonly(this.props.name)) { + if (this.props.isEditable) { this.state.isEditing = true; } } diff --git a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js index 58d001165d2..287061489f0 100644 --- a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js +++ b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.js @@ -1,10 +1,11 @@ /** @odoo-module **/ -import { registry } from "@web/core/registry"; import { _lt } from "@web/core/l10n/translation"; +import { registry } from "@web/core/registry"; +import { useAutofocus } from "@web/core/utils/hooks"; +import { useNumpadDecimal } from "../numpad_decimal_hook"; import { parseFloat } from "../parsers"; import { standardFieldProps } from "../standard_field_props"; -import { useNumpadDecimal } from "../numpad_decimal_hook"; const { Component, onWillUpdateProps, useState } = owl; const formatters = registry.category("formatters"); @@ -13,6 +14,8 @@ const parsers = registry.category("parsers"); export class ProgressBarField extends Component { setup() { useNumpadDecimal(); + useAutofocus({ refName: "max-value", selectAll: true }); + useAutofocus({ refName: "current-value", selectAll: true }); this.state = useState({ currentValue: this.getCurrentValue(this.props), maxValue: this.getMaxValue(this.props), @@ -62,10 +65,10 @@ export class ProgressBarField extends Component { return formatter(this.state.maxValue, { humanReadable }); } - onCurrentValueChange(value) { + onCurrentValueChange(ev) { let parsedValue; try { - parsedValue = parseFloat(value); + parsedValue = parseFloat(ev.target.value); } catch { this.props.record.setInvalidField(this.props.name); return; @@ -81,10 +84,10 @@ export class ProgressBarField extends Component { this.props.record.save(); } } - onMaxValueChange(value) { + onMaxValueChange(ev) { let parsedValue; try { - parsedValue = parseFloat(value); + parsedValue = parseFloat(ev.target.value); } catch { this.props.record.setInvalidField(this.props.name); return; @@ -151,7 +154,7 @@ ProgressBarField.extractProps = ({ attrs }) => { maxValueField: attrs.options.max_value, currentValueField: attrs.options.current_value, isPercentage: !attrs.options.max_value, - isEditable: attrs.options.editable, + isEditable: !attrs.options.readonly && attrs.options.editable, isEditableInReadonly: attrs.options.editable_readonly, isCurrentValueEditable: attrs.options.editable && diff --git a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.xml b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.xml index 20b0134418a..351fa5235fe 100644 --- a/addons/web/static/src/views/fields/progress_bar/progress_bar_field.xml +++ b/addons/web/static/src/views/fields/progress_bar/progress_bar_field.xml @@ -30,8 +30,8 @@ inputmode="numeric" t-att-value="formatCurrentValue() or ''" t-att-required="props.required" - t-on-change="(ev) => this.onCurrentValueChange(ev.target.value)" - t-on-input="(ev) => this.onCurrentValueInput(ev)" + t-on-change="onCurrentValueChange" + t-on-input="onCurrentValueInput" t-on-blur="onBlur" /> % @@ -40,23 +40,25 @@ @@ -65,4 +67,3 @@ - diff --git a/addons/web/static/src/views/kanban/kanban_arch_parser.js b/addons/web/static/src/views/kanban/kanban_arch_parser.js index ebf7ca3bc7a..5bf4b4a1ceb 100644 --- a/addons/web/static/src/views/kanban/kanban_arch_parser.js +++ b/addons/web/static/src/views/kanban/kanban_arch_parser.js @@ -72,6 +72,11 @@ export class KanbanArchParser extends XMLParser { node.setAttribute("widget", "many2many_tags"); } const fieldInfo = Field.parseFieldNode(node, models, modelName, "kanban", jsClass); + if (!node.hasAttribute("force_save")) { + // Force save is true by default on kanban views: + // this allows to write on any field regardless of its modifiers. + fieldInfo.forceSave = true; + } const name = fieldInfo.name; fieldNodes[name] = fieldInfo; node.setAttribute("field_id", name); diff --git a/addons/web/static/tests/views/fields/progress_bar_field_tests.js b/addons/web/static/tests/views/fields/progress_bar_field_tests.js index 0eeee07cece..9eb8d205239 100644 --- a/addons/web/static/tests/views/fields/progress_bar_field_tests.js +++ b/addons/web/static/tests/views/fields/progress_bar_field_tests.js @@ -364,6 +364,8 @@ QUnit.module("Fields", (hooks) => { QUnit.test("ProgressBarField: field is editable in kanban", async function (assert) { assert.expect(7); + + serverData.models.partner.fields.int_field.readonly = true; serverData.models.partner.records[0].int_field = 99; await makeView({ @@ -412,6 +414,7 @@ QUnit.module("Fields", (hooks) => { ); await editInput(target, ".o_progressbar_value.o_input", "69"); + assert.strictEqual( target.querySelector(".o_progressbar_value").textContent, "69 / 100", @@ -423,6 +426,42 @@ QUnit.module("Fields", (hooks) => { ); }); + QUnit.test("force readonly in kanban", async (assert) => { + assert.expect(3); + + serverData.models.partner.records[0].int_field = 99; + + await makeView({ + serverData, + type: "kanban", + resModel: "partner", + arch: /* xml */ ` + + + +
+ +
+
+
+
`, + resId: 1, + mockRPC(route, { method, args }) { + if (method === "write") { + throw new Error("Not supposed to write"); + } + }, + }); + + assert.strictEqual(target.querySelector(".o_progressbar_value").textContent, "99 / 100"); + + // Clicking on the progress bar should not change the value + await click(target.querySelector(".o_progress")); + + assert.strictEqual(target.querySelector(".o_progressbar_value").textContent, "99 / 100"); + assert.containsNone(target, ".o_progressbar_value.o_input"); + }); + QUnit.test( "ProgressBarField: readonly and editable attrs/options in kanban", async function (assert) {