[FIX] base: res.config.settings must not have <t> nodes
The res.config.settings form view is handled with a custom widget expecting a very specific structure. a `<t>` node in the middle of `<div class="settings">` and `<div class="app_settings_block">` screws things up, and the app block will no longer be shown as expected in the web interface. This issue has been introduced with odoo/odoo#103799 The current revision reverts the change so it becomes as before, the `<t>` blocks with only `groups="..."` are removed from the architecture, even if they have not been added by the postprocessing itself. An alternative fix is done, directly in the `web_studio` module of odoo/enterprise, to overcome the issue odoo/odoo#103799 was solving. Both issues are covered with unit tests: - the issue odoo/odoo#103799 was solving is covered with the unit test added in the related odoo/enterprise#33075 - the issue solved by the current revision is covered with units tests added in this revision directly. closes odoo/odoo#104542 X-original-commit: 56d2de23919f9efa3cd1eef756725e8bc9b86d81 Related: odoo/enterprise#33410 Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
This commit is contained in:
@@ -1036,7 +1036,7 @@ actual arch.
|
||||
for node in tree.xpath('//*[@groups]'):
|
||||
if not self.user_has_groups(node.attrib.pop('groups')):
|
||||
node.getparent().remove(node)
|
||||
elif node.get('postprocess_remove'):
|
||||
elif node.tag == 't' and not node.attrib:
|
||||
# Move content of <t> blocks created in `_postprocess_tag_field` to the parent
|
||||
# and remove the <t> node.
|
||||
# This is to keep the structure
|
||||
@@ -1223,7 +1223,7 @@ actual arch.
|
||||
# set on the field in the Python model
|
||||
# e.g. <t groups="base.group_system"><field name="foo" groups="base.group_no_one"/></t>
|
||||
# The <t> node will be removed later, in _postprocess_access_rights.
|
||||
node_t = E.t(groups=field.groups, postprocess_remove="1")
|
||||
node_t = E.t(groups=field.groups)
|
||||
node.getparent().replace(node, node_t)
|
||||
node_t.append(node)
|
||||
else:
|
||||
|
||||
@@ -85,6 +85,68 @@ class TestResConfig(TransactionCase):
|
||||
# Check returned value
|
||||
self.assertEqual(res.args[0], self.expected_final_error_msg_wo_menu)
|
||||
|
||||
def test_40_view_expected_architecture(self):
|
||||
"""Tests the res.config.settings form view architecture expected by the web client.
|
||||
The res.config.settings form view is handled with a custom widget expecting a very specific
|
||||
structure. This architecture is tested extensively in Javascript unit tests.
|
||||
Here we briefly ensure the view sent by the server to the web client has the right architecture,
|
||||
the right blocks with the right classes in the right order.
|
||||
This tests is to ensure the specification/requirements are listed and tested server side, and
|
||||
if a change occurs in future development, this test will need to be adapted to specify these changes."""
|
||||
view = self.env['ir.ui.view'].create({
|
||||
'name': 'foo',
|
||||
'type': 'form',
|
||||
'model': 'res.config.settings',
|
||||
'inherit_id': self.env.ref('base.res_config_settings_view_form').id,
|
||||
'arch': """
|
||||
<xpath expr="//div[hasclass('settings')]" position="inside">
|
||||
<t groups="base.group_system">
|
||||
<div class="app_settings_block" data-string="Foo" string="Foo" data-key="foo">
|
||||
<h2>Foo</h2>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
""",
|
||||
})
|
||||
arch = self.env['res.config.settings'].get_view(view.id)['arch']
|
||||
tree = etree.fromstring(arch)
|
||||
self.assertTrue(tree.xpath("""
|
||||
//form[@class="oe_form_configuration o_base_settings"]
|
||||
/div[@class="o_setting_container"]
|
||||
/div[@class="settings"]
|
||||
/div[@class="app_settings_block"][@data-key="foo"]
|
||||
"""), 'The res.config.settings form view architecture is not what is expected by the web client.')
|
||||
|
||||
def test_50_view_expected_architecture_t_node_groups(self):
|
||||
"""Tests the behavior of the res.config.settings form view postprocessing when a block `app_settings_block`
|
||||
is wrapped in a `<t groups="...">`, which is used when you need to display an app settings section
|
||||
only for users part of two groups at the same time."""
|
||||
view = self.env['ir.ui.view'].create({
|
||||
'name': 'foo',
|
||||
'type': 'form',
|
||||
'model': 'res.config.settings',
|
||||
'inherit_id': self.env.ref('base.res_config_settings_view_form').id,
|
||||
'arch': """
|
||||
<xpath expr="//div[hasclass('settings')]" position="inside">
|
||||
<t groups="base.group_system">
|
||||
<div class="app_settings_block" data-string="Foo"
|
||||
string="Foo" data-key="foo" groups="base.group_no_one">
|
||||
<h2>Foo</h2>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
""",
|
||||
})
|
||||
with self.debug_mode():
|
||||
arch = self.env['res.config.settings'].get_view(view.id)['arch']
|
||||
tree = etree.fromstring(arch)
|
||||
# The <t> must be removed from the structure
|
||||
self.assertFalse(tree.xpath('//t'), 'The `<t groups="...">` block must not remain in the view')
|
||||
self.assertTrue(tree.xpath("""
|
||||
//div[@class="settings"]
|
||||
/div[@class="app_settings_block"][@data-key="foo"]
|
||||
"""), 'The `class="app_settings_block"` block must be a direct child of the `class="settings"` block')
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestResConfigExecute(TransactionCase):
|
||||
|
||||
Reference in New Issue
Block a user