diff --git a/web_dashboard_tile/__init__.py b/web_dashboard_tile/__init__.py new file mode 100644 index 00000000..9ad11b3e --- /dev/null +++ b/web_dashboard_tile/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Copyright (C) 2015-Today GRAP +# Author Markus Schneider +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from . import tile diff --git a/web_dashboard_tile/__openerp__.py b/web_dashboard_tile/__openerp__.py new file mode 100644 index 00000000..d0f8cf41 --- /dev/null +++ b/web_dashboard_tile/__openerp__.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Author Markus Schneider +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + "name": "Dashboard Tile", + "summary": "Add Tiles to Dashboard", + "version": "1.0", + "depends": [ + 'web', + 'board', + 'mail', + 'web_widget_color', + ], + 'author': "initOS GmbH & Co. KG,GRAP,Odoo Community Association (OCA)", + "category": "", + 'license': 'AGPL-3', + "description": """ +Add Tiles to Dashboard +====================== +Features: +--------- +module to give you a dashboard where you can configure tile from any view +and add them as short cut. + +* Tile can be: + * displayed only for a user; + * global for all users (In that case, some tiles will be hidden if + the current user doesn't have access to the given model); +* The tile displays items count of a given model restricted to a given domain; +* Optionnaly, the tile can display the result of a function of a field; + * Function is one of sum/avg/min/max/median; + * Field must be integer or float; + +Screenshot: +----------- +* Dashboad sample, displaying Sale Orders to invoice: +.. image:: web_dashboard_tile/static/src/img/screenshot_dashboard.png +* Tree view displayed when user click on the tile: +.. image:: web_dashboard_tile/static/src/img/screenshot_action_click.png + + +Kown issues/limits: +------------------- +* can not edit tile from dashboard (color, sequence, function, ...); +* context are ignored; +* date filter can not be relative; +* combine domain of menue and filter so can not restore origin filter; + +possible future improvments: +---------------------------- +* support context_today; +* add icons; +* support client side action (like inbox); + """, + 'data': [ + 'view/tile.xml', + 'security/ir.model.access.csv', + 'security/rules.xml', + ], + 'css': [ + 'static/src/css/tile.css', + ], + 'demo': [ + 'demo/res_groups.yml', + 'demo/tile_tile.yml', + ], + 'js': [ + 'static/src/js/custom_js.js', + ], + 'qweb': [ + 'static/src/xml/custom_xml.xml', + ], +} diff --git a/web_dashboard_tile/demo/res_groups.yml b/web_dashboard_tile/demo/res_groups.yml new file mode 100644 index 00000000..735437c5 --- /dev/null +++ b/web_dashboard_tile/demo/res_groups.yml @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +- !record {model: res.groups, id: base.group_no_one}: + users: + - base.user_root diff --git a/web_dashboard_tile/demo/tile_tile.yml b/web_dashboard_tile/demo/tile_tile.yml new file mode 100644 index 00000000..c40b5903 --- /dev/null +++ b/web_dashboard_tile/demo/tile_tile.yml @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +- !record {model: tile.tile, id: installed_modules}: + name: Installed Modules + model_id: base.model_ir_module_module + domain: [['state', 'in', ['installed', 'to upgrade', 'to remove']]] + action_id: base.open_module_tree + +- !record {model: tile.tile, id: installed_OCA_modules}: + name: Installed OCA Modules + model_id: base.model_ir_module_module + domain: [['state', 'in', ['installed', 'to upgrade', 'to remove']], ['author', 'ilike', 'Odoo Community Association (OCA)']] + action_id: base.open_module_tree diff --git a/web_dashboard_tile/i18n/fr.po b/web_dashboard_tile/i18n/fr.po new file mode 100644 index 00000000..6bb700fa --- /dev/null +++ b/web_dashboard_tile/i18n/fr.po @@ -0,0 +1,220 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * web_dashboard_tile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-10 01:04+0000\n" +"PO-Revision-Date: 2015-04-10 01:04+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_dashboard_tile +#: field:tile.tile,action_id:0 +msgid "Action" +msgstr "Action" + +#. module: web_dashboard_tile +#: field:tile.tile,active:0 +msgid "Active" +msgstr "Actif" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Average" +msgstr "Moyenne" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:82 +#, python-format +msgid "Average value of '%s'" +msgstr "Valeur moyenne du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,color:0 +msgid "Background color" +msgstr "Couleur de fond" + +#. module: web_dashboard_tile +#: field:tile.tile,computed_value:0 +msgid "Computed Value" +msgstr "Valeur calculée" + +#. module: web_dashboard_tile +#: field:tile.tile,count:0 +msgid "Count" +msgstr "Quantité" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:8 +#, python-format +msgid "Create" +msgstr "Créer" + +#. module: web_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_kanban_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_tree_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.mail_dashboard +msgid "Dashboard" +msgstr "Tableau de bord" + +#. module: web_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.menue_dashboard_tile +msgid "Dashboard Tile" +msgstr "Indicateur de tableau de bord" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Dashboard tiles" +msgstr "Indicateurs de tableau de bord" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Delete" +msgstr "Supprimer" + +#. module: web_dashboard_tile +#: field:tile.tile,domain:0 +msgid "Domain" +msgstr "Domaine" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Edit..." +msgstr "Editer..." + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Error" +msgstr "Erreur" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please select a field of the selected model." +msgstr "Erreur ! Veuillez sélectioner un champ qui correspond au modèle." + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please set both fields: 'Field' and 'Function'." +msgstr "Erreur ! Veuillez renseigner les deux champs : 'Champ' et 'Fonction'." + +#. module: web_dashboard_tile +#: field:tile.tile,field_id:0 +msgid "Field" +msgstr "Champ" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Filter name is required." +msgstr "Le nom du filtre est requis." + +#. module: web_dashboard_tile +#: field:tile.tile,font_color:0 +msgid "Font Color" +msgstr "Couleur du texte" + +#. module: web_dashboard_tile +#: field:tile.tile,field_function:0 +msgid "Function" +msgstr "Fonction" + +#. module: web_dashboard_tile +#: field:tile.tile,helper:0 +msgid "Helper Text" +msgstr "Texte Descriptif" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Maximum" +msgstr "Maximum" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:76 +#, python-format +msgid "Maximum value of '%s'" +msgstr "Valeur maximale du champ '%s'" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Median" +msgstr "Médiane" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:85 +#, python-format +msgid "Median value of '%s'" +msgstr "Valeur médian du champ '%s'" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Minimum" +msgstr "Minimum" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:73 +#, python-format +msgid "Minimum value of '%s'" +msgstr "Valeur minimale du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,model_id:0 +msgid "Model" +msgstr "Modèle" + +#. module: web_dashboard_tile +#: field:tile.tile,sequence:0 +msgid "Sequence" +msgstr "Séquence" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Success" +msgstr "Succès" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Sum" +msgstr "Somme" + +#. module: web_dashboard_tile +#: field:tile.tile,name:0 +msgid "Tile Name" +msgstr "Nom de l'indicateur" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Tile is created" +msgstr "L'indicateur a été créé" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:6 +#, python-format +msgid "Tile:" +msgstr "Indicateur :" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:79 +#, python-format +msgid "Total value of '%s'" +msgstr "Somme du champ '%s'" + +#. module: web_dashboard_tile +#: field:tile.tile,user_id:0 +msgid "User" +msgstr "Utilisateur" diff --git a/web_dashboard_tile/i18n/web_dashboard_tile.pot b/web_dashboard_tile/i18n/web_dashboard_tile.pot new file mode 100644 index 00000000..0e89f8ca --- /dev/null +++ b/web_dashboard_tile/i18n/web_dashboard_tile.pot @@ -0,0 +1,232 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * web_dashboard_tile +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-10 01:03+0000\n" +"PO-Revision-Date: 2015-04-10 01:03+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: web_dashboard_tile +#: field:tile.tile,action_id:0 +msgid "Action" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,active:0 +msgid "Active" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Average" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:82 +#, python-format +msgid "Average value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,color:0 +msgid "Background color" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,computed_value:0 +msgid "Computed Value" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,count:0 +msgid "Count" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:8 +#, python-format +msgid "Create" +msgstr "" + +#. module: web_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_kanban_dashboard_tile +#: model:ir.actions.act_window,name:web_dashboard_tile.action_tree_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.mail_dashboard +msgid "Dashboard" +msgstr "" + +#. module: web_dashboard_tile +#: model:ir.ui.menu,name:web_dashboard_tile.menue_dashboard_tile +msgid "Dashboard Tile" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Dashboard tiles" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Delete" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,domain:0 +msgid "Domain" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "Edit..." +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Error" +msgstr "" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please select a field of the selected model." +msgstr "" + +#. module: web_dashboard_tile +#: constraint:tile.tile:0 +msgid "Error ! Please set both fields: 'Field' and 'Function'." +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,field_id:0 +msgid "Field" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:61 +#, python-format +msgid "Filter name is required." +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,font_color:0 +msgid "Font Color" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,field_function:0 +msgid "Function" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,helper:0 +msgid "Helper Text" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Maximum" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:76 +#, python-format +msgid "Maximum value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Median" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:85 +#, python-format +msgid "Median value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Minimum" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:73 +#, python-format +msgid "Minimum value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,model_id:0 +msgid "Model" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,sequence:0 +msgid "Sequence" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Success" +msgstr "" + +#. module: web_dashboard_tile +#: selection:tile.tile,field_function:0 +msgid "Sum" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,name:0 +msgid "Tile Name" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/js/custom_js.js:100 +#, python-format +msgid "Tile is created" +msgstr "" + +#. module: web_dashboard_tile +#. openerp-web +#: code:addons/web_dashboard_tile/static/src/xml/custom_xml.xml:6 +#, python-format +msgid "Tile:" +msgstr "" + +#. module: web_dashboard_tile +#: code:addons/web_dashboard_tile/tile.py:79 +#, python-format +msgid "Total value of '%s'" +msgstr "" + +#. module: web_dashboard_tile +#: field:tile.tile,user_id:0 +msgid "User" +msgstr "" + +#. module: web_dashboard_tile +#: code:_description:0 +#: model:ir.model,name:web_dashboard_tile.model_tile_tile +#, python-format +msgid "tile.tile" +msgstr "" + +#. module: web_dashboard_tile +#: view:tile.tile:0 +msgid "í" +msgstr "" diff --git a/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py b/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py new file mode 100644 index 00000000..f8c33840 --- /dev/null +++ b/web_dashboard_tile/migrations/7.0.1.0/post-migration-color.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2015-Today GRAP +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + + +COLOR_NUMERIC_TO_RVB = { + 0: '#006015', + 1: '#CD2513', + 2: '#CDC713', + 3: '#57158A', + 4: '#0E9B2D', + 5: '#7F0C00', + 6: '#7F7B00', + 7: '#320455', + 8: '#CD6E13', + 9: '#0E6C7E', +} + + +def migrate_color(cr): + for old, new in COLOR_NUMERIC_TO_RVB.iteritems(): + cr.execute(""" + UPDATE tile_tile + SET color='%s', font_color='#FFFFFF' + WHERE color='%s' + """ % (new, old)) + + +def migrate(cr, installed_version): + migrate_color(cr) diff --git a/web_dashboard_tile/security/ir.model.access.csv b/web_dashboard_tile/security/ir.model.access.csv new file mode 100644 index 00000000..3229b4ea --- /dev/null +++ b/web_dashboard_tile/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +tile_user,tile_user,model_tile_tile,base.group_user,1,1,1,1 diff --git a/web_dashboard_tile/security/rules.xml b/web_dashboard_tile/security/rules.xml new file mode 100644 index 00000000..8d653b70 --- /dev/null +++ b/web_dashboard_tile/security/rules.xml @@ -0,0 +1,13 @@ + + + + + + tile.owner + + + [('user_id','in',[False,user.id])] + + + + diff --git a/web_dashboard_tile/static/src/css/tile.css b/web_dashboard_tile/static/src/css/tile.css new file mode 100644 index 00000000..1d057cee --- /dev/null +++ b/web_dashboard_tile/static/src/css/tile.css @@ -0,0 +1,44 @@ +.openerp .oe_kanban_view .oe_dashbaord_tile{ + width: 150px; + height: 150px; + border: 0; + border-radius: 0; +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_label, +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_without_computed_value, +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_with_computed_value, +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_computed_value { + width: 140px; + text-align: center; +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_label{ + padding: 5px; + font-size: 15px; +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_without_computed_value{ + font-size: 52px; + font-weight: bold; + position: absolute; + left: 5px; + bottom: 5px; +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_count_with_computed_value{ + font-size: 38px; + font-weight: bold; + position: absolute; + left: 5px; + bottom: 30px; +} + +.openerp .oe_kanban_view .oe_dashbaord_tile .tile_computed_value{ + font-size: 18px; + font-weight: bold; + position: absolute; + right: 10px; + bottom: 5px; + font-style: italic; +} diff --git a/web_dashboard_tile/static/src/img/avg.png b/web_dashboard_tile/static/src/img/avg.png new file mode 100644 index 00000000..2f534e93 Binary files /dev/null and b/web_dashboard_tile/static/src/img/avg.png differ diff --git a/web_dashboard_tile/static/src/img/icon.png b/web_dashboard_tile/static/src/img/icon.png new file mode 100644 index 00000000..fb6b1b29 Binary files /dev/null and b/web_dashboard_tile/static/src/img/icon.png differ diff --git a/web_dashboard_tile/static/src/img/max.png b/web_dashboard_tile/static/src/img/max.png new file mode 100644 index 00000000..ff33ee43 Binary files /dev/null and b/web_dashboard_tile/static/src/img/max.png differ diff --git a/web_dashboard_tile/static/src/img/median.png b/web_dashboard_tile/static/src/img/median.png new file mode 100644 index 00000000..61d5dd7c Binary files /dev/null and b/web_dashboard_tile/static/src/img/median.png differ diff --git a/web_dashboard_tile/static/src/img/min.png b/web_dashboard_tile/static/src/img/min.png new file mode 100644 index 00000000..de7c3fd0 Binary files /dev/null and b/web_dashboard_tile/static/src/img/min.png differ diff --git a/web_dashboard_tile/static/src/img/screenshot_action_click.png b/web_dashboard_tile/static/src/img/screenshot_action_click.png new file mode 100644 index 00000000..3fd41f99 Binary files /dev/null and b/web_dashboard_tile/static/src/img/screenshot_action_click.png differ diff --git a/web_dashboard_tile/static/src/img/screenshot_dashboard.png b/web_dashboard_tile/static/src/img/screenshot_dashboard.png new file mode 100644 index 00000000..9cbdeecd Binary files /dev/null and b/web_dashboard_tile/static/src/img/screenshot_dashboard.png differ diff --git a/web_dashboard_tile/static/src/img/sum.png b/web_dashboard_tile/static/src/img/sum.png new file mode 100644 index 00000000..90908e8b Binary files /dev/null and b/web_dashboard_tile/static/src/img/sum.png differ diff --git a/web_dashboard_tile/static/src/js/custom_js.js b/web_dashboard_tile/static/src/js/custom_js.js new file mode 100644 index 00000000..53a2bd0e --- /dev/null +++ b/web_dashboard_tile/static/src/js/custom_js.js @@ -0,0 +1,105 @@ +// @@@ web_dashboard_tile custom JS @@@ +//############################################################################# +// +// Copyright (C) 2010-2013 OpenERP s.a. () +// Copyright (C) 2014 initOS GmbH & Co. KG () +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +//############################################################################# + +openerp.web_dashboard_tile = function (instance) +{ +var QWeb = instance.web.qweb, + _t = instance.web._t, + _lt = instance.web._lt; +_.mixin({ + sum: function (obj) { return _.reduce(obj, function (a, b) { return a + b; }, 0); } +}); + var module = instance.board.AddToDashboard; + + module.include({ + start: function () { + this._super(); + var self = this; + this.$('#add_dashboard_tile').on('click', this, function (){ + self.save_tile(); + }) + }, + render_data: function(dashboard_choices){ + var selection = instance.web.qweb.render( + "SearchView.addtodashboard.selection", { + selections: dashboard_choices}); + this.$("form input").before(selection) + }, + save_tile: function () { + var self = this; + var getParent = this.getParent(); + var view_parent = this.getParent().getParent(); + if (! view_parent.action || ! this.$el.find("select").val()) { + this.do_warn("Can't find dashboard action"); + return; + } + + var $name = this.$('#dashboard_tile_new_name'); + + this.tile = new instance.web.Model('tile.tile'); + + var private_filter = !this.$('#oe_searchview_custom_public').prop('checked'); + if (_.isEmpty($name.val())){ + this.do_warn(_t("Error"), _t("Filter name is required.")); + return false; + } + var search = this.view.build_search_data(); + var context = new instance.web.CompoundContext(getParent.dataset.get_context() || []); + var domain = new instance.web.CompoundDomain(getParent.dataset.get_domain() || []); + _.each(search.contexts, context.add, context); + _.each(search.domains, domain.add, domain); + + var c = instance.web.pyeval.eval('context', context); + for(var k in c) { + if (c.hasOwnProperty(k) && /^search_default_/.test(k)) { + delete c[k]; + } + } + // TODO: replace this 6.1 workaround by attribute on + c.dashboard_merge_domains_contexts = false; + var d = instance.web.pyeval.eval('domain', domain); + + context.add({ + group_by: instance.web.pyeval.eval('groupbys', search.groupbys || []) + }); + // Don't save user_context keys in the custom filter, otherwise end + // up with e.g. wrong uid or lang stored *and used in subsequent + // reqs* + var ctx = context; + _(_.keys(instance.session.user_context)).each(function (key) { + delete ctx[key]; + }); + var filter = { + name: $name.val(), + user_id: private_filter ? instance.session.uid : false, + model_id: self.view.model, + //context: context, + domain: d, + action_id: view_parent.action.id, + }; + // FIXME: current context? + return self.tile.call('add', [filter]).done(function (id) { + self.do_warn(_t("Success"), _t("Tile is created")); + }); + + } + }); +} diff --git a/web_dashboard_tile/static/src/xml/custom_xml.xml b/web_dashboard_tile/static/src/xml/custom_xml.xml new file mode 100644 index 00000000..3e0c2316 --- /dev/null +++ b/web_dashboard_tile/static/src/xml/custom_xml.xml @@ -0,0 +1,12 @@ + + + + +
+ + + +
+
+
+
diff --git a/web_dashboard_tile/tile.py b/web_dashboard_tile/tile.py new file mode 100644 index 00000000..92243875 --- /dev/null +++ b/web_dashboard_tile/tile.py @@ -0,0 +1,209 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2014 initOS GmbH & Co. KG (). +# Copyright (C) 2015-Today GRAP +# Author Markus Schneider +# @author Sylvain LE GAL (https://twitter.com/legalsylvain) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.osv import orm, fields +from openerp.tools.translate import _ + + +class tile(orm.Model): + _name = 'tile.tile' + _order = 'sequence, name' + + def median(self, aList): + # https://docs.python.org/3/library/statistics.html#statistics.median + # TODO : refactor, using statistics.median when Odoo will be available + # in Python 3.4 + even = (0 if len(aList) % 2 else 1) + 1 + half = (len(aList) - 1) / 2 + return sum(sorted(aList)[half:half + even]) / float(even) + + def _get_tile_info(self, cr, uid, ids, fields, args, context=None): + ima_obj = self.pool['ir.model.access'] + res = {} + records = self.browse(cr, uid, ids, context=context) + for r in records: + res[r.id] = { + 'active': False, + 'count': 0, + 'computed_value': 0, + 'helper': '', + } + if ima_obj.check( + cr, uid, r.model_id.model, 'read', False, context): + # Compute count item + model = self.pool.get(r.model_id.model) + count = model.search_count( + cr, uid, eval(r.domain), context=context) + res[r.id].update({ + 'active': True, + 'count': count, + }) + + # Compute datas for field_id depending of field_function + if r.field_function and r.field_id and count != 0: + ids = model.search( + cr, uid, eval(r.domain), context=context) + vals = [x[r.field_id.name] for x in model.read( + cr, uid, ids, [r.field_id.name], context=context)] + desc = r.field_id.field_description + if r.field_function == 'min': + value = min(vals) + helper = _("Minimum value of '%s'") % desc + elif r.field_function == 'max': + value = max(vals) + helper = _("Maximum value of '%s'") % desc + elif r.field_function == 'sum': + value = sum(vals) + helper = _("Total value of '%s'") % desc + elif r.field_function == 'avg': + value = sum(vals) / len(vals) + helper = _("Average value of '%s'") % desc + elif r.field_function == 'median': + value = self.median(vals) + helper = _("Median value of '%s'") % desc + res[r.id].update({ + 'computed_value': value, + 'helper': helper, + }) + return res + + def _search_active(self, cr, uid, obj, name, arg, context=None): + ima_obj = self.pool['ir.model.access'] + ids = [] + cr.execute(""" + SELECT tt.id, im.model + FROM tile_tile tt + INNER JOIN ir_model im + ON tt.model_id = im.id""") + for result in cr.fetchall(): + if (ima_obj.check(cr, uid, result[1], 'read', False) == + arg[0][2]): + ids.append(result[0]) + return [('id', 'in', ids)] + + _columns = { + 'name': fields.char('Tile Name'), + 'model_id': fields.many2one('ir.model', 'Model', required=True), + 'user_id': fields.many2one('res.users', 'User'), + 'domain': fields.text('Domain'), + 'action_id': fields.many2one('ir.actions.act_window', 'Action'), + 'count': fields.function( + _get_tile_info, type='int', string='Count', + multi='tile_info', readonly=True), + 'computed_value': fields.function( + _get_tile_info, type='float', string='Computed Value', + multi='tile_info', readonly=True), + 'helper': fields.function( + _get_tile_info, type='char', string='Helper Text', + multi='tile_info', readonly=True), + 'field_function': fields.selection([ + ('min', 'Minimum'), + ('max', 'Maximum'), + ('sum', 'Sum'), + ('avg', 'Average'), + ('median', 'Median'), + ], 'Function'), + 'field_id': fields.many2one( + 'ir.model.fields', 'Field', + domain="[('model_id', '=', model_id)," + " ('ttype', 'in', ['float', 'int'])]"), + 'active': fields.function( + _get_tile_info, type='boolean', string='Active', + multi='tile_info', readonly=True, fnct_search=_search_active), + 'color': fields.char('Background color'), + 'font_color': fields.char('Font Color'), + 'sequence': fields.integer( + 'Sequence', required=True), + } + + # Constraint Section + def _check_model_id_field_id(self, cr, uid, ids, context=None): + for t in self.browse(cr, uid, ids, context=context): + if t.field_id and t.field_id.model_id.id != t.model_id.id: + return False + return True + + def _check_field_id_field_function(self, cr, uid, ids, context=None): + for t in self.browse(cr, uid, ids, context=context): + if t.field_id and not t.field_function or\ + t.field_function and not t.field_id: + return False + return True + + _constraints = [ + ( + _check_model_id_field_id, + "Error ! Please select a field of the selected model.", + ['model_id', 'field_id']), + ( + _check_field_id_field_function, + "Error ! Please set both fields: 'Field' and 'Function'.", + ['field_id', 'field_function']), + ] + + _defaults = { + 'domain': '[]', + 'color': '#0E6C7E', + 'font_color': '#FFFFFF', + 'sequence': 0, + } + + def open_link(self, cr, uid, ids, context=None): + + tile_id = ids[0] + tile_object = self.browse(cr, uid, tile_id, context=context) + + if tile_object.action_id: + act_obj = self.pool.get('ir.actions.act_window') + result = act_obj.read(cr, uid, [tile_object.action_id.id], + context=context)[0] + # FIXME: restore original Domain + Filter would be better + result['domain'] = tile_object.domain + return result + + # we have no action_id stored, + # so try to load a default tree view + return { + 'name': tile_object.name, + 'view_type': 'form', + 'view_mode': 'tree', + 'view_id': [False], + 'res_model': tile_object.model_id.model, + 'type': 'ir.actions.act_window', + 'context': context, + 'nodestroy': True, + 'target': 'current', + 'domain': tile_object.domain, + } + + def add(self, cr, uid, vals, context=None): + # TODO: check if string + if 'model_id' in vals: + # need to replace model_name with its id + model_ids = self.pool.get('ir.model').search(cr, uid, + [('model', '=', + vals['model_id'])]) + vals['model_id'] = model_ids[0] + return self.create(cr, uid, vals, context) diff --git a/web_dashboard_tile/view/tile.xml b/web_dashboard_tile/view/tile.xml new file mode 100644 index 00000000..154efd90 --- /dev/null +++ b/web_dashboard_tile/view/tile.xml @@ -0,0 +1,120 @@ + + + + + tile.tile.tree + tile.tile + + + + + + + + + + + + + + + tile.tile.form + tile.tile + +
+ + + + + + + + + + + +
+
+
+ + + + tile.tile.kanban + tile.tile + + + + + + + + + + + + + + + + + + + + + + + Dashboard + tile.tile + form + tree,kanban,form + + + + + + + Dashboard + tile.tile + form + kanban + ['|',('user_id','=',False),('user_id','=',uid)] + + + + + Dashboard + + + + + +
+