[MIG] web_dashboard_tile from 12.0 to 16.0
- remove 12.0 migration scripts - bump version to 16.0 - use new api convention @api.model_create_multi ; new compute function logic ; - add dependency to spreasheet_dashboard to use 'Dashboard' main menu item - use new way to include assets - remove totally useless controllers - distinct different errors, depending on domain or format errors - fix : _compute_data depends on many fields - update : documentation and printscreens16.0
|
@ -113,7 +113,7 @@ Known issues / Roadmap
|
||||||
* Can not edit color from dashboard
|
* Can not edit color from dashboard
|
||||||
* Original context is ignored.
|
* Original context is ignored.
|
||||||
* Original domain and filter are not restored.
|
* Original domain and filter are not restored.
|
||||||
* To preserve a relative date domain, you have to manually edit the tile's domain from "Configuration > User Interface > Dashboard Tile". You can use the same variables available in filters (``uid``, ``context_today()``, ``current_date``, ``time``, ``datetime``, `relativedelta`).
|
* To preserve a relative date domain, you have to manually edit the tile's domain from "Configuration > User Interface > Dashboard Tile". You can use the same variables available in filters (``uid``, ``context_today()``, ``current_date``, ``relativedelta``).
|
||||||
|
|
||||||
**Roadmap**
|
**Roadmap**
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
from . import controllers
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
{
|
{
|
||||||
"name": "Overview Dashboard (Tiles)",
|
"name": "Overview Dashboard (Tiles)",
|
||||||
"summary": "Add Overview Dashboards with Tiles",
|
"summary": "Add Overview Dashboards with Tiles",
|
||||||
"version": "12.0.1.0.2",
|
"version": "16.0.1.0.2",
|
||||||
"depends": ["web", "board", "mail", "web_widget_color"],
|
"depends": [
|
||||||
|
"web",
|
||||||
|
"spreadsheet_dashboard",
|
||||||
|
],
|
||||||
"author": "initOS GmbH & Co. KG, "
|
"author": "initOS GmbH & Co. KG, "
|
||||||
"GRAP, "
|
"GRAP, "
|
||||||
"Iván Todorovich <ivan.todorovich@gmail.com>, "
|
"Iván Todorovich <ivan.todorovich@gmail.com>, "
|
||||||
|
@ -17,11 +20,15 @@
|
||||||
"data": [
|
"data": [
|
||||||
"security/ir.model.access.csv",
|
"security/ir.model.access.csv",
|
||||||
"security/ir_rule.xml",
|
"security/ir_rule.xml",
|
||||||
"views/templates.xml",
|
|
||||||
"views/menu.xml",
|
"views/menu.xml",
|
||||||
"views/tile_tile.xml",
|
"views/tile_tile.xml",
|
||||||
"views/tile_category.xml",
|
"views/tile_category.xml",
|
||||||
],
|
],
|
||||||
|
"assets": {
|
||||||
|
"web.assets_common": [
|
||||||
|
"web_dashboard_tile/static/src/css/web_dashboard_tile.css",
|
||||||
|
],
|
||||||
|
},
|
||||||
"demo": [
|
"demo": [
|
||||||
"demo/tile_category.xml",
|
"demo/tile_category.xml",
|
||||||
"demo/tile_tile.xml",
|
"demo/tile_tile.xml",
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
from . import main
|
|
|
@ -1,14 +0,0 @@
|
||||||
# Copyright (C) 2019-Today: GTRAP (<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).
|
|
||||||
|
|
||||||
from odoo.http import Controller, request, route
|
|
||||||
|
|
||||||
|
|
||||||
class WebDashboardTile(Controller):
|
|
||||||
@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)
|
|
|
@ -4,23 +4,21 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 12.0\n"
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-08-02 15:38+0000\n"
|
"POT-Creation-Date: 2022-10-26 21:53+0000\n"
|
||||||
"PO-Revision-Date: 2022-01-19 13:10+0000\n"
|
"PO-Revision-Date: 2022-10-26 21:53+0000\n"
|
||||||
"Last-Translator: Yann Papouin <y.papouin@dec-industrie.com>\n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: fr\n"
|
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: \n"
|
"Content-Transfer-Encoding: \n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: Weblate 4.3.2\n"
|
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__action_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__action_id
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "Action"
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__active
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__active
|
||||||
|
@ -29,13 +27,18 @@ msgid "Active"
|
||||||
msgstr "Actif"
|
msgstr "Actif"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_category_form
|
||||||
#: selection:tile.tile,secondary_function:0
|
msgid "Archived"
|
||||||
|
msgstr "Archivée"
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__avg
|
||||||
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__avg
|
||||||
msgid "Average"
|
msgid "Average"
|
||||||
msgstr "Moyenne"
|
msgstr "Moyenne"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:53
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Average value of '%s'"
|
msgid "Average value of '%s'"
|
||||||
msgstr "Valeur moyenne du champ '%s'"
|
msgstr "Valeur moyenne du champ '%s'"
|
||||||
|
@ -51,10 +54,10 @@ msgid "Category"
|
||||||
msgstr "Catégorie"
|
msgstr "Catégorie"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__count
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__count
|
||||||
msgid "Count"
|
msgid "Count"
|
||||||
msgstr "Nbr"
|
msgstr "Décompte"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__create_uid
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__create_uid
|
||||||
|
@ -108,17 +111,18 @@ msgid "Domain"
|
||||||
msgstr "Domaine"
|
msgstr "Domaine"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:202
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:240
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__domain_error
|
||||||
|
#, python-format
|
||||||
|
msgid "Domain Error"
|
||||||
|
msgstr "Erreur sur le domaine"
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Erreur"
|
msgstr "Erreur"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__error
|
|
||||||
msgid "Error Details"
|
|
||||||
msgstr "Détails de l'erreur"
|
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__font_color
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__font_color
|
||||||
msgid "Font Color"
|
msgid "Font Color"
|
||||||
|
@ -143,7 +147,7 @@ msgstr "Cacher si non défini"
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_category__id
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__id
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__hide_if_null
|
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__hide_if_null
|
||||||
|
@ -198,37 +202,37 @@ msgid "Main Value"
|
||||||
msgstr "Valeur principale"
|
msgstr "Valeur principale"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__max
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__max
|
||||||
msgid "Maximum"
|
msgid "Maximum"
|
||||||
msgstr "Maximum"
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:41
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Maximum value of '%s'"
|
msgid "Maximum value of '%s'"
|
||||||
msgstr "Valeur maximale du champ '%s'"
|
msgstr "Valeur maximale du champ '%s'"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__median
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__median
|
||||||
msgid "Median"
|
msgid "Median"
|
||||||
msgstr "Médiane"
|
msgstr "Médiane"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:61
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Median value of '%s'"
|
msgid "Median value of '%s'"
|
||||||
msgstr "Valeur médiane du champ '%s'"
|
msgstr "Valeur médiane du champ '%s'"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__min
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__min
|
||||||
msgid "Minimum"
|
msgid "Minimum"
|
||||||
msgstr "Minimum"
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:33
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Minimum value of '%s'"
|
msgid "Minimum value of '%s'"
|
||||||
msgstr "Valeur minimale du champ '%s'"
|
msgstr "Valeur minimale du champ '%s'"
|
||||||
|
@ -250,7 +254,7 @@ msgid "Name"
|
||||||
msgstr "Nom"
|
msgstr "Nom"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:25
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Number of records"
|
msgid "Number of records"
|
||||||
msgstr "Nombre d'enregistrements"
|
msgstr "Nombre d'enregistrements"
|
||||||
|
@ -271,11 +275,21 @@ msgid "Overview"
|
||||||
msgstr "Vue d'ensemble"
|
msgstr "Vue d'ensemble"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:317
|
#: model:ir.ui.menu,name:web_dashboard_tile.menu_tile_configuration
|
||||||
|
msgid "Overview Settings"
|
||||||
|
msgstr "Paramétrage de la vue d'ensemble"
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please select a field from the selected model."
|
msgid "Please select a field from the selected model."
|
||||||
msgstr "Veuillez sélectionner un champ correspondant au modèle sélectionné."
|
msgstr "Veuillez sélectionner un champ correspondant au modèle sélectionné."
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_error
|
||||||
|
msgid "Primary Error"
|
||||||
|
msgstr "Erreur principale"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_field_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_field_id
|
||||||
msgid "Primary Field"
|
msgid "Primary Field"
|
||||||
|
@ -316,6 +330,11 @@ msgstr ""
|
||||||
"Chaîne de format python valide, avec str.format()\n"
|
"Chaîne de format python valide, avec str.format()\n"
|
||||||
"par exemple: {:,} Kgs' affichera '1000 Kgs' si la valeur est 1000."
|
"par exemple: {:,} Kgs' affichera '1000 Kgs' si la valeur est 1000."
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_error
|
||||||
|
msgid "Secondary Error"
|
||||||
|
msgstr "Erreur secondaire"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_field_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_field_id
|
||||||
msgid "Secondary Field"
|
msgid "Secondary Field"
|
||||||
|
@ -359,14 +378,13 @@ msgid "Sequence"
|
||||||
msgstr "Séquence"
|
msgstr "Séquence"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.ui.menu,name:web_dashboard_tile.menu_dashboard_tile_settings
|
|
||||||
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_tile_form
|
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_tile_form
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Configuration"
|
msgstr "Configuration"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__sum
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__sum
|
||||||
msgid "Sum"
|
msgid "Sum"
|
||||||
msgstr "Somme"
|
msgstr "Somme"
|
||||||
|
|
||||||
|
@ -387,13 +405,13 @@ msgid "Tiles Quantity"
|
||||||
msgstr "Nombre de tuiles"
|
msgstr "Nombre de tuiles"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:46
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Total value of '%s'"
|
msgid "Total value of '%s'"
|
||||||
msgstr "Somme du champ '%s'"
|
msgstr "Somme du champ '%s'"
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:288
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Unimplemented Feature. Search on Active field disabled."
|
msgid "Unimplemented Feature. Search on Active field disabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -404,24 +422,3 @@ msgstr ""
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__user_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__user_id
|
||||||
msgid "User"
|
msgid "User"
|
||||||
msgstr "Utilisateur"
|
msgstr "Utilisateur"
|
||||||
|
|
||||||
#~ msgid "'%s' added to the overview dashboard"
|
|
||||||
#~ msgstr "'%s' a été ajouté au tableau de bord synthétique"
|
|
||||||
|
|
||||||
#~ msgid "Add"
|
|
||||||
#~ msgstr "Ajouter"
|
|
||||||
|
|
||||||
#~ msgid "Add to the Overview Dashboard"
|
|
||||||
#~ msgstr "Ajouter au tableau de bord synthétique"
|
|
||||||
|
|
||||||
#~ msgid "Could not add new element to the overview dashboard"
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Impossible d'ajouter un nouvel élément au tableau de bord synthétique"
|
|
||||||
|
|
||||||
#~ msgid "Name Field is required."
|
|
||||||
#~ msgstr "Le nom du champ est requis."
|
|
||||||
|
|
||||||
#~ msgid "Please refresh your browser for the changes to take effect."
|
|
||||||
#~ msgstr ""
|
|
||||||
#~ "Veuillez rafraichir votre navigateur pour que les changements prennent "
|
|
||||||
#~ "effets."
|
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Odoo Server 12.0\n"
|
"Project-Id-Version: Odoo Server 16.0\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"Last-Translator: <>\n"
|
"POT-Creation-Date: 2022-10-26 21:53+0000\n"
|
||||||
|
"PO-Revision-Date: 2022-10-26 21:53+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
@ -25,13 +27,18 @@ msgid "Active"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_category_form
|
||||||
#: selection:tile.tile,secondary_function:0
|
msgid "Archived"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__avg
|
||||||
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__avg
|
||||||
msgid "Average"
|
msgid "Average"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:53
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Average value of '%s'"
|
msgid "Average value of '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -47,8 +54,8 @@ msgid "Category"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__count
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__count
|
||||||
msgid "Count"
|
msgid "Count"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -104,15 +111,16 @@ msgid "Domain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:202
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:240
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__domain_error
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Error"
|
msgid "Domain Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__error
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
msgid "Error Details"
|
#, python-format
|
||||||
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
|
@ -148,7 +156,10 @@ msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__group_ids
|
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__group_ids
|
||||||
msgid "If this field is set, only users of this group can view this tile. Please note that it will only work for global tiles (that is, when User field is left empty)"
|
msgid ""
|
||||||
|
"If this field is set, only users of this group can view this tile. Please "
|
||||||
|
"note that it will only work for global tiles (that is, when User field is "
|
||||||
|
"left empty)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
|
@ -185,37 +196,37 @@ msgid "Main Value"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__max
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__max
|
||||||
msgid "Maximum"
|
msgid "Maximum"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:41
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Maximum value of '%s'"
|
msgid "Maximum value of '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__median
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__median
|
||||||
msgid "Median"
|
msgid "Median"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:61
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Median value of '%s'"
|
msgid "Median value of '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__min
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__min
|
||||||
msgid "Minimum"
|
msgid "Minimum"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:33
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Minimum value of '%s'"
|
msgid "Minimum value of '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -237,7 +248,7 @@ msgid "Name"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:25
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Number of records"
|
msgid "Number of records"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -258,11 +269,21 @@ msgid "Overview"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:317
|
#: model:ir.ui.menu,name:web_dashboard_tile.menu_tile_configuration
|
||||||
|
msgid "Overview Settings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Please select a field from the selected model."
|
msgid "Please select a field from the selected model."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_error
|
||||||
|
msgid "Primary Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_field_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__primary_field_id
|
||||||
msgid "Primary Field"
|
msgid "Primary Field"
|
||||||
|
@ -296,10 +317,16 @@ msgstr ""
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__primary_format
|
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__primary_format
|
||||||
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__secondary_format
|
#: model:ir.model.fields,help:web_dashboard_tile.field_tile_tile__secondary_format
|
||||||
msgid "Python Format String valid with str.format()\n"
|
msgid ""
|
||||||
|
"Python Format String valid with str.format()\n"
|
||||||
"ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000."
|
"ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#. module: web_dashboard_tile
|
||||||
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_error
|
||||||
|
msgid "Secondary Error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_field_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__secondary_field_id
|
||||||
msgid "Secondary Field"
|
msgid "Secondary Field"
|
||||||
|
@ -343,14 +370,13 @@ msgid "Sequence"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: model:ir.ui.menu,name:web_dashboard_tile.menu_dashboard_tile_settings
|
|
||||||
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_tile_form
|
#: model_terms:ir.ui.view,arch_db:web_dashboard_tile.view_tile_tile_form
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: selection:tile.tile,primary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__primary_function__sum
|
||||||
#: selection:tile.tile,secondary_function:0
|
#: model:ir.model.fields.selection,name:web_dashboard_tile.selection__tile_tile__secondary_function__sum
|
||||||
msgid "Sum"
|
msgid "Sum"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -371,13 +397,13 @@ msgid "Tiles Quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:46
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Total value of '%s'"
|
msgid "Total value of '%s'"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. module: web_dashboard_tile
|
#. module: web_dashboard_tile
|
||||||
#: code:addons/web_dashboard_tile/models/tile_tile.py:288
|
#: code:addons/web_dashboard_tile/models/tile_tile.py:0
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Unimplemented Feature. Search on Active field disabled."
|
msgid "Unimplemented Feature. Search on Active field disabled."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -386,4 +412,3 @@ msgstr ""
|
||||||
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__user_id
|
#: model:ir.model.fields,field_description:web_dashboard_tile.field_tile_tile__user_id
|
||||||
msgid "User"
|
msgid "User"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
# Copyright (C) 2019-Today: GTRAP (<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).
|
|
||||||
import odoo
|
|
||||||
|
|
||||||
|
|
||||||
def migrate(cr, version):
|
|
||||||
if not version:
|
|
||||||
return
|
|
||||||
|
|
||||||
with odoo.api.Environment.manage():
|
|
||||||
env = odoo.api.Environment(cr, odoo.SUPERUSER_ID, {})
|
|
||||||
|
|
||||||
# categories was optional in previous versions
|
|
||||||
# affecting all tiles without categories
|
|
||||||
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})
|
|
||||||
|
|
||||||
# Enable all categories, to generate actions and menus
|
|
||||||
categories = env["tile.category"].with_context(active_test=False).search([])
|
|
||||||
categories.write({"active": True})
|
|
|
@ -82,12 +82,11 @@ class TileCategory(models.Model):
|
||||||
if category.action_id:
|
if category.action_id:
|
||||||
category.action_id.unlink()
|
category.action_id.unlink()
|
||||||
|
|
||||||
@api.model
|
@api.model_create_multi
|
||||||
def create(self, vals):
|
def create(self, vals_list):
|
||||||
category = super().create(vals)
|
categories = super().create(vals_list)
|
||||||
if category.active:
|
categories.filtered(lambda x: x.active)._create_ui()
|
||||||
category._create_ui()
|
return categories
|
||||||
return category
|
|
||||||
|
|
||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
res = super().write(vals)
|
res = super().write(vals)
|
||||||
|
@ -105,4 +104,4 @@ class TileCategory(models.Model):
|
||||||
|
|
||||||
def unlink(self):
|
def unlink(self):
|
||||||
self._delete_ui()
|
self._delete_ui()
|
||||||
super().unlink()
|
return super().unlink()
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
# © 2015-Today GRAP
|
# © 2015-Today GRAP
|
||||||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
|
||||||
import datetime
|
|
||||||
import time
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from statistics import median
|
from statistics import median
|
||||||
|
|
||||||
|
@ -12,7 +10,7 @@ from dateutil.relativedelta import relativedelta
|
||||||
|
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
from odoo.exceptions import ValidationError, except_orm
|
from odoo.exceptions import ValidationError, except_orm
|
||||||
from odoo.tools.safe_eval import safe_eval as eval
|
from odoo.tools.safe_eval import safe_eval
|
||||||
from odoo.tools.translate import _
|
from odoo.tools.translate import _
|
||||||
|
|
||||||
FIELD_FUNCTIONS = OrderedDict(
|
FIELD_FUNCTIONS = OrderedDict(
|
||||||
|
@ -101,11 +99,15 @@ class TileTile(models.Model):
|
||||||
"(that is, when User field is left empty)",
|
"(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, ondelete="cascade"
|
||||||
|
)
|
||||||
|
|
||||||
model_name = fields.Char(string="Model name", related="model_id.model")
|
model_name = fields.Char(string="Model name", related="model_id.model")
|
||||||
|
|
||||||
domain = fields.Text(default="[]")
|
domain = fields.Text(default="[]", required=True)
|
||||||
|
|
||||||
|
domain_error = fields.Char(compute="_compute_data")
|
||||||
|
|
||||||
action_id = fields.Many2one(
|
action_id = fields.Many2one(
|
||||||
comodel_name="ir.actions.act_window",
|
comodel_name="ir.actions.act_window",
|
||||||
|
@ -123,13 +125,10 @@ class TileTile(models.Model):
|
||||||
help="If checked, the item will be hidden" " if the primary value is null.",
|
help="If checked, the item will be hidden" " if the primary value is null.",
|
||||||
)
|
)
|
||||||
|
|
||||||
hidden = fields.Boolean(
|
hidden = fields.Boolean(compute="_compute_data", search="_search_hidden")
|
||||||
string="Hidden", compute="_compute_data", search="_search_hidden"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Primary Value
|
# Primary Value
|
||||||
primary_function = fields.Selection(
|
primary_function = fields.Selection(
|
||||||
string="Primary Function",
|
|
||||||
required=True,
|
required=True,
|
||||||
selection=FIELD_FUNCTION_SELECTION,
|
selection=FIELD_FUNCTION_SELECTION,
|
||||||
default="count",
|
default="count",
|
||||||
|
@ -143,24 +142,20 @@ class TileTile(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
primary_format = fields.Char(
|
primary_format = fields.Char(
|
||||||
string="Primary Format",
|
|
||||||
help="Python Format String valid with str.format()\n"
|
help="Python Format String valid with str.format()\n"
|
||||||
"ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000.",
|
"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(compute="_compute_data")
|
||||||
|
|
||||||
primary_formated_value = fields.Char(
|
primary_formated_value = fields.Char(compute="_compute_data")
|
||||||
string="Primary Formated Value", compute="_compute_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
primary_helper = fields.Char(
|
primary_helper = fields.Char(compute="_compute_helper", store=True)
|
||||||
string="Primary Helper", compute="_compute_helper", store=True
|
|
||||||
)
|
primary_error = fields.Char(compute="_compute_data")
|
||||||
|
|
||||||
# Secondary Value
|
# Secondary Value
|
||||||
secondary_function = fields.Selection(
|
secondary_function = fields.Selection(
|
||||||
string="Secondary Function",
|
|
||||||
selection=FIELD_FUNCTION_SELECTION,
|
selection=FIELD_FUNCTION_SELECTION,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -172,44 +167,61 @@ class TileTile(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
secondary_format = fields.Char(
|
secondary_format = fields.Char(
|
||||||
string="Secondary Format",
|
|
||||||
help="Python Format String valid with str.format()\n"
|
help="Python Format String valid with str.format()\n"
|
||||||
"ie: '{:,} Kgs' will output '1,000 Kgs' if value is 1000.",
|
"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(compute="_compute_data")
|
||||||
|
|
||||||
secondary_formated_value = fields.Char(
|
secondary_formated_value = fields.Char(compute="_compute_data")
|
||||||
string="Secondary Formated Value", compute="_compute_data"
|
|
||||||
)
|
|
||||||
|
|
||||||
secondary_helper = fields.Char(
|
secondary_helper = fields.Char(compute="_compute_helper", store=True)
|
||||||
string="Secondary Helper", compute="_compute_helper", store=True
|
|
||||||
)
|
|
||||||
|
|
||||||
error = fields.Char(string="Error Details", compute="_compute_data")
|
secondary_error = fields.Char(compute="_compute_data")
|
||||||
|
|
||||||
# Compute Section
|
# Compute Section
|
||||||
@api.depends("primary_format", "secondary_format", "model_id", "domain")
|
@api.depends(
|
||||||
|
"model_id",
|
||||||
|
"domain",
|
||||||
|
"primary_format",
|
||||||
|
"primary_function",
|
||||||
|
"primary_field_id",
|
||||||
|
"secondary_format",
|
||||||
|
"secondary_function",
|
||||||
|
"secondary_field_id",
|
||||||
|
)
|
||||||
def _compute_data(self):
|
def _compute_data(self):
|
||||||
for tile in self:
|
for tile in self:
|
||||||
|
# initialize all vals
|
||||||
|
tile.hidden = False
|
||||||
|
tile.primary_value = False
|
||||||
|
tile.primary_formated_value = False
|
||||||
|
tile.secondary_value = False
|
||||||
|
tile.secondary_formated_value = False
|
||||||
|
tile.domain_error = False
|
||||||
|
tile.primary_error = False
|
||||||
|
tile.secondary_error = False
|
||||||
if not tile.model_id or not tile.active:
|
if not tile.model_id or not tile.active:
|
||||||
return
|
return
|
||||||
|
|
||||||
model = self.env[tile.model_id.model]
|
model = self.env[tile.model_id.model]
|
||||||
eval_context = self._get_eval_context()
|
eval_context = self._get_eval_context()
|
||||||
domain = tile.domain or "[]"
|
domain = tile.domain or "[]"
|
||||||
try:
|
try:
|
||||||
count = model.search_count(eval(domain, eval_context))
|
count = model.search_count(safe_eval(domain, eval_context))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
tile.primary_value = 0.0
|
tile.primary_formated_value = tile.secondary_formated_value = _(
|
||||||
tile.primary_formated_value = tile.secondary_formated_value = _("Error")
|
"Domain Error"
|
||||||
tile.error = str(e)
|
)
|
||||||
|
tile.domain_error = str(e)
|
||||||
return
|
return
|
||||||
fields = [
|
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 = (
|
read_vals = (
|
||||||
fields and model.search_read(eval(domain, eval_context), fields) or []
|
fields
|
||||||
|
and model.search_read(safe_eval(domain, eval_context), fields)
|
||||||
|
or []
|
||||||
)
|
)
|
||||||
for f in ["primary_", "secondary_"]:
|
for f in ["primary_", "secondary_"]:
|
||||||
f_function = f + "function"
|
f_function = f + "function"
|
||||||
|
@ -217,28 +229,25 @@ class TileTile(models.Model):
|
||||||
f_format = f + "format"
|
f_format = f + "format"
|
||||||
f_value = f + "value"
|
f_value = f + "value"
|
||||||
f_formated_value = f + "formated_value"
|
f_formated_value = f + "formated_value"
|
||||||
value = 0
|
f_error = f + "error"
|
||||||
|
|
||||||
if not tile[f_function]:
|
if not tile[f_function]:
|
||||||
tile[f_value] = 0.0
|
continue
|
||||||
tile[f_formated_value] = False
|
elif tile[f_function] == "count":
|
||||||
else:
|
|
||||||
if tile[f_function] == "count":
|
|
||||||
value = count
|
value = count
|
||||||
else:
|
else:
|
||||||
func = FIELD_FUNCTIONS[tile[f_function]]["func"]
|
func = FIELD_FUNCTIONS[tile[f_function]]["func"]
|
||||||
vals = [x[tile[f_field_id].name] for x in read_vals]
|
vals = [x[tile[f_field_id].name] for x in read_vals]
|
||||||
value = func(vals or [0.0])
|
value = func(vals or [0.0])
|
||||||
try:
|
|
||||||
tile[f_value] = value
|
tile[f_value] = value
|
||||||
tile[f_formated_value] = (tile[f_format] or "{:,}").format(
|
|
||||||
value
|
try:
|
||||||
)
|
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:
|
except ValueError as e:
|
||||||
tile[f_value] = 0.0
|
|
||||||
tile[f_formated_value] = _("Error")
|
tile[f_formated_value] = _("Error")
|
||||||
tile.error = str(e)
|
tile[f_error] = str(e)
|
||||||
|
|
||||||
|
tile.hidden = tile.hide_if_null and not tile.primary_value
|
||||||
|
|
||||||
@api.depends(
|
@api.depends(
|
||||||
"primary_function",
|
"primary_function",
|
||||||
|
@ -254,19 +263,17 @@ class TileTile(models.Model):
|
||||||
f_helper = f + "helper"
|
f_helper = f + "helper"
|
||||||
tile[f_helper] = ""
|
tile[f_helper] = ""
|
||||||
field_func = FIELD_FUNCTIONS.get(tile[f_function], {})
|
field_func = FIELD_FUNCTIONS.get(tile[f_function], {})
|
||||||
help = field_func.get("help", False)
|
help_text = field_func.get("help", False)
|
||||||
if help:
|
if help_text and tile[f_function] != "count" and tile[f_field_id]:
|
||||||
if tile[f_function] != "count" and tile[f_field_id]:
|
tile[f_helper] = help_text % tile[f_field_id].field_description
|
||||||
desc = tile[f_field_id].field_description
|
|
||||||
tile[f_helper] = help % desc
|
|
||||||
else:
|
else:
|
||||||
tile[f_helper] = help
|
tile[f_helper] = help_text
|
||||||
|
|
||||||
def _compute_active(self):
|
def _compute_active(self):
|
||||||
ima = self.env["ir.model.access"]
|
IrModelAccess = self.env["ir.model.access"]
|
||||||
for tile in self:
|
for tile in self:
|
||||||
if tile.model_id:
|
if tile.model_id:
|
||||||
tile.active = ima.check(tile.model_id.model, "read", False)
|
tile.active = IrModelAccess.check(tile.model_id.model, "read", False)
|
||||||
else:
|
else:
|
||||||
tile.active = True
|
tile.active = True
|
||||||
|
|
||||||
|
@ -288,7 +295,7 @@ class TileTile(models.Model):
|
||||||
raise except_orm(
|
raise except_orm(
|
||||||
_("Unimplemented Feature. Search on Active field disabled.")
|
_("Unimplemented Feature. Search on Active field disabled.")
|
||||||
)
|
)
|
||||||
ima = self.env["ir.model.access"]
|
IrModelAccess = self.env["ir.model.access"]
|
||||||
ids = []
|
ids = []
|
||||||
cr.execute(
|
cr.execute(
|
||||||
"""
|
"""
|
||||||
|
@ -298,20 +305,20 @@ class TileTile(models.Model):
|
||||||
ON tt.model_id = im.id"""
|
ON tt.model_id = im.id"""
|
||||||
)
|
)
|
||||||
for result in cr.fetchall():
|
for result in cr.fetchall():
|
||||||
if ima.check(result[1], "read", False) == value:
|
if IrModelAccess.check(result[1], "read", False) == value:
|
||||||
ids.append(result[0])
|
ids.append(result[0])
|
||||||
return [("id", "in", ids)]
|
return [("id", "in", ids)]
|
||||||
|
|
||||||
# Constraints Sections
|
# Constraints Sections
|
||||||
@api.constrains("model_id", "primary_field_id", "secondary_field_id")
|
@api.constrains("model_id", "primary_field_id", "secondary_field_id")
|
||||||
def _check_model_id_field_id(self):
|
def _check_model_id_field_id(self):
|
||||||
for rec in self:
|
for tile in self:
|
||||||
if any(
|
if any(
|
||||||
[
|
[
|
||||||
rec.primary_field_id
|
tile.primary_field_id
|
||||||
and rec.primary_field_id.model_id.id != rec.model_id.id,
|
and tile.primary_field_id.model_id.id != tile.model_id.id,
|
||||||
rec.secondary_field_id
|
tile.secondary_field_id
|
||||||
and rec.secondary_field_id.model_id.id != rec.model_id.id,
|
and tile.secondary_field_id.model_id.id != tile.model_id.id,
|
||||||
]
|
]
|
||||||
):
|
):
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
|
@ -333,13 +340,11 @@ class TileTile(models.Model):
|
||||||
self.secondary_field_id = False
|
self.secondary_field_id = False
|
||||||
|
|
||||||
# Action methods
|
# Action methods
|
||||||
@api.multi
|
|
||||||
def open_link(self):
|
def open_link(self):
|
||||||
if self.action_id:
|
if self.action_id:
|
||||||
action = self.action_id.read()[0]
|
action = self.action_id.read()[0]
|
||||||
else:
|
else:
|
||||||
action = {
|
action = {
|
||||||
"view_type": "form",
|
|
||||||
"view_mode": "tree",
|
"view_mode": "tree",
|
||||||
"view_id": False,
|
"view_id": False,
|
||||||
"res_model": self.model_id.model,
|
"res_model": self.model_id.model,
|
||||||
|
@ -357,27 +362,15 @@ class TileTile(models.Model):
|
||||||
)
|
)
|
||||||
return action
|
return action
|
||||||
|
|
||||||
@api.model
|
|
||||||
def add(self, vals):
|
|
||||||
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.create(vals)
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_eval_context(self):
|
def _get_eval_context(self):
|
||||||
def _context_today():
|
|
||||||
return fields.Date.from_string(fields.Date.context_today(self))
|
|
||||||
|
|
||||||
context = self.env.context.copy()
|
context = self.env.context.copy()
|
||||||
context.update(
|
context.update(
|
||||||
{
|
{
|
||||||
"time": time,
|
|
||||||
"datetime": datetime,
|
|
||||||
"relativedelta": relativedelta,
|
"relativedelta": relativedelta,
|
||||||
"context_today": _context_today,
|
"context_today": fields.Date.from_string(
|
||||||
|
fields.Date.context_today(self)
|
||||||
|
),
|
||||||
"current_date": fields.Date.today(),
|
"current_date": fields.Date.today(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
First, you have to create tile categories.
|
First, you have to create tile categories.
|
||||||
|
|
||||||
* Go to "Dashboards > Settings > Dashboard Categories"
|
* Go to "Dashboards > Configuration > Overview Settings > Dashboard Categories"
|
||||||
|
|
||||||
* Click on Create
|
* Create categories
|
||||||
|
|
||||||
* Set a name, and save.
|
Odoo menu and action are automatically created in the "Dashboard > Overview" menu
|
||||||
|
|
||||||
Odoo menu and action are automatically created.
|
|
||||||
You should refresh your browser to see new menu items.
|
You should refresh your browser to see new menu items.
|
||||||
|
|
||||||
.. image:: ../static/description/tile_category_form.png
|
.. image:: ../static/description/tile_category_form.png
|
||||||
|
|
||||||
Then you can create tiles.
|
Then you can create tiles.
|
||||||
|
|
||||||
* go to "Dashboards > Settings > Dashboard Tiles"
|
* Go to "Dashboards > Configuration > Overview Settings > Dashboard Items"
|
||||||
|
|
||||||
* create a new tile, set a name, a category and a model.
|
* create a new tile, set a name, a category and a model.
|
||||||
|
|
||||||
* You can optionally define colors, domain a specific action to use.
|
* You can optionally define colors, domain and a specific action to use.
|
||||||
|
|
||||||
* Setting a user, or a group in "Security" tab will restrict the display of the tile.
|
* Setting a user, or a group in "Security" tab will restrict the display of the tile.
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Adds a dashboard where you can configure tiles from any view and add them as short cut.
|
This module extends the web module to add new dashboard overview system.
|
||||||
|
|
||||||
By default, the tile displays items count of a given model restricted to a given domain.
|
By default, the tile displays items count of a given model restricted to a given domain.
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* Can not edit color from dashboard
|
* Can not edit color from dashboard
|
||||||
* Original context is ignored.
|
* Original context is ignored.
|
||||||
* Original domain and filter are not restored.
|
* Original domain and filter are not restored.
|
||||||
* To preserve a relative date domain, you have to manually edit the tile's domain from "Configuration > User Interface > Dashboard Tile". You can use the same variables available in filters (``uid``, ``context_today()``, ``current_date``, ``time``, ``datetime``, `relativedelta`).
|
* To preserve a relative date domain, you have to manually edit the tile's domain from "Configuration > User Interface > Dashboard Tile". You can use the same variables available in filters (``uid``, ``context_today()``, ``current_date``, ``relativedelta``).
|
||||||
|
|
||||||
**Roadmap**
|
**Roadmap**
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,3 @@
|
||||||
* By clicking on the item, you'll navigate to the tree view of the according model.
|
* By clicking on the item, you'll navigate to the tree view of the according model.
|
||||||
|
|
||||||
.. image:: ../static/description/tile_tile_2_tree_view.png
|
.. image:: ../static/description/tile_tile_2_tree_view.png
|
||||||
|
|
||||||
**Note**
|
|
||||||
|
|
||||||
When you are in a tree view, with a domain, you can save it in the favorite menu, but the configuration is limited.
|
|
||||||
|
|
||||||
.. image:: ../static/description/favorite_menu_create_tile.png
|
|
||||||
|
|
||||||
.. image:: ../static/description/favorite_menu_create_tile_result.png
|
|
||||||
|
|
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 5.6 KiB |
|
@ -1,12 +1,8 @@
|
||||||
/* custom kanban style */
|
/* custom kanban style */
|
||||||
.o_kanban_view .oe_dashboard_tile {
|
.o_kanban_view .oe_dashboard_tile {
|
||||||
height: 150px;
|
height: 150px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix bug where draggin a tile results in the element losing its style */
|
|
||||||
.o_kanban_view .oe_dashboard_tile {
|
|
||||||
padding: 0px !important;
|
|
||||||
}
|
|
||||||
.o_kanban_view .oe_dashboard_tile .tile_background {
|
.o_kanban_view .oe_dashboard_tile .tile_background {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -26,7 +22,6 @@
|
||||||
|
|
||||||
.o_kanban_view .oe_dashboard_tile .tile_primary_value {
|
.o_kanban_view .oe_dashboard_tile .tile_primary_value {
|
||||||
font-size: 54px;
|
font-size: 54px;
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
left: 5px;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
|
@ -36,7 +31,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
left: 5px;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
|
@ -50,10 +44,3 @@
|
||||||
.o_kanban_view .oe_dashboard_tile .with_secondary .tile_secondary_value {
|
.o_kanban_view .oe_dashboard_tile .with_secondary .tile_secondary_value {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make dropdown menu button not affect text flow */
|
|
||||||
.o_kanban_view .oe_dashboard_tile .o_dropdown_kanban {
|
|
||||||
float: none;
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,17 +2,10 @@
|
||||||
<odoo>
|
<odoo>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_dashboard_tile"
|
id="menu_tile_configuration"
|
||||||
parent="base.menu_board_root"
|
name="Overview Settings"
|
||||||
name="Overview"
|
parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_configuration"
|
||||||
sequence="0"
|
sequence="160"
|
||||||
/>
|
|
||||||
|
|
||||||
<menuitem
|
|
||||||
id="menu_dashboard_tile_settings"
|
|
||||||
parent="base.menu_board_root"
|
|
||||||
name="Settings"
|
|
||||||
sequence="100"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<odoo>
|
|
||||||
|
|
||||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
|
||||||
<xpath expr="." position="inside">
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="/web_dashboard_tile/static/src/css/web_dashboard_tile.css"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</odoo>
|
|
|
@ -4,7 +4,6 @@
|
||||||
<record id="action_category_2_tile" model="ir.actions.act_window">
|
<record id="action_category_2_tile" model="ir.actions.act_window">
|
||||||
<field name="name">Dashboard Items</field>
|
<field name="name">Dashboard Items</field>
|
||||||
<field name="res_model">tile.tile</field>
|
<field name="res_model">tile.tile</field>
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="context">{'search_default_category_id': active_id}</field>
|
<field name="context">{'search_default_category_id': active_id}</field>
|
||||||
</record>
|
</record>
|
||||||
|
@ -15,18 +14,6 @@
|
||||||
<form>
|
<form>
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_button_box" name="button_box">
|
<div class="oe_button_box" name="button_box">
|
||||||
<button
|
|
||||||
name="toggle_active"
|
|
||||||
type="object"
|
|
||||||
class="oe_stat_button"
|
|
||||||
icon="fa-archive"
|
|
||||||
>
|
|
||||||
<field
|
|
||||||
name="active"
|
|
||||||
widget="boolean_button"
|
|
||||||
options="{"terminology": "archive"}"
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
class="oe_stat_button"
|
class="oe_stat_button"
|
||||||
type="action"
|
type="action"
|
||||||
|
@ -37,11 +24,18 @@
|
||||||
<field string="Items" name="tile_qty" widget="statinfo" />
|
<field string="Items" name="tile_qty" widget="statinfo" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<widget
|
||||||
|
name="web_ribbon"
|
||||||
|
title="Archived"
|
||||||
|
bg_color="bg-danger"
|
||||||
|
attrs="{'invisible': [('active', '=', True)]}"
|
||||||
|
/>
|
||||||
<div class="oe_title">
|
<div class="oe_title">
|
||||||
<label for="name" class="oe_edit_only" />
|
<label for="name" class="oe_edit_only" />
|
||||||
<h1><field name="name" required="1" /></h1>
|
<h1><field name="name" required="1" /></h1>
|
||||||
</div>
|
</div>
|
||||||
<group string="Technical Informations">
|
<group string="Technical Informations">
|
||||||
|
<field name="active" invisible="1" />
|
||||||
<field name="menu_id" />
|
<field name="menu_id" />
|
||||||
<field name="action_id" />
|
<field name="action_id" />
|
||||||
</group>
|
</group>
|
||||||
|
@ -65,16 +59,15 @@
|
||||||
<record model="ir.actions.act_window" id="action_tile_category">
|
<record model="ir.actions.act_window" id="action_tile_category">
|
||||||
<field name="name">Dashboard Categories</field>
|
<field name="name">Dashboard Categories</field>
|
||||||
<field name="res_model">tile.category</field>
|
<field name="res_model">tile.category</field>
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,kanban,form</field>
|
<field name="view_mode">tree,kanban,form</field>
|
||||||
<field name="context">{'active_test': False}</field>
|
<field name="context">{'active_test': False}</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_tile_category"
|
id="menu_tile_category"
|
||||||
parent="menu_dashboard_tile_settings"
|
parent="menu_tile_configuration"
|
||||||
action="action_tile_category"
|
action="action_tile_category"
|
||||||
sequence="50"
|
sequence="160"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
@ -35,27 +35,30 @@
|
||||||
<field name="model">tile.tile</field>
|
<field name="model">tile.tile</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form>
|
<form>
|
||||||
|
<field name="model_name" invisible="1" />
|
||||||
<sheet>
|
<sheet>
|
||||||
<h1>
|
<h1>
|
||||||
<field name="name" />
|
<field name="name" />
|
||||||
</h1>
|
</h1>
|
||||||
<group>
|
<group col="4" string="Display">
|
||||||
<field name="category_id" />
|
<field name="category_id" colspan="4" />
|
||||||
<field name="user_id" />
|
|
||||||
</group>
|
|
||||||
<group col="4">
|
|
||||||
<separator string="Display" colspan="4" />
|
|
||||||
<field name="background_color" widget="color" />
|
<field name="background_color" widget="color" />
|
||||||
<field name="font_color" widget="color" />
|
<field name="font_color" widget="color" />
|
||||||
<separator string="Technical Informations" colspan="4" />
|
</group>
|
||||||
|
<group col="4" string="Technical Informations">
|
||||||
<field name="model_id" />
|
<field name="model_id" />
|
||||||
<field name="action_id" />
|
<field name="action_id" />
|
||||||
<field name="domain" colspan="4" />
|
|
||||||
<field name="model_name" invisible="1" />
|
|
||||||
<separator colspan="4" />
|
|
||||||
<field
|
<field
|
||||||
name="error"
|
name="domain"
|
||||||
attrs="{'invisible':[('error','=',False)]}"
|
colspan="4"
|
||||||
|
widget="ace"
|
||||||
|
option="{'mode': 'python'}"
|
||||||
|
/>
|
||||||
|
<field
|
||||||
|
name="domain_error"
|
||||||
|
attrs="{'invisible':[('domain_error','=',False)]}"
|
||||||
|
nolabel="1"
|
||||||
|
colspan="4"
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
|
@ -83,6 +86,12 @@
|
||||||
attrs="{'invisible':[('primary_value','=',False)]}"
|
attrs="{'invisible':[('primary_value','=',False)]}"
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<field
|
||||||
|
name="primary_error"
|
||||||
|
attrs="{'invisible': [('primary_error', '=', False)]}"
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group string="Secondary Value">
|
<group string="Secondary Value">
|
||||||
<group>
|
<group>
|
||||||
|
@ -106,10 +115,17 @@
|
||||||
attrs="{'invisible':[('secondary_value','=',False)]}"
|
attrs="{'invisible':[('secondary_value','=',False)]}"
|
||||||
/>
|
/>
|
||||||
</group>
|
</group>
|
||||||
|
<group>
|
||||||
|
<field
|
||||||
|
name="secondary_error"
|
||||||
|
attrs="{'invisible': [('secondary_error', '=', False)]}"
|
||||||
|
/>
|
||||||
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="Security">
|
<page string="Security">
|
||||||
<field name="group_ids" />
|
<field name="group_ids" />
|
||||||
|
<field name="user_id" />
|
||||||
</page>
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
</sheet>
|
</sheet>
|
||||||
|
@ -193,15 +209,23 @@
|
||||||
<record model="ir.actions.act_window" id="action_tile_tile">
|
<record model="ir.actions.act_window" id="action_tile_tile">
|
||||||
<field name="name">Dashboard Items</field>
|
<field name="name">Dashboard Items</field>
|
||||||
<field name="res_model">tile.tile</field>
|
<field name="res_model">tile.tile</field>
|
||||||
<field name="view_type">form</field>
|
|
||||||
<field name="view_mode">tree,form,kanban</field>
|
<field name="view_mode">tree,form,kanban</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
id="menu_tile_tile"
|
id="menu_tile_tile"
|
||||||
parent="menu_dashboard_tile_settings"
|
parent="menu_tile_configuration"
|
||||||
action="action_tile_tile"
|
action="action_tile_tile"
|
||||||
sequence="10"
|
sequence="161"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Root menu item that will contains all the sub menu entries
|
||||||
|
that contains tiles -->
|
||||||
|
<menuitem
|
||||||
|
id="menu_dashboard_tile"
|
||||||
|
parent="spreadsheet_dashboard.spreadsheet_dashboard_menu_root"
|
||||||
|
name="Overview"
|
||||||
|
sequence="0"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|