From c074c26abcfe5a7fe6b41c05b7203d8b772735fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 23 Apr 2026 12:47:01 +0200 Subject: [PATCH] Do not render buttons in readonly screen Closes #14803 --- sao/src/screen.js | 6 ++++-- sao/src/view/form.js | 11 ++++++++--- sao/src/view/tree.js | 3 +++ tryton/tryton/gui/window/view_form/screen/screen.py | 6 ++++-- tryton/tryton/gui/window/view_form/view/form.py | 9 ++++++--- tryton/tryton/gui/window/view_form/view/list.py | 2 ++ 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/sao/src/screen.js b/sao/src/screen.js index 973c719f53..6794dc0842 100644 --- a/sao/src/screen.js +++ b/sao/src/screen.js @@ -836,10 +836,12 @@ this._current_domain = []; this.offset = 0; this.order = this.default_order = attributes.order; - this.readonly = this.attributes.readonly || false; + this.screen_readonly = this.attributes.readonly || false; var access = Sao.common.MODELACCESS.get(model_name); if (!(access.write || access.create)) { this.readonly = true; + } else { + this.readonly = this.screen_readonly; } this.search_count = 0; this.new_group(attributes.context || {}); @@ -2015,7 +2017,7 @@ get_buttons: function() { var selected_records = ( this.current_view ? this.current_view.selected_records : []); - if (jQuery.isEmptyObject(selected_records)) { + if (jQuery.isEmptyObject(selected_records) || this.screen_readonly) { return []; } var buttons = ( diff --git a/sao/src/view/form.js b/sao/src/view/form.js index a6ca70a50a..ef48cdfdef 100644 --- a/sao/src/view/form.js +++ b/sao/src/view/form.js @@ -130,9 +130,14 @@ function eval_pyson(value){ } }, _parse_button: function(node, attributes) { - var button = new Sao.common.Button(attributes); - button.el.click(button, this.view.button_clicked.bind(this.view)); - this.view.state_widgets.push(button); + let button; + if (this.view.screen.screen_readonly) { + button = null; + } else { + button = new Sao.common.Button(attributes); + button.el.click(button, this.view.button_clicked.bind(this.view)); + this.view.state_widgets.push(button); + } this.container.add(button, attributes); }, _parse_link: function(node, attributes) { diff --git a/sao/src/view/tree.js b/sao/src/view/tree.js index 66bf9300eb..9128575d69 100644 --- a/sao/src/view/tree.js +++ b/sao/src/view/tree.js @@ -87,6 +87,9 @@ } }, _parse_button: function(node, attributes) { + if (this.view.screen.screen_readonly) { + return; + } let button; if (parseInt(attributes.multiple || '0', 10)) { button = new Sao.View.Tree.ButtonMultiple(attributes); diff --git a/tryton/tryton/gui/window/view_form/screen/screen.py b/tryton/tryton/gui/window/view_form/screen/screen.py index 8d20be8f70..7e69a7aba8 100644 --- a/tryton/tryton/gui/window/view_form/screen/screen.py +++ b/tryton/tryton/gui/window/view_form/screen/screen.py @@ -49,10 +49,12 @@ class Screen: self.offset = 0 self.windows = [] - self.readonly = attributes.get('readonly', False) + self.screen_readonly = attributes.get('readonly', False) if not (MODELACCESS[model_name]['write'] or MODELACCESS[model_name]['create']): self.readonly = True + else: + self.readonly = self.screen_readonly self.search_count = 0 if not attributes.get('row_activate'): self.row_activate = self.default_row_activate @@ -1245,7 +1247,7 @@ class Screen: states = record.expr_eval(button.attrs.get('states', {})) return not (states.get('invisible') or states.get('readonly')) - if not self.selected_records: + if not self.selected_records or self.screen_readonly: return [] buttons = self.current_view.get_buttons() if self.current_view else [] diff --git a/tryton/tryton/gui/window/view_form/view/form.py b/tryton/tryton/gui/window/view_form/view/form.py index f77133110a..694ff6de67 100644 --- a/tryton/tryton/gui/window/view_form/view/form.py +++ b/tryton/tryton/gui/window/view_form/view/form.py @@ -261,9 +261,12 @@ class FormXMLViewParser(XMLViewParser): label.set_mnemonic_widget(widget.mnemonic_widget) def _parse_button(self, node, attributes): - button = Button(attributes) - button.connect('clicked', self.view.button_clicked) - self.view.state_widgets.append(button) + if self.view.screen.screen_readonly: + button = None + else: + button = Button(attributes) + button.connect('clicked', self.view.button_clicked) + self.view.state_widgets.append(button) self.container.add(button, attributes) def _parse_link(self, node, attributes): diff --git a/tryton/tryton/gui/window/view_form/view/list.py b/tryton/tryton/gui/window/view_form/view/list.py index 19aef93008..2abd38bd79 100644 --- a/tryton/tryton/gui/window/view_form/view/list.py +++ b/tryton/tryton/gui/window/view_form/view/list.py @@ -372,6 +372,8 @@ class TreeXMLViewParser(XMLViewParser): self.view.optionals[column.name].append(column) def _parse_button(self, node, attributes): + if self.view.screen.screen_readonly: + return if int(attributes.get('multiple', 0)): button = ButtonMutiple(attributes) button.connect('clicked', self.view.button_clicked)