From 0d15ce1df884ae70dbcc066a8ba5bec42ab6a2c7 Mon Sep 17 00:00:00 2001 From: Sylvain LE GAL Date: Wed, 26 Oct 2022 16:53:50 +0200 Subject: [PATCH] [IMP] web_dashboard_tile: black, isort, prettier --- .../odoo/addons/web_dashboard_tile | 1 + setup/web_dashboard_tile/setup.py | 6 + web_dashboard_tile/controllers/main.py | 13 +- web_dashboard_tile/demo/tile_category.xml | 6 +- web_dashboard_tile/demo/tile_tile.xml | 28 +-- .../migrations/12.0.1.0.0/post-migration.py | 20 +- web_dashboard_tile/models/tile_category.py | 61 +++--- web_dashboard_tile/models/tile_tile.py | 99 +++++----- web_dashboard_tile/readme/CONFIGURE.rst | 1 - web_dashboard_tile/readme/ROADMAP.rst | 1 - web_dashboard_tile/security/ir_rule.xml | 4 +- .../static/src/css/web_dashboard_tile.css | 14 +- web_dashboard_tile/views/menu.xml | 14 +- web_dashboard_tile/views/templates.xml | 7 +- web_dashboard_tile/views/tile_category.xml | 49 +++-- web_dashboard_tile/views/tile_tile.xml | 181 +++++++++++------- 16 files changed, 293 insertions(+), 212 deletions(-) create mode 120000 setup/web_dashboard_tile/odoo/addons/web_dashboard_tile create mode 100644 setup/web_dashboard_tile/setup.py diff --git a/setup/web_dashboard_tile/odoo/addons/web_dashboard_tile b/setup/web_dashboard_tile/odoo/addons/web_dashboard_tile new file mode 120000 index 000000000..f721548b7 --- /dev/null +++ b/setup/web_dashboard_tile/odoo/addons/web_dashboard_tile @@ -0,0 +1 @@ +../../../../web_dashboard_tile \ No newline at end of file diff --git a/setup/web_dashboard_tile/setup.py b/setup/web_dashboard_tile/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/web_dashboard_tile/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/web_dashboard_tile/controllers/main.py b/web_dashboard_tile/controllers/main.py index 1f29fe29a..d561a67b9 100644 --- a/web_dashboard_tile/controllers/main.py +++ b/web_dashboard_tile/controllers/main.py @@ -2,14 +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.http import Controller, route, request +from odoo.http import Controller, request, route class WebDashboardTile(Controller): - - @route('/web_dashboard_tile/create_tile', type='json', auth='user') + @route("/web_dashboard_tile/create_tile", type="json", auth="user") def create_tile(self, model_name, *args, **kwargs): - IrModel = request.env['ir.model'] - model = IrModel.search([('model', '=', model_name)]) - kwargs.update({'model_id': model.id}) - return request.env['tile.tile'].create(kwargs) + IrModel = request.env["ir.model"] + model = IrModel.search([("model", "=", model_name)]) + kwargs.update({"model_id": model.id}) + return request.env["tile.tile"].create(kwargs) diff --git a/web_dashboard_tile/demo/tile_category.xml b/web_dashboard_tile/demo/tile_category.xml index c8be7c677..9a1da03d4 100644 --- a/web_dashboard_tile/demo/tile_category.xml +++ b/web_dashboard_tile/demo/tile_category.xml @@ -1,16 +1,16 @@ - + Modules 1 - + Currencies 2 - + diff --git a/web_dashboard_tile/demo/tile_tile.xml b/web_dashboard_tile/demo/tile_tile.xml index aca1a2d34..cd1550cb1 100644 --- a/web_dashboard_tile/demo/tile_tile.xml +++ b/web_dashboard_tile/demo/tile_tile.xml @@ -1,28 +1,32 @@ - + Installed Modules - - - - [['state', 'in', ['installed', 'to upgrade', 'to remove']]] + + + + [['state', 'in', ['installed', 'to upgrade', 'to remove']]] Installed OCA Modules - - - - [['state', 'in', ['installed', 'to upgrade', 'to remove']], ['author', 'ilike', 'Odoo Community Association (OCA)']] + + + + [['state', 'in', ['installed', 'to upgrade', 'to remove']], ['author', 'ilike', 'Odoo Community Association (OCA)']] Currencies (Max Rate) - - + + max - + [] diff --git a/web_dashboard_tile/migrations/12.0.1.0.0/post-migration.py b/web_dashboard_tile/migrations/12.0.1.0.0/post-migration.py index 118657c6d..16ecb2788 100644 --- a/web_dashboard_tile/migrations/12.0.1.0.0/post-migration.py +++ b/web_dashboard_tile/migrations/12.0.1.0.0/post-migration.py @@ -13,17 +13,15 @@ def migrate(cr, version): # categories was optional in previous versions # affecting all tiles without categories - tiles_without_category = env["tile.tile"].search( - [('category_id', '=', False)]) + tiles_without_category = env["tile.tile"].search([("category_id", "=", False)]) if tiles_without_category: - default_category = env["tile.category"].create({ - "name": "Default Category", - }) - tiles_without_category.write({ - 'category_id': default_category.id - }) + default_category = env["tile.category"].create( + { + "name": "Default Category", + } + ) + tiles_without_category.write({"category_id": default_category.id}) # Enable all categories, to generate actions and menus - categories = env['tile.category'].with_context( - active_test=False).search([]) - categories.write({'active': True}) + categories = env["tile.category"].with_context(active_test=False).search([]) + categories.write({"active": True}) diff --git a/web_dashboard_tile/models/tile_category.py b/web_dashboard_tile/models/tile_category.py index f43c96369..6a48073f0 100644 --- a/web_dashboard_tile/models/tile_category.py +++ b/web_dashboard_tile/models/tile_category.py @@ -17,23 +17,24 @@ class TileCategory(models.Model): active = fields.Boolean(default=True) action_id = fields.Many2one( - string='Odoo Action', comodel_name='ir.actions.act_window', - readonly=True) + string="Odoo Action", comodel_name="ir.actions.act_window", readonly=True + ) menu_id = fields.Many2one( - string='Odoo Menu', comodel_name='ir.ui.menu', readonly=True) + string="Odoo Menu", comodel_name="ir.ui.menu", readonly=True + ) tile_ids = fields.One2many( - string='Tiles', comodel_name='tile.tile', - inverse_name='category_id') + string="Tiles", comodel_name="tile.tile", inverse_name="category_id" + ) tile_qty = fields.Integer( - string='Tiles Quantity', - compute='_compute_tile_qty', + string="Tiles Quantity", + compute="_compute_tile_qty", store=True, ) - @api.depends('tile_ids') + @api.depends("tile_ids") def _compute_tile_qty(self): for category in self: category.tile_qty = len(category.tile_ids) @@ -41,34 +42,36 @@ class TileCategory(models.Model): def _prepare_action(self): self.ensure_one() return { - 'name': self.name, - 'res_model': 'tile.tile', - 'type': 'ir.actions.act_window', - 'view_mode': 'kanban', - 'domain': """[ + "name": self.name, + "res_model": "tile.tile", + "type": "ir.actions.act_window", + "view_mode": "kanban", + "domain": """[ ('hidden', '=', False), '|', ('user_id', '=', False), ('user_id', '=', uid), ('category_id', '=', {self.id}) - ]""".format(self=self), + ]""".format( + self=self + ), } def _prepare_menu(self): self.ensure_one() return { - 'name': self.name, - 'parent_id': self.env.ref( - 'web_dashboard_tile.menu_dashboard_tile').id, - 'action': 'ir.actions.act_window,%d' % self.action_id.id, - 'sequence': self.sequence, + "name": self.name, + "parent_id": self.env.ref("web_dashboard_tile.menu_dashboard_tile").id, + "action": "ir.actions.act_window,%d" % self.action_id.id, + "sequence": self.sequence, } def _create_ui(self): - IrUiMenu = self.env['ir.ui.menu'] - IrActionsActWindows = self.env['ir.actions.act_window'] + IrUiMenu = self.env["ir.ui.menu"] + IrActionsActWindows = self.env["ir.actions.act_window"] for category in self: if not category.action_id: category.action_id = IrActionsActWindows.create( - category._prepare_action()) + category._prepare_action() + ) if not category.menu_id: category.menu_id = IrUiMenu.create(category._prepare_menu()) @@ -88,16 +91,16 @@ class TileCategory(models.Model): def write(self, vals): res = super().write(vals) - if 'active' in vals.keys(): - if vals.get('active'): + if "active" in vals.keys(): + if vals.get("active"): self._create_ui() else: self._delete_ui() - if 'sequence' in vals.keys(): - self.mapped('menu_id').write({'sequence': vals['sequence']}) - if 'name' in vals.keys(): - self.mapped('menu_id').write({'name': vals['name']}) - self.mapped('action_id').write({'name': vals['name']}) + if "sequence" in vals.keys(): + self.mapped("menu_id").write({"sequence": vals["sequence"]}) + if "name" in vals.keys(): + self.mapped("menu_id").write({"name": vals["name"]}) + self.mapped("action_id").write({"name": vals["name"]}) return res def unlink(self): diff --git a/web_dashboard_tile/models/tile_tile.py b/web_dashboard_tile/models/tile_tile.py index 3eb408c58..e9f9a8d10 100644 --- a/web_dashboard_tile/models/tile_tile.py +++ b/web_dashboard_tile/models/tile_tile.py @@ -5,15 +5,15 @@ import datetime import time -from statistics import median -from dateutil.relativedelta import relativedelta from collections import OrderedDict +from statistics import median + +from dateutil.relativedelta import relativedelta from odoo import api, fields, models +from odoo.exceptions import ValidationError, except_orm from odoo.tools.safe_eval import safe_eval as eval from odoo.tools.translate import _ -from odoo.exceptions import ValidationError, except_orm - FIELD_FUNCTIONS = OrderedDict( [ @@ -81,8 +81,11 @@ class TileTile(models.Model): sequence = fields.Integer(default=0, required=True) category_id = fields.Many2one( - string="Category", comodel_name="tile.category", required=True, - ondelete="CASCADE") + string="Category", + comodel_name="tile.category", + required=True, + ondelete="CASCADE", + ) user_id = fields.Many2one(string="User", comodel_name="res.users") @@ -98,9 +101,7 @@ class TileTile(models.Model): "(that is, when User field is left empty)", ) - model_id = fields.Many2one( - comodel_name="ir.model", string="Model", required=True - ) + model_id = fields.Many2one(comodel_name="ir.model", string="Model", required=True) model_name = fields.Char(string="Model name", related="model_id.model") @@ -108,26 +109,30 @@ class TileTile(models.Model): action_id = fields.Many2one( comodel_name="ir.actions.act_window", - string="Action", help="Let empty to use the default action related to" - " the selected model.", - domain="[('res_model', '=', model_name)]") + string="Action", + help="Let empty to use the default action related to" " the selected model.", + domain="[('res_model', '=', model_name)]", + ) active = fields.Boolean( compute="_compute_active", search="_search_active", readonly=True ) hide_if_null = fields.Boolean( - string="Hide if null", help="If checked, the item will be hidden" - " if the primary value is null.") + string="Hide if null", + help="If checked, the item will be hidden" " if the primary value is null.", + ) hidden = fields.Boolean( - string="Hidden", compute="_compute_data", - search="_search_hidden") + string="Hidden", compute="_compute_data", search="_search_hidden" + ) # Primary Value primary_function = fields.Selection( - string="Primary Function", required=True, - selection=FIELD_FUNCTION_SELECTION, default="count", + string="Primary Function", + required=True, + selection=FIELD_FUNCTION_SELECTION, + default="count", ) primary_field_id = fields.Many2one( @@ -143,19 +148,20 @@ class TileTile(models.Model): "ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000.", ) - primary_value = fields.Float( - string="Primary Value", compute="_compute_data") + primary_value = fields.Float(string="Primary Value", compute="_compute_data") primary_formated_value = fields.Char( - string="Primary Formated Value", compute="_compute_data") + string="Primary Formated Value", compute="_compute_data" + ) primary_helper = fields.Char( - string="Primary Helper", compute="_compute_helper", - store=True) + string="Primary Helper", compute="_compute_helper", store=True + ) # Secondary Value secondary_function = fields.Selection( - string="Secondary Function", selection=FIELD_FUNCTION_SELECTION, + string="Secondary Function", + selection=FIELD_FUNCTION_SELECTION, ) secondary_field_id = fields.Many2one( @@ -171,16 +177,14 @@ class TileTile(models.Model): "ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000.", ) - secondary_value = fields.Float( - string="Secondary Value", compute="_compute_data") + secondary_value = fields.Float(string="Secondary Value", compute="_compute_data") secondary_formated_value = fields.Char( string="Secondary Formated Value", compute="_compute_data" ) secondary_helper = fields.Char( - string="Secondary Helper", compute="_compute_helper", - store=True + string="Secondary Helper", compute="_compute_helper", store=True ) error = fields.Char(string="Error Details", compute="_compute_data") @@ -198,19 +202,14 @@ class TileTile(models.Model): count = model.search_count(eval(domain, eval_context)) except Exception as e: tile.primary_value = 0.0 - tile.primary_formated_value =\ - tile.secondary_formated_value = _("Error") + tile.primary_formated_value = tile.secondary_formated_value = _("Error") tile.error = str(e) return fields = [ - f.name - for f in [tile.primary_field_id, tile.secondary_field_id] - if f + f.name for f in [tile.primary_field_id, tile.secondary_field_id] if f ] read_vals = ( - fields - and model.search_read(eval(domain, eval_context), fields) - or [] + fields and model.search_read(eval(domain, eval_context), fields) or [] ) for f in ["primary_", "secondary_"]: f_function = f + "function" @@ -231,8 +230,9 @@ class TileTile(models.Model): value = func(vals or [0.0]) try: tile[f_value] = value - tile[f_formated_value] = ( - tile[f_format] or "{:,}").format(value) + tile[f_formated_value] = (tile[f_format] or "{:,}").format( + value + ) if tile.hide_if_null and not value: tile.hidden = True except ValueError as e: @@ -274,8 +274,9 @@ class TileTile(models.Model): def _search_hidden(self, operator, operand): items = self.search([]) hidden_tile_ids = [x.id for x in items if x.hidden] - if (operator == "=" and operand is False) or\ - (operator == "!=" and operand is True): + if (operator == "=" and operand is False) or ( + operator == "!=" and operand is True + ): domain = [("id", "not in", hidden_tile_ids)] else: domain = [("id", "in", hidden_tile_ids)] @@ -346,12 +347,14 @@ class TileTile(models.Model): "target": "current", "domain": self.domain, } - action.update({ - "name": self.name, - "display_name": self.name, - "context": dict(self.env.context, group_by=False), - "domain": self.domain, - }) + action.update( + { + "name": self.name, + "display_name": self.name, + "context": dict(self.env.context, group_by=False), + "domain": self.domain, + } + ) return action @api.model @@ -359,9 +362,7 @@ class TileTile(models.Model): if "model_id" in vals and not vals["model_id"].isdigit(): # need to replace model_name with its id vals["model_id"] = ( - self.env["ir.model"] - .search([("model", "=", vals["model_id"])]) - .id + self.env["ir.model"].search([("model", "=", vals["model_id"])]).id ) self.create(vals) diff --git a/web_dashboard_tile/readme/CONFIGURE.rst b/web_dashboard_tile/readme/CONFIGURE.rst index 858db81f8..96b88356e 100644 --- a/web_dashboard_tile/readme/CONFIGURE.rst +++ b/web_dashboard_tile/readme/CONFIGURE.rst @@ -30,4 +30,3 @@ You can optionally define a secondary value, for that purpose : * You can define a specific format. (``.format()`` python syntax) .. image:: ../static/description/tile_tile_form_secondary_value.png - diff --git a/web_dashboard_tile/readme/ROADMAP.rst b/web_dashboard_tile/readme/ROADMAP.rst index b6bc023e7..6801a4c4c 100644 --- a/web_dashboard_tile/readme/ROADMAP.rst +++ b/web_dashboard_tile/readme/ROADMAP.rst @@ -12,4 +12,3 @@ * Restore original Domain + Filter when an action is set. * Posibility to hide the tile based on a field expression. * Posibility to set the background color based on a field expression. - diff --git a/web_dashboard_tile/security/ir_rule.xml b/web_dashboard_tile/security/ir_rule.xml index f30705e35..15f43a31f 100644 --- a/web_dashboard_tile/security/ir_rule.xml +++ b/web_dashboard_tile/security/ir_rule.xml @@ -1,10 +1,10 @@ - + tile.owner - + [ '|', diff --git a/web_dashboard_tile/static/src/css/web_dashboard_tile.css b/web_dashboard_tile/static/src/css/web_dashboard_tile.css index e9a3d962a..7e9d1ceec 100644 --- a/web_dashboard_tile/static/src/css/web_dashboard_tile.css +++ b/web_dashboard_tile/static/src/css/web_dashboard_tile.css @@ -5,11 +5,11 @@ /* Fix bug where draggin a tile results in the element losing its style */ .o_kanban_view .oe_dashboard_tile { - padding: 0px !important; + padding: 0px !important; } .o_kanban_view .oe_dashboard_tile .tile_background { - padding: 8px; - height: 100%; + padding: 8px; + height: 100%; } .o_kanban_view .oe_dashboard_tile .tile_label, @@ -24,7 +24,7 @@ font-size: 15px; } -.o_kanban_view .oe_dashboard_tile .tile_primary_value{ +.o_kanban_view .oe_dashboard_tile .tile_primary_value { font-size: 54px; position: absolute; left: 5px; @@ -32,7 +32,7 @@ bottom: 5px; } -.o_kanban_view .oe_dashboard_tile .tile_secondary_value{ +.o_kanban_view .oe_dashboard_tile .tile_secondary_value { display: none; font-size: 18px; font-style: italic; @@ -42,12 +42,12 @@ bottom: 5px; } -.o_kanban_view .oe_dashboard_tile .with_secondary .tile_primary_value{ +.o_kanban_view .oe_dashboard_tile .with_secondary .tile_primary_value { font-size: 38px; bottom: 30px; } -.o_kanban_view .oe_dashboard_tile .with_secondary .tile_secondary_value{ +.o_kanban_view .oe_dashboard_tile .with_secondary .tile_secondary_value { display: block; } diff --git a/web_dashboard_tile/views/menu.xml b/web_dashboard_tile/views/menu.xml index a2dd84a61..3c7004c20 100644 --- a/web_dashboard_tile/views/menu.xml +++ b/web_dashboard_tile/views/menu.xml @@ -1,14 +1,18 @@ - + - + sequence="0" + /> - + sequence="100" + /> diff --git a/web_dashboard_tile/views/templates.xml b/web_dashboard_tile/views/templates.xml index 69acf7d7c..e143f532c 100644 --- a/web_dashboard_tile/views/templates.xml +++ b/web_dashboard_tile/views/templates.xml @@ -1,9 +1,12 @@ - + diff --git a/web_dashboard_tile/views/tile_category.xml b/web_dashboard_tile/views/tile_category.xml index b8c8eab58..f88da43d6 100644 --- a/web_dashboard_tile/views/tile_category.xml +++ b/web_dashboard_tile/views/tile_category.xml @@ -1,4 +1,4 @@ - + @@ -15,21 +15,35 @@
- -
-
- - + +
@@ -40,10 +54,10 @@ tile.category - - - - + + + +
@@ -56,8 +70,11 @@ {'active_test': False}
- + action="action_tile_category" + sequence="50" + />
diff --git a/web_dashboard_tile/views/tile_tile.xml b/web_dashboard_tile/views/tile_tile.xml index 2d2ecb247..5ffdb1c84 100644 --- a/web_dashboard_tile/views/tile_tile.xml +++ b/web_dashboard_tile/views/tile_tile.xml @@ -1,13 +1,13 @@ - + tile.tile - - - + + + @@ -16,17 +16,17 @@ tile.tile - - - - - - - - - - - + + + + + + + + + + + @@ -37,64 +37,79 @@

- +

- - + + - - - - - - - - - - + + + + + + + + + + - - + + }" + /> - - + + - - - + + + - - + + }" + /> - + - - - + + + - +
@@ -107,38 +122,67 @@ - - - - - - - - - - + + + + + + + + + + -
+
- -
+ +
- +
-
-
+
@@ -153,8 +197,11 @@ tree,form,kanban - + action="action_tile_tile" + sequence="10" + />