[IMP] module_analysis: black, isort, prettier

pull/2608/head
Telmo Santos 2021-01-06 15:19:29 +01:00 committed by Florian da Costa
parent 2e88c5b31e
commit 8fc7d87806
19 changed files with 242 additions and 260 deletions

View File

@ -1,2 +1,2 @@
from . import models
from . post_init_hook import analyse_installed_modules
from .post_init_hook import analyse_installed_modules

View File

@ -3,32 +3,28 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': "Module Analysis",
'summary': "Add analysis tools regarding installed modules"
"name": "Module Analysis",
"summary": "Add analysis tools regarding installed modules"
" to know which installed modules comes from Odoo Core, OCA, or are"
" custom modules",
'author': 'GRAP, Odoo Community Association (OCA)',
'website': "https://github.com/OCA/server-tools/",
'version': '12.0.1.0.0',
'license': 'AGPL-3',
'depends': [
'base',
"author": "GRAP, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/server-tools/",
"version": "12.0.1.0.0",
"license": "AGPL-3",
"depends": ["base",],
"data": [
"security/ir.model.access.csv",
"views/menu.xml",
"views/view_base_module_update.xml",
"views/view_ir_module_author.xml",
"views/view_ir_module_type.xml",
"views/view_ir_module_type_rule.xml",
"views/view_ir_module_module.xml",
"data/ir_config_parameter.xml",
"data/ir_module_type.xml",
"data/ir_module_type_rule.xml",
],
'data': [
'security/ir.model.access.csv',
'views/menu.xml',
'views/view_base_module_update.xml',
'views/view_ir_module_author.xml',
'views/view_ir_module_type.xml',
'views/view_ir_module_type_rule.xml',
'views/view_ir_module_module.xml',
'data/ir_config_parameter.xml',
'data/ir_module_type.xml',
'data/ir_module_type_rule.xml',
],
'external_dependencies': {
'python': ['pygount'],
},
'post_init_hook': 'analyse_installed_modules',
'installable': True,
"external_dependencies": {"python": ["pygount"],},
"post_init_hook": "analyse_installed_modules",
"installable": True,
}

View File

@ -1,20 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo noupdate="1">
<record id="parameter_exclude_directories" model="ir.config_parameter">
<field name="key">module_analysis.exclude_directories</field>
<field name="value">lib,demo,test,tests,doc,description</field>
</record>
<record id="parameter_exclude_files" model="ir.config_parameter">
<field name="key">module_analysis.exclude_files</field>
<field name="value">__openerp__.py,__manifest__.py</field>
</record>
</odoo>

View File

@ -1,18 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="module_type_odoo" model="ir.module.type">
<field name="name">Odoo Core</field>
</record>
<record id="module_type_oca" model="ir.module.type">
<field name="name">OCA</field>
</record>
</odoo>

View File

@ -1,42 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<!-- Odoo Rules -->
<record id="module_type_rule_odoo_a" model="ir.module.type.rule">
<field name="sequence">1</field>
<field name="module_domain">[('author_ids', 'ilike', 'Odoo S.A')]</field>
<field name="module_type_id" ref="module_type_odoo"/>
<field name="module_type_id" ref="module_type_odoo" />
</record>
<record id="module_type_rule_odoo_b" model="ir.module.type.rule">
<field name="sequence">2</field>
<field name="module_domain">[('author_ids', 'ilike', 'OpenERP SA')]</field>
<field name="module_type_id" ref="module_type_odoo"/>
<field name="module_type_id" ref="module_type_odoo" />
</record>
<record id="module_type_rule_odoo_c" model="ir.module.type.rule">
<field name="sequence">3</field>
<field name="module_domain">[('author_ids', '=', 'Odoo SA')]</field>
<field name="module_type_id" ref="module_type_odoo"/>
<field name="module_type_id" ref="module_type_odoo" />
</record>
<record id="module_type_rule_odoo_d" model="ir.module.type.rule">
<field name="sequence">4</field>
<field name="module_domain">[('author_ids', '=', 'Odoo')]</field>
<field name="module_type_id" ref="module_type_odoo"/>
<field name="module_type_id" ref="module_type_odoo" />
</record>
<!-- OCA Rules -->
<record id="module_type_rule_oca_a" model="ir.module.type.rule">
<field name="sequence">100</field>
<field name="module_domain">[('author_ids', '=', 'Odoo Community Association (OCA)')]</field>
<field name="module_type_id" ref="module_type_oca"/>
<field
name="module_domain"
>[('author_ids', '=', 'Odoo Community Association (OCA)')]</field>
<field name="module_type_id" ref="module_type_oca" />
</record>
</odoo>

