Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions src/oca_pre_commit_hooks/checks_odoo_module_xml.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,33 @@ class ChecksOdooModuleXML(BaseChecker):
xpath_xpath = etree.XPath("//xpath")
xpath_oe_chatter = etree.XPath("//div[hasclass('oe_chatter')]")

# Mapping ``{deprecated_class: replacement}`` for ``check_xml_deprecated_css_class``.
# Each entry is a one-to-one substitution that does not depend on the
# element's tag, parent, or surrounding markup. Ambiguous cases (e.g.
# ``oe_inline``, where the BS5 replacement depends on context) are
# intentionally omitted.
deprecated_css_classes = {
# Bootstrap 3 → 5 utility renames. Odoo bundles Bootstrap 5 since
# version 15.0.
"pull-left": "float-start",
"pull-right": "float-end",
"panel": "card",
"panel-default": "card",
"panel-heading": "card-header",
"panel-body": "card-body",
"panel-title": "card-title",
"panel-footer": "card-footer",
"img-responsive": "img-fluid",
"btn-default": "btn-secondary",
# Odoo legacy classes that were superseded by BS5 utilities.
"oe_left": "float-start",
"oe_right": "float-end",
"oe_grey": "text-muted",
}
xpath_deprecated_css_class = {
css_class: etree.XPath(f"//*[hasclass('{css_class}')]") for css_class in deprecated_css_classes
}

tree_deprecate_attrs = {"string", "colors", "fonts"}
xpath_tree_deprecated = etree.XPath(f'.//tree[{"|".join(f"@{a}" for a in tree_deprecate_attrs)}]')

Expand Down Expand Up @@ -926,3 +953,37 @@ def check_xml_deprecated_oe_chatter(self):
filepath=manifest_data["filename_short"],
line=xpath_node.sourceline,
)

@utils.only_required_for_checks("xml-deprecated-css-class")
def check_xml_deprecated_css_class(self):
"""* Check xml-deprecated-css-class

Detect legacy CSS classes in XML / QWeb views and suggest the
modern replacement. Two sources are covered:

* Bootstrap 3 utility classes that were renamed in Bootstrap 5.
Odoo bundles Bootstrap 5 since version 15.0, so any module
targeting 15.0+ should drop the legacy names.
* Odoo legacy classes (``oe_left``, ``oe_right``, ``oe_grey``)
that were superseded by Bootstrap 5 utilities.

Only unambiguous one-to-one mappings are flagged here; ambiguous
classes (``oe_inline``, ``oe_button_box``, …) are left out so the
rule can be enabled without manual review of every hit.
"""
if not self.module_version or (self.module_version and self.module_version < Version("15")):
return

for manifest_data in self.manifest_datas:
for css_class, replacement in self.deprecated_css_classes.items():
xpath = self.xpath_deprecated_css_class[css_class]
for xpath_node in xpath(manifest_data["node"]):
self.register_error(
code="xml-deprecated-css-class",
message=(
f"Deprecated CSS class {css_class!r}; "
f"replace with {replacement!r}."
),
filepath=manifest_data["filename_short"],
line=xpath_node.sourceline,
)
1 change: 1 addition & 0 deletions test_repo/odoo18_module/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
],
'data': [
'views/deprecated_chatter.xml',
'views/deprecated_css_class.xml',
'views/deprecated_qweb_directives15.xml',
],
}
20 changes: 20 additions & 0 deletions test_repo/odoo18_module/views/deprecated_css_class.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8" ?>
<record id="deprecated_css_class_view" model="ir.ui.view">
<field name="name">deprecated.css.view</field>
<field name="model">random.model</field>
<field name="arch" type="xml">
<form>
<div class="pull-right">Right-floated content</div>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Title</h3></div>
<div class="panel-body">Body</div>
<div class="panel-footer">Footer</div>
</div>
<img src="logo.png" class="img-responsive"/>
<button class="btn btn-default">Cancel</button>
<div class="oe_left">Old-style left</div>
<div class="oe_right">Old-style right</div>
<span class="oe_grey">Faded label</span>
</form>
</field>
</record>
1 change: 1 addition & 0 deletions tests/test_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"xml-header-missing": 2,
"xml-header-wrong": 18,
"xml-id-position-first": 9,
"xml-deprecated-css-class": 12,
"xml-deprecated-oe-chatter": 1,
"xml-field-bool-without-eval": 2,
"xml-field-numeric-without-eval": 7,
Expand Down
Loading