View File

@ -6,13 +6,15 @@ from odoo import api, fields, models
class BaseModuleUpdate(models.TransientModel):
_inherit = 'base.module.update'
_inherit = "base.module.update"
analyse_installed_modules = fields.Boolean(
string='Analyse Installed Modules', default=True)
string="Analyse Installed Modules", default=True
)
@api.multi
def update_module(self):
return super(BaseModuleUpdate, self.with_context(
analyse_installed_modules=self.analyse_installed_modules)
return super(
BaseModuleUpdate,
self.with_context(analyse_installed_modules=self.analyse_installed_modules),
).update_module()

View File

@ -6,34 +6,41 @@ from odoo import api, fields, models
class IrModuleAuthor(models.Model):
_name = 'ir.module.author'
_description = 'Modules Authors'
_name = "ir.module.author"
_description = "Modules Authors"
name = fields.Char(string='Name', required=True)
name = fields.Char(string="Name", required=True)
installed_module_ids = fields.Many2many(
string='Modules', comodel_name='ir.module.module',
relation='ir_module_module_author_rel')
string="Modules",
comodel_name="ir.module.module",
relation="ir_module_module_author_rel",
)
installed_module_qty = fields.Integer(
string="Installed Modules Quantity",
compute='_compute_installed_module_qty', store=True)
compute="_compute_installed_module_qty",
store=True,
)
_sql_constraints = [
('name_uniq', 'unique(name)',
'The name of the modules author should be unique per database!'),
(
"name_uniq",
"unique(name)",
"The name of the modules author should be unique per database!",
),
]
@api.multi
@api.depends('installed_module_ids')
@api.depends("installed_module_ids")
def _compute_installed_module_qty(self):
for author in self:
author.installed_module_qty = len(author.installed_module_ids)
@api.model
def _get_or_create(self, name):
authors = self.search([('name', '=', name)])
authors = self.search([("name", "=", name)])
if authors:
return authors[0]
else:
return self.create({'name': name})
return self.create({"name": name})

View File

@ -2,39 +2,40 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import os
import pygount
from pathlib import Path
import logging
import os
from pathlib import Path
import pygount
from odoo import api, fields, models
from odoo.tools.safe_eval import safe_eval
from odoo.modules.module import get_module_path
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__)
class IrModuleModule(models.Model):
_inherit = 'ir.module.module'
_inherit = "ir.module.module"
author_ids = fields.Many2many(
string='Authors', comodel_name='ir.module.author', readonly=True,
relation='ir_module_module_author_rel')
string="Authors",
comodel_name="ir.module.author",
readonly=True,
relation="ir_module_module_author_rel",
)
module_type_id = fields.Many2one(
string='Module Type', comodel_name='ir.module.type', readonly=True)
string="Module Type", comodel_name="ir.module.type", readonly=True
)
python_code_qty = fields.Integer(
string='Python Code Quantity', readonly=True)
python_code_qty = fields.Integer(string="Python Code Quantity", readonly=True)
xml_code_qty = fields.Integer(
string='XML Code Quantity', readonly=True)
xml_code_qty = fields.Integer(string="XML Code Quantity", readonly=True)
js_code_qty = fields.Integer(
string='JS Code Quantity', readonly=True)
js_code_qty = fields.Integer(string="JS Code Quantity", readonly=True)
css_code_qty = fields.Integer(
string='CSS Code Quantity', readonly=True)
css_code_qty = fields.Integer(string="CSS Code Quantity", readonly=True)
# Overloadable Section
@api.model
@ -51,76 +52,69 @@ class IrModuleModule(models.Model):
field_name: Odoo field name to store the analysis
"""
return {
'.py': {
'code': 'python_code_qty',
},
'.xml': {
'code': 'xml_code_qty',
},
'.js': {
'code': 'js_code_qty',
},
'.css': {
'code': 'css_code_qty',
},
".py": {"code": "python_code_qty",},
".xml": {"code": "xml_code_qty",},
".js": {"code": "js_code_qty",},
".css": {"code": "css_code_qty",},
}
@api.model
def _get_clean_analyse_values(self):
"""List of fields to unset when a module is uninstalled"""
return {
'author_ids': [6, 0, []],
'module_type_id': False,
'python_code_qty': False,
'xml_code_qty': 0,
'js_code_qty': 0,
'css_code_qty': 0,
"author_ids": [6, 0, []],
"module_type_id": False,
"python_code_qty": False,
"xml_code_qty": 0,
"js_code_qty": 0,
"css_code_qty": 0,
}
@api.model
def _get_module_encoding(self, file_ext):
return 'utf-8'
return "utf-8"
# Overload Section
@api.model
def update_list(self):
res = super().update_list()
if self.env.context.get('analyse_installed_modules', False):
self.search([('state', '=', 'installed')]).button_analyse_code()
if self.env.context.get("analyse_installed_modules", False):
self.search([("state", "=", "installed")]).button_analyse_code()
return res
@api.multi
def write(self, vals):
res = super().write(vals)
if vals.get('state', False) == 'installed':
if vals.get("state", False) == "installed":
self.button_analyse_code()
elif vals.get('state', False) == 'uninstalled'\
and 'module_analysis' not in [x.name for x in self]:
elif vals.get("state", False) == "uninstalled" and "module_analysis" not in [
x.name for x in self
]:
self.write(self._get_clean_analyse_values())
return res
# Public Section
@api.multi
def button_analyse_code(self):
IrModuleAuthor = self.env['ir.module.author']
IrModuleTypeRule = self.env['ir.module.type.rule']
IrModuleAuthor = self.env["ir.module.author"]
IrModuleTypeRule = self.env["ir.module.type.rule"]
rules = IrModuleTypeRule.search([])
cfg = self.env['ir.config_parameter']
val = cfg.get_param('module_analysis.exclude_directories', '')
exclude_directories = [x.strip() for x in val.split(',') if x.strip()]
val = cfg.get_param('module_analysis.exclude_files', '')
exclude_files = [x.strip() for x in val.split(',') if x.strip()]
cfg = self.env["ir.config_parameter"]
val = cfg.get_param("module_analysis.exclude_directories", "")
exclude_directories = [x.strip() for x in val.split(",") if x.strip()]
val = cfg.get_param("module_analysis.exclude_files", "")
exclude_files = [x.strip() for x in val.split(",") if x.strip()]
for module in self:
_logger.info("Analysing Code for module %s ..." % (module.name))
# Update Authors, based on manifest key
authors = []
if module.author and module.author[0] == '[':
if module.author and module.author[0] == "[":
author_txt_list = safe_eval(module.author)
else:
author_txt_list = module.author.split(',')
author_txt_list = module.author.split(",")
author_txt_list = [x.strip() for x in author_txt_list]
author_txt_list = [x for x in author_txt_list if x]
@ -141,27 +135,28 @@ class IrModuleModule(models.Model):
analysed_datas = self._get_analyse_data_dict()
file_extensions = analysed_datas.keys()
file_list = self._get_files_to_analyse(
module_path, file_extensions, exclude_directories,
exclude_files)
module_path, file_extensions, exclude_directories, exclude_files
)
for file_path, file_ext in file_list:
file_res = pygount.source_analysis(
file_path, '',
encoding=self._get_module_encoding(file_ext))
file_path, "", encoding=self._get_module_encoding(file_ext)
)
for k, v in analysed_datas.get(file_ext).items():
v['value'] += getattr(file_res, k)
v["value"] += getattr(file_res, k)
# Update the module with the datas
values = {}
for file_ext, analyses in analysed_datas.items():
for k, v in analyses.items():
values[v['field']] = v['value']
values[v["field"]] = v["value"]
module.write(values)
# Custom Section
@api.model
def _get_files_to_analyse(
self, path, file_extensions, exclude_directories, exclude_files):
self, path, file_extensions, exclude_directories, exclude_files
):
res = []
for root, dirs, files in os.walk(path, followlinks=True):
if set(Path(root).parts) & set(exclude_directories):
@ -179,8 +174,5 @@ class IrModuleModule(models.Model):
res_dict = self._get_analyse_settings().copy()
for file_ext, analyse_dict in res_dict.items():
for analyse_type, v in analyse_dict.items():
analyse_dict[analyse_type] = {
'field': v,
'value': 0
}
analyse_dict[analyse_type] = {"field": v, "value": 0}
return res_dict

View File

@ -6,25 +6,26 @@ from odoo import api, fields, models
class IrModuleType(models.Model):
_name = 'ir.module.type'
_description = 'Modules Types'
_order = 'sequence'
_name = "ir.module.type"
_description = "Modules Types"
_order = "sequence"
name = fields.Char(string='Name', required=True)
name = fields.Char(string="Name", required=True)
sequence = fields.Integer(string='Sequence')
sequence = fields.Integer(string="Sequence")
installed_module_ids = fields.One2many(
string='Installed Modules', comodel_name='ir.module.module',
inverse_name='module_type_id')
string="Installed Modules",
comodel_name="ir.module.module",
inverse_name="module_type_id",
)
installed_module_qty = fields.Integer(
string='Modules Quantity', compute='_compute_installed_module_qty',
store=True)
string="Modules Quantity", compute="_compute_installed_module_qty", store=True
)
@api.multi
@api.depends('installed_module_ids.module_type_id')
@api.depends("installed_module_ids.module_type_id")
def _compute_installed_module_qty(self):
for module_type in self:
module_type.installed_module_qty = len(
module_type.installed_module_ids)
module_type.installed_module_qty = len(module_type.installed_module_ids)

View File

@ -7,24 +7,24 @@ from odoo.tools.safe_eval import safe_eval
class IrModuleType(models.Model):
_name = 'ir.module.type.rule'
_description = 'Modules Types Rules'
_order = 'sequence'
_name = "ir.module.type.rule"
_description = "Modules Types Rules"
_order = "sequence"
sequence = fields.Integer(string='Sequence')
sequence = fields.Integer(string="Sequence")
module_domain = fields.Char(
string='Module Domain', required=True, default='[]')
module_domain = fields.Char(string="Module Domain", required=True, default="[]")
module_type_id = fields.Many2one(
string='Module type', comodel_name='ir.module.type', required=True)
string="Module type", comodel_name="ir.module.type", required=True
)
@api.multi
def _get_module_type_id_from_module(self, module):
IrModuleModule = self.env['ir.module.module']
IrModuleModule = self.env["ir.module.module"]
for rule in self:
domain = safe_eval(rule.module_domain)
domain.append(('id', '=', module.id))
domain.append(("id", "=", module.id))
if IrModuleModule.search(domain):
return rule.module_type_id.id
return False

View File

@ -2,12 +2,13 @@
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import api, SUPERUSER_ID
from odoo import SUPERUSER_ID, api
def analyse_installed_modules(cr, registry):
with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
installed_modules = env['ir.module.module'].search(
[('state', '=', 'installed')])
installed_modules = env["ir.module.module"].search(
[("state", "=", "installed")]
)
installed_modules.button_analyse_code()

View File

@ -5,4 +5,3 @@ Open the stats to analyse the detail of the code installed
.. image:: ../static/description/analysis_pivot.png
.. image:: ../static/description/analysis_pie.png

View File

@ -7,27 +7,26 @@ from odoo.tests.common import TransactionCase, post_install
@post_install(True)
class TestModule(TransactionCase):
def setUp(self):
super().setUp()
self.IrModuleModule = self.env['ir.module.module']
self.IrModuleModule = self.env["ir.module.module"]
def test_installed_modules(self):
installed_modules = self.IrModuleModule.search(
[('state', '=', 'installed')])
installed_modules = self.IrModuleModule.search([("state", "=", "installed")])
for module in installed_modules:
self.assertTrue(
module.python_code_qty > 0 or
module.xml_code_qty > 0 or
module.js_code_qty > 0,
module.python_code_qty > 0
or module.xml_code_qty > 0
or module.js_code_qty > 0,
"module '%s' doesn't have code analysed defined, whereas it is"
" installed." % (module.name))
" installed." % (module.name),
)
def test_uninstalled_modules(self):
uninstalled_modules = self.IrModuleModule.search(
[('state', '!=', 'installed')])
uninstalled_modules = self.IrModuleModule.search([("state", "!=", "installed")])
for module in uninstalled_modules:
self.assertTrue(
module.python_code_qty == 0,
"module '%s' has python lines defined, whereas it is"
" not installed." % (module.name))
" not installed." % (module.name),
)

View File

@ -1,24 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<menuitem id="menu_module_analysis"
<menuitem
id="menu_module_analysis"
name="Analysis"
parent="base.menu_management" sequence="100"
groups="base.group_no_one"/>
<menuitem id="menu_module_analysis_settings"
parent="base.menu_management"
sequence="100"
groups="base.group_no_one"
/>
<menuitem
id="menu_module_analysis_settings"
name="Settings"
parent="menu_module_analysis" sequence="10"/>
<menuitem id="menu_module_analysis_reporting"
parent="menu_module_analysis"
sequence="10"
/>
<menuitem
id="menu_module_analysis_reporting"
name="Reporting"
parent="menu_module_analysis" sequence="20"/>
parent="menu_module_analysis"
sequence="20"
/>
</odoo>

View File

@ -1,20 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_base_module_update_form" model="ir.ui.view">
<field name="model">base.module.update</field>
<field name="inherit_id" ref="base.view_base_module_update"/>
<field name="inherit_id" ref="base.view_base_module_update" />
<field name="arch" type="xml">
<xpath expr='//group[@states="init"]' position="inside">
<field name="analyse_installed_modules"/>
<field name="analyse_installed_modules" />
</xpath>
</field>
</record>
</odoo>

View File

@ -1,40 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_ir_module_author_form" model="ir.ui.view">
<field name="model">ir.module.author</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_title">
<div class="oe_edit_only"><label for="name"/></div>
<h1><field name="name"/></h1>
<div class="oe_edit_only">
<label for="name" />
</div>
<h1>
<field name="name" />
</h1>
</div>
<group>
<field name="installed_module_qty"/>
<field name="installed_module_qty" />
</group>
</sheet>
</form>
</field>
</record>
<record id="view_ir_module_author_tree" model="ir.ui.view">
<field name="model">ir.module.author</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="installed_module_qty"/>
<field name="name" />
<field name="installed_module_qty" />
</tree>
</field>
</record>
<record id="action_ir_module_author" model="ir.actions.act_window">
<field name="name">Modules Authors</field>
<field name="type">ir.actions.act_window</field>
@ -42,11 +41,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_module_authors"
parent="menu_module_analysis_settings" sequence="1"
<menuitem
id="menu_module_authors"
parent="menu_module_analysis_settings"
sequence="1"
action="action_ir_module_author"
groups="base.group_no_one"/>
groups="base.group_no_one"
/>
</odoo>

View File

@ -1,55 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_ir_module_module_form" model="ir.ui.view">
<field name="model">ir.module.module</field>
<field name="inherit_id" ref="base.module_form"/>
<field name="inherit_id" ref="base.module_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='state']/.." position="after">
<button name="button_analyse_code" states="installed" string="Refresh Code Analysis" type="object" class="btn btn-primary"/>
<button
name="button_analyse_code"
states="installed"
string="Refresh Code Analysis"
type="object"
class="btn btn-primary"
/>
<group string="Code Size" col="4">
<field name="python_code_qty"/>
<field name="xml_code_qty"/>
<field name="js_code_qty"/>
<field name="css_code_qty"/>
<field name="python_code_qty" />
<field name="xml_code_qty" />
<field name="js_code_qty" />
<field name="css_code_qty" />
</group>
<group string="Type and Authors">
<field name="author_ids" widget="many2many_tags"/>
<field name="module_type_id"/>
<field name="author_ids" widget="many2many_tags" />
<field name="module_type_id" />
</group>
</xpath>
</field>
</record>
<record id="view_ir_module_module_pivot" model="ir.ui.view">
<field name="model">ir.module.module</field>
<field name="arch" type="xml">
<pivot>
<field name="module_type_id" type="row"/>
<field name="python_code_qty" type="measure"/>
<field name="xml_code_qty" type="measure"/>
<field name="js_code_qty" type="measure"/>
<field name="css_code_qty" type="measure"/>
<field name="module_type_id" type="row" />
<field name="python_code_qty" type="measure" />
<field name="xml_code_qty" type="measure" />
<field name="js_code_qty" type="measure" />
<field name="css_code_qty" type="measure" />
</pivot>
</field>
</record>
<record id="view_ir_module_module_graph" model="ir.ui.view">
<field name="model">ir.module.module</field>
<field name="arch" type="xml">
<graph type="pie">
<field name="module_type_id" type="row"/>
<field name="module_type_id" type="row" />
</graph>
</field>
</record>
<record id="action_ir_module_module_by_type" model="ir.actions.act_window">
<field name="name">Installed Modules by Types</field>
<field name="type">ir.actions.act_window</field>
@ -58,10 +58,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field>
<field name="view_mode">pivot,graph</field>
</record>
<menuitem id="menu_module_by_type"
parent="menu_module_analysis_reporting" sequence="5"
<menuitem
id="menu_module_by_type"
parent="menu_module_analysis_reporting"
sequence="5"
action="action_ir_module_module_by_type"
groups="base.group_no_one"/>
groups="base.group_no_one"
/>
</odoo>

View File

@ -1,20 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_ir_module_type_form" model="ir.ui.view">
<field name="model">ir.module.type</field>
<field name="arch" type="xml">
<form>
<sheet>
<div class="oe_title">
<div class="oe_edit_only"><label for="name"/></div>
<h1><field name="name"/></h1>
<div class="oe_edit_only">
<label for="name" />
</div>
<h1>
<field name="name" />
</h1>
</div>
<group>
</group>
@ -22,17 +24,15 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</form>
</field>
</record>
<record id="view_ir_module_type_tree" model="ir.ui.view">
<field name="model">ir.module.type</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="installed_module_qty"/>
<field name="name" />
<field name="installed_module_qty" />
</tree>
</field>
</record>
<record id="action_ir_module_type" model="ir.actions.act_window">
<field name="name">Modules Types</field>
<field name="type">ir.actions.act_window</field>
@ -40,11 +40,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_module_types"
parent="menu_module_analysis_settings" sequence="2"
<menuitem
id="menu_module_types"
parent="menu_module_analysis_settings"
sequence="2"
action="action_ir_module_type"
groups="base.group_no_one"/>
groups="base.group_no_one"
/>
</odoo>

View File

@ -1,23 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
@author: Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo>
<record id="view_ir_module_type_rule_tree" model="ir.ui.view">
<field name="model">ir.module.type.rule</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="sequence" widget="handle"/>
<field name="module_type_id"/>
<field name="module_domain"/>
<field name="sequence" widget="handle" />
<field name="module_type_id" />
<field name="module_domain" />
</tree>
</field>
</record>
<record id="action_ir_module_type_rule" model="ir.actions.act_window">
<field name="name">Modules Types Rules</field>
<field name="type">ir.actions.act_window</field>
@ -25,10 +22,11 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
<field name="view_type">form</field>
<field name="view_mode">tree</field>
</record>
<menuitem id="menu_module_type_rules"
parent="menu_module_analysis_settings" sequence="3"
<menuitem
id="menu_module_type_rules"
parent="menu_module_analysis_settings"
sequence="3"
action="action_ir_module_type_rule"
groups="base.group_no_one"/>
groups="base.group_no_one"
/>
</odoo>