diff --git a/advanced_dynamic_dashboard/README.rst b/advanced_dynamic_dashboard/README.rst new file mode 100644 index 000000000..8911b899a --- /dev/null +++ b/advanced_dynamic_dashboard/README.rst @@ -0,0 +1,46 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +Advanced Dynamic Dashboard +========================== +* Helps to create configurable dashboards easily. + +Configuration +============= +* No additional configurations needed + +License +------- +General Public License, Version 3 (AGPL v3). +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +Developer: (V14) Unnimaya C O, Contact : odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/advanced_dynamic_dashboard/__init__.py b/advanced_dynamic_dashboard/__init__.py new file mode 100644 index 000000000..369d3f940 --- /dev/null +++ b/advanced_dynamic_dashboard/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import controllers +from . import models diff --git a/advanced_dynamic_dashboard/__manifest__.py b/advanced_dynamic_dashboard/__manifest__.py new file mode 100644 index 000000000..d3709ac07 --- /dev/null +++ b/advanced_dynamic_dashboard/__manifest__.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +{ + 'name': "Advanced Dynamic Dashboard", + 'version': '14.0.1.0.0', + 'category': 'Productivity', + 'summary': """Helps to create configurable dashboards easily.""", + 'description': """This module helps to create configurable advanced dynamic + dashboard to get the information that are relevant to your business, + department or a specific process or need.""", + 'author': 'Cybrosys Techno Solutions', + 'website': "https://www.cybrosys.com", + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'depends': ['web'], + 'data': [ + 'security/ir.model.access.csv', + 'views/dashboard_views.xml', + 'views/dynamic_block_views.xml', + 'views/dashboard_menu_views.xml', + 'views/dynamic_dashboard_views.xml' + ], + 'qweb': [ + 'static/src/xml/dynamic_dashboard_template.xml', + ], + 'images': ['static/description/banner.png'], + 'license': "AGPL-3", + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/advanced_dynamic_dashboard/controllers/__init__.py b/advanced_dynamic_dashboard/controllers/__init__.py new file mode 100644 index 000000000..70c622ced --- /dev/null +++ b/advanced_dynamic_dashboard/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import advanced_dynamic_dashboard diff --git a/advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py b/advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py new file mode 100644 index 000000000..951252f80 --- /dev/null +++ b/advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import http +from odoo.http import request + + +class DynamicDashboard(http.Controller): + """Class to search and filter values in dashboard""" + + @http.route('/tile/details', type='json', auth='user') + def tile_details(self, **kw): + """Function to get tile details""" + tile_id = request.env['dashboard.block'].sudo().browse( + int(kw.get('id'))) + if tile_id: + return {'model': tile_id.model_id.model, 'filter': tile_id.filter, + 'model_name': tile_id.model_id.name} + else: + return False + + @http.route('/custom_dashboard/search_input_chart', type='json', + auth="public", website=True) + def dashboard_search_input_chart(self, search_input): + """Function to filter search input in dashboard""" + return request.env['dashboard.block'].search([ + ('name', 'ilike', search_input)]).ids diff --git a/advanced_dynamic_dashboard/doc/RELEASE_NOTES.md b/advanced_dynamic_dashboard/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..04b0691ba --- /dev/null +++ b/advanced_dynamic_dashboard/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 05.02.2024 +#### Version 14.0.1.0.0 +#### ADD +- Initial commit for Advanced Dynamic Dashboard diff --git a/advanced_dynamic_dashboard/models/__init__.py b/advanced_dynamic_dashboard/models/__init__.py new file mode 100644 index 000000000..8eaed4199 --- /dev/null +++ b/advanced_dynamic_dashboard/models/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from . import dashboard_block +from . import dashboard_menu +from . import models diff --git a/advanced_dynamic_dashboard/models/dashboard_block.py b/advanced_dynamic_dashboard/models/dashboard_block.py new file mode 100644 index 000000000..926b3b32a --- /dev/null +++ b/advanced_dynamic_dashboard/models/dashboard_block.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from ast import literal_eval +from datetime import datetime +from odoo import api, fields, models +from odoo.osv import expression + + +class DashboardBlock(models.Model): + """Class is used to create charts and tiles in dashboard""" + _name = "dashboard.block" + _description = "Dashboard Blocks" + + def get_default_action(self): + """Function to get values from dashboard if action_id is true return + id else return false""" + action_id = self.env.ref( + 'advanced_dynamic_dashboard.dashboard_view_action') + if action_id: + return action_id.id + return False + + name = fields.Char(string="Name", help='Name of the block') + fa_icon = fields.Char(string="Icon", help="Add icon for tile") + graph_size = fields.Selection( + selection=[("col-lg-4", "Small"), ("col-lg-6", "Medium"), + ("col-lg-12", "Large")], + string="Graph Size", default='col-lg-4', help="Select the graph size") + operation = fields.Selection( + selection=[("sum", "Sum"), ("avg", "Average"), ("count", "Count")], + string="Operation", + help='Tile Operation that needs to bring values for tile', + required=True) + graph_type = fields.Selection( + selection=[("bar", "Bar"), ("radar", "Radar"), ("pie", "Pie"), + ("line", "Line"), + ("doughnut", "Doughnut")], + string="Chart Type", help='Type of Chart') + measured_field_id = fields.Many2one("ir.model.fields", + string="Measured Field", + help="Select the Measured") + client_action_id = fields.Many2one('ir.actions.client', + string="Client action", + default=get_default_action, + help="Choose the client action") + type = fields.Selection( + selection=[("graph", "Chart"), ("tile", "Tile")], string="Type", + help='Type of Block ie, Chart or Tile') + x_axis = fields.Char(string="X-Axis", help="Chart X-axis") + y_axis = fields.Char(string="Y-Axis", help="Chart Y-axis") + x_pos = fields.Integer(string="X-Position", help="Chart X-axis position") + y_pos = fields.Integer(string="Y-Position", help="Chart Y-axis position") + height = fields.Integer(string="Height", help="Chart height") + width = fields.Integer(string="Width", help="Chart width") + group_by_id = fields.Many2one("ir.model.fields", store=True, + string="Group by(Y-Axis)", + help='Field value for Y-Axis') + tile_color = fields.Char(string="Tile Color", help='Primary color of Tile') + text_color = fields.Char(string="Text Color", help='Text color of Tile') + val_color = fields.Char(string="Value Color", help='Value color of Tile') + fa_color = fields.Char(string="Icon Color", help='Icon color of Tile') + filter = fields.Char(string="Filter", help="Add filter") + model_id = fields.Many2one('ir.model', string='Model', + help="Select the module name") + model_name = fields.Char(related='model_id.model', string="Model Name", + help="Added model_id model") + edit_mode = fields.Boolean(string="Edit Mode", + help="Enable to edit chart and tile", + invisible=True) + + @api.onchange('model_id') + def _onchange_model_id(self): + self.operation = False + self.measured_field_id = False + self.group_by_id = False + + def get_dashboard_vals(self, action_id, start_date=None, end_date=None): + """Fetch block values from js and create chart""" + block_id = [] + for rec in self.sudo().search( + [('client_action_id', '=', int(action_id))]): + if rec.filter is False: + rec.filter = "[]" + filter_list = literal_eval(rec.filter) + # Remove existing date filters if any exist + filter_list = [filter_item for filter_item in filter_list if not ( + isinstance(filter_item, tuple) and filter_item[0] == + 'create_date')] + if start_date and start_date != 'null': + start_date_obj = datetime.strptime(start_date, + '%Y-%m-%d') + filter_list.append( + ('create_date', '>=', start_date_obj.strftime('%Y-%m-%d'))) + if end_date and end_date != 'null': + end_date_obj = datetime.strptime(end_date, '%Y-%m-%d') + filter_list.append( + ('create_date', '<=', end_date_obj.strftime('%Y-%m-%d'))) + rec.filter = repr(filter_list) + vals = {'id': rec.id, 'name': rec.name, 'type': rec.type, + 'graph_type': rec.graph_type, 'icon': rec.fa_icon, + 'cols': rec.graph_size, + 'color': 'background-color: %s;' % rec.tile_color + if rec.tile_color else '#1f6abb;', + 'text_color': 'color: %s;' % rec.text_color + if rec.text_color else '#FFFFFF;', + 'val_color': 'color: %s;' % rec.val_color + if rec.val_color else '#FFFFFF;', + 'icon_color': 'color: %s;' % rec.tile_color + if rec.tile_color else '#1f6abb;', + 'x_pos': rec.x_pos, 'y_pos': rec.y_pos, + 'height': rec.height, + 'width': rec.width} + domain = [] + if rec.filter: + domain = expression.AND([literal_eval(rec.filter)]) + if rec.model_name: + if rec.type == 'graph': + self._cr.execute(self.env[rec.model_name]. + get_query(domain, rec.operation, + rec.measured_field_id, + group_by=rec.group_by_id)) + records = self._cr.dictfetchall() + x_axis = [] + for record in records: + if record.get('name') and type( + record.get('name')) == dict: + x_axis.append(record.get('name')[self._context.get( + 'lang') or 'en_US']) + else: + x_axis.append(record.get(rec.group_by_id.name)) + y_axis = [] + for record in records: + y_axis.append(record.get('value')) + vals.update({'x_axis': x_axis, 'y_axis': y_axis}) + else: + self._cr.execute(self.env[rec.model_name]. + get_query(domain, rec.operation, + rec.measured_field_id)) + records = self._cr.dictfetchall() + magnitude = 0 + total = records[0].get('value') + while abs(total) >= 1000: + magnitude += 1 + total /= 1000.0 + # add more suffixes if you need them + val = '%.2f%s' % ( + total, ['', 'K', 'M', 'G', 'T', 'P'][magnitude]) + records[0]['value'] = val + vals.update(records[0]) + block_id.append(vals) + return block_id + + def get_save_layout(self, act_id, grid_data_list): + """Function fetch edited values while edit layout of the chart or tile + and save values in a database""" + for block in self.env['dashboard.block'].sudo().search( + [('client_action_id', '=', int(act_id))]): + for data in grid_data_list: + if block['id'] == data['id']: + block.write({ + 'x_pos': int(data['x']), + 'y_pos': int(data['y']), + 'height': int(data['height']), + 'width': int(data['width']), + }) diff --git a/advanced_dynamic_dashboard/models/dashboard_menu.py b/advanced_dynamic_dashboard/models/dashboard_menu.py new file mode 100644 index 000000000..ff84a92b8 --- /dev/null +++ b/advanced_dynamic_dashboard/models/dashboard_menu.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import api, fields, models + + +class DashboardMenu(models.Model): + """Class to create new dashboard menu""" + _name = "dashboard.menu" + _description = "Dashboard Menu" + + name = fields.Char(string="Name", + help="Enter a name for the dashboard menu") + menu_id = fields.Many2one('ir.ui.menu', string="Parent Menu", + help="Parent Menu Location of New Dashboard", + ondelete='cascade') + group_ids = fields.Many2many('res.groups', string='Groups', + related='menu_id.groups_id', + help="User need to be at least in one of " + "these groups to see the menu") + client_action_id = fields.Many2one('ir.actions.client', + string="Client Action", + help="Client action") + + @api.model + def create(self, vals): + """Function to create new dashboard menu""" + action_id = self.env['ir.actions.client'].create({ + 'name': vals['name'], + 'tag': 'advanced_dynamic_dashboard', + }) + vals['client_action_id'] = action_id.id + self.env['ir.ui.menu'].create({ + 'name': vals['name'], + 'parent_id': vals['menu_id'], + 'action': 'ir.actions.client,%d' % (action_id.id,) + }) + return super().create(vals) + + def write(self, vals): + """Function to save edited data in dashboard menu""" + for rec in self: + client_act_id = rec['client_action_id'].id + self.env['ir.ui.menu'].search( + [('parent_id', '=', rec['menu_id'].id), + ('action', '=', f'ir.actions.client,{client_act_id}')]).write( + {'name': vals['name'] if 'name' in vals.keys() else rec['name'], + 'parent_id': vals['menu_id'] if 'menu_id' in vals.keys() else + rec['menu_id'], + 'action': f'ir.actions.client,{client_act_id}' + }) + return super().write(vals) + + def unlink(self): + """Delete dashboard along with menu item""" + for rec in self: + self.env['ir.ui.menu'].search( + [('parent_id', '=', rec['menu_id'].id), + ('action', '=', + f'ir.actions.client,{rec["client_action_id"].id}')]).unlink() + return super().unlink() diff --git a/advanced_dynamic_dashboard/models/models.py b/advanced_dynamic_dashboard/models/models.py new file mode 100644 index 000000000..12808f1dd --- /dev/null +++ b/advanced_dynamic_dashboard/models/models.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# 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 (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +################################################################################ +from odoo import models + + +def get_query(self, args, operation, field, group_by=False, + apply_ir_rules=False): + """Method for creating query for fetching data to be displayed on the + dashboard block""" + query = self._where_calc(args) + if apply_ir_rules: + self._apply_ir_rules(query, 'read') + join = '' + group_by_str = '' + if operation and field: + data = 'COALESCE(%s("%s".%s),0) AS value' % (operation.upper(), + self._table, field.name) + if group_by: + if group_by.ttype == 'many2one': + relation_model = group_by.relation.replace('.', '_') + join = ' INNER JOIN %s on "%s".id = "%s".%s' % ( + relation_model, relation_model, self._table, group_by.name) + rec_name = self.env[group_by.relation]._rec_name_fallback() + data = data + ',"%s".%s AS %s' % (relation_model, rec_name, + group_by.name) + group_by_str = ' Group by "%s".%s' % (relation_model, rec_name) + else: + data = data + ',"%s".%s' % (self._table, group_by.name) + group_by_str = ' Group by "%s".%s' % (self._table, + str(group_by.name)) + else: + data = '"%s".id' % self._table + from_clause, where_clause, where_clause_params = query.get_sql() + where_str = where_clause and (" WHERE %s" % where_clause) or '' + query_str = ('SELECT %s FROM ' % data + from_clause + join + where_str + + group_by_str) + return query_str % tuple( + map(lambda x: "'" + str(x) + "'", where_clause_params)) + + +models.BaseModel.get_query = get_query diff --git a/advanced_dynamic_dashboard/security/ir.model.access.csv b/advanced_dynamic_dashboard/security/ir.model.access.csv new file mode 100644 index 000000000..19830e967 --- /dev/null +++ b/advanced_dynamic_dashboard/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_dashboard_block_user,access.dashboard.block.user,model_dashboard_block,base.group_user,1,1,1,1 +access_dashboard_menu_user,access.dashboard.menu.user,model_dashboard_menu,base.group_user,1,1,1,1 diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/check.png b/advanced_dynamic_dashboard/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/check.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/cogs.png b/advanced_dynamic_dashboard/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/cogs.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/consultation.png b/advanced_dynamic_dashboard/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/consultation.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/down.svg b/advanced_dynamic_dashboard/static/description/assets/icons/down.svg new file mode 100644 index 000000000..f21c36271 --- /dev/null +++ b/advanced_dynamic_dashboard/static/description/assets/icons/down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/ecom-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/ecom-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/education-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/education-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/faq.png b/advanced_dynamic_dashboard/static/description/assets/icons/faq.png new file mode 100644 index 000000000..4250b5b81 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/faq.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/feature.png b/advanced_dynamic_dashboard/static/description/assets/icons/feature.png new file mode 100644 index 000000000..ac7a785c0 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/feature.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/license.png b/advanced_dynamic_dashboard/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/license.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png b/advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png b/advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/screenshot.png b/advanced_dynamic_dashboard/static/description/assets/icons/screenshot.png new file mode 100644 index 000000000..cef272529 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/screenshot.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/service-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/service-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/support.png b/advanced_dynamic_dashboard/static/description/assets/icons/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/support.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/test-2.png b/advanced_dynamic_dashboard/static/description/assets/icons/test-2.png new file mode 100644 index 000000000..08022c474 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/test-2.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png b/advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/training.png b/advanced_dynamic_dashboard/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/training.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/update.png b/advanced_dynamic_dashboard/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/update.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/user.png b/advanced_dynamic_dashboard/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/user.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/video.png b/advanced_dynamic_dashboard/static/description/assets/icons/video.png new file mode 100644 index 000000000..576705b17 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/video.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/whatsapp.png b/advanced_dynamic_dashboard/static/description/assets/icons/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/whatsapp.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/icons/wrench.png b/advanced_dynamic_dashboard/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/icons/wrench.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/categories.png b/advanced_dynamic_dashboard/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/categories.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/check-box.png b/advanced_dynamic_dashboard/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/check-box.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/compass.png b/advanced_dynamic_dashboard/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/compass.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/corporate.png b/advanced_dynamic_dashboard/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/corporate.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/customer-support.png b/advanced_dynamic_dashboard/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/customer-support.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/cybrosys-logo.png b/advanced_dynamic_dashboard/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/cybrosys-logo.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/features.png b/advanced_dynamic_dashboard/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/features.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/logo.png b/advanced_dynamic_dashboard/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/logo.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/pictures.png b/advanced_dynamic_dashboard/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/pictures.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/pie-chart.png b/advanced_dynamic_dashboard/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/pie-chart.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/right-arrow.png b/advanced_dynamic_dashboard/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/right-arrow.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/star.png b/advanced_dynamic_dashboard/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/star.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/support.png b/advanced_dynamic_dashboard/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/support.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/misc/whatsapp.png b/advanced_dynamic_dashboard/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/misc/whatsapp.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/1.png b/advanced_dynamic_dashboard/static/description/assets/modules/1.png new file mode 100644 index 000000000..b987fd3b5 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/1.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/2.png b/advanced_dynamic_dashboard/static/description/assets/modules/2.png new file mode 100644 index 000000000..1f05ed27f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/2.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/3.gif b/advanced_dynamic_dashboard/static/description/assets/modules/3.gif new file mode 100644 index 000000000..69bf230e7 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/3.gif differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/3.png b/advanced_dynamic_dashboard/static/description/assets/modules/3.png new file mode 100644 index 000000000..28800d37c Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/3.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/4.png b/advanced_dynamic_dashboard/static/description/assets/modules/4.png new file mode 100644 index 000000000..24abcb0a2 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/4.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/5.png b/advanced_dynamic_dashboard/static/description/assets/modules/5.png new file mode 100644 index 000000000..09d86f8ec Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/5.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/modules/6.png b/advanced_dynamic_dashboard/static/description/assets/modules/6.png new file mode 100644 index 000000000..cdcfef5ae Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/modules/6.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/1.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..718a351cb Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/1.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/10.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/10.png new file mode 100644 index 000000000..e7a729dd9 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/10.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/11.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/11.png new file mode 100644 index 000000000..941aab369 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/11.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/12.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/12.png new file mode 100644 index 000000000..bca328ab9 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/12.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/13.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/13.png new file mode 100644 index 000000000..ea86a1641 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/13.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/2.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..926bfc259 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/2.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/3.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..3abb995f1 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/3.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/4.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..38189513f Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/4.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/5.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..bc9712c41 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/5.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/6.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..edc47895c Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/6.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/7.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..ae9e5ce45 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/7.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/8.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..c38bf9cdc Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/8.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/9.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..3494a0a6e Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/9.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif b/advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..1aee26e39 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png new file mode 100644 index 000000000..07de37fbc Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png new file mode 100644 index 000000000..cd916f845 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png new file mode 100644 index 000000000..131f7485c Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png new file mode 100644 index 000000000..0088d84a4 Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png differ diff --git a/advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png b/advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png new file mode 100644 index 000000000..45f2eb3ef Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png differ diff --git a/advanced_dynamic_dashboard/static/description/banner.png b/advanced_dynamic_dashboard/static/description/banner.png new file mode 100644 index 000000000..f1537328b Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/banner.png differ diff --git a/advanced_dynamic_dashboard/static/description/icon.png b/advanced_dynamic_dashboard/static/description/icon.png new file mode 100644 index 000000000..ce37d9b9e Binary files /dev/null and b/advanced_dynamic_dashboard/static/description/icon.png differ diff --git a/advanced_dynamic_dashboard/static/description/index.html b/advanced_dynamic_dashboard/static/description/index.html new file mode 100644 index 000000000..e99fb0c6f --- /dev/null +++ b/advanced_dynamic_dashboard/static/description/index.html @@ -0,0 +1,714 @@ +
+ +
+ +
+
+ Enterprise +
+
+ Community +
+
+ Odoo.sh +
+
+
+ +
+
+
+ +

+ Advanced Dynamic Dashboard +

+

+ Facilitates the Seamless Creation of Customizable + Dashboards.

+ + +
+
+
+
+ +
+
+ +
+

+ Explore This + Module

+
+ + + +
+
+ +
+

+ Overview +

+
+
+
+ The Advanced Dynamic Dashboard module empowers users to + customize,arrange, and access real-time data relevant to their + business, + department, or specific processes, facilitating informed + decision-making and optimized performance. +
+
+ + +
+
+ +
+

+ Features +

+
+
+
+
+ + Effortlessly generate interactive Charts and Tiles. +
+
+ + Available Dark mode and Light mode. +
+
+ + Feasible to establish a Dashboard Menu in any + model. +
+
+ + Charts can be exported as Images, PDFs, and CSVs. +
+
+ + Enable dragging and resizing of Charts and Tiles for + flexible layouts. +
+
+ + Edit and configure Charts and Tiles +
+
+
+ + +
+
+ +
+

+ Screenshots +

+
+
+
+
+

+ Click ADD ITEMS to add Graphs and Tiles to the Dashboard. +

+ +
+
+

+ Add required details for creating a Tile. +

+ +
+
+

+ New Tiles on the dashboard. +

+ +
+
+

+ Create new Chart. +

+ +
+
+

+ Charts added to the dashboard. +

+ +
+
+

+ Dashboard based on the date filter. +

+ +
+
+

+ It is possible to Search the name of chart or tile. +

+ +
+
+

+ Click the marked button for enabling Dark Mode. +

+ +
+
+

+ Dashboard in Dark Mode. +

+ +
+
+

+ Click EDIT LAYOUT for editing the dashboard layout. +

+ +
+
+

+ It is possible to change size of chart and tile by clicking the + marked icon, also we can drag them to any position. +

+

+

+ +
+
+

+ Click on the 3 dots icon for exporting the graphs. +

+ +
+
+

+ Graph exported as image. +

+ +
+
+

+ Graph exported as pdf. +

+ +
+

+ Navigate to Dashboards menu to add the dashboard menu under any + menu. +

+ +
+
+

+ Choose the menu name and parent menu. +

+ +
+
+

+ New menu added in Inventory module. +

+ +
+
+

+ We can create new dashboard here. +

+

+

+ +
+
+
+ + +
+
+ +
+

+ Related + Products +

+
+
+
+ +
+
+ + +
+
+ +
+

+ Our Services +

+
+
+
+
+
+ +
+
+ Odoo + Customization
+
+
+
+ +
+
+ Odoo + Implementation
+
+
+
+ +
+
+ Odoo + Support
+
+
+
+ +
+
+ Hire + Odoo + Developer
+
+
+
+ +
+
+ Odoo + Integration
+
+
+
+ +
+
+ Odoo + Migration
+
+
+
+ +
+
+ Odoo + Consultancy
+
+
+
+ +
+
+ Odoo + Implementation
+
+
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + +
+
+ +
+

+ Our + Industries +

+
+
+
+
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+
+
+ + +
+
+ +
+

+ Support +

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? + Get in touch.

+ +

+ odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+ +91 86068 + 27707

+
+
+
+
+
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/advanced_dynamic_dashboard/static/lib/css/gridstack.min.css b/advanced_dynamic_dashboard/static/lib/css/gridstack.min.css new file mode 100644 index 000000000..2e6e98b6f --- /dev/null +++ b/advanced_dynamic_dashboard/static/lib/css/gridstack.min.css @@ -0,0 +1 @@ +:root .grid-stack-item>.ui-resizable-handle{filter:none}.grid-stack{position:relative}.grid-stack.grid-stack-rtl{direction:ltr}.grid-stack.grid-stack-rtl>.grid-stack-item{direction:rtl}.grid-stack .grid-stack-placeholder>.placeholder-content{border:1px dashed #d3d3d3;margin:0;position:absolute;top:0;left:10px;right:10px;bottom:0;width:auto;z-index:0!important;text-align:center}.grid-stack>.grid-stack-item{min-width:8.3333333333%;position:absolute;padding:0}.grid-stack>.grid-stack-item>.grid-stack-item-content{margin:0;position:absolute;top:0;left:10px;right:10px;bottom:0;width:auto;z-index:0!important;overflow-x:hidden;overflow-y:hidden}.grid-stack>.grid-stack-item>.ui-resizable-handle{position:absolute;font-size:.1px;display:block;-ms-touch-action:none;touch-action:none}.grid-stack>.grid-stack-item.ui-resizable-autohide>.ui-resizable-handle,.grid-stack>.grid-stack-item.ui-resizable-disabled>.ui-resizable-handle{display:none}.grid-stack>.grid-stack-item.ui-draggable-dragging,.grid-stack>.grid-stack-item.ui-resizable-resizing{z-index:100}.grid-stack>.grid-stack-item.ui-draggable-dragging>.grid-stack-item-content,.grid-stack>.grid-stack-item.ui-resizable-resizing>.grid-stack-item-content{box-shadow:1px 4px 6px rgba(0,0,0,.2);opacity:.8}.grid-stack>.grid-stack-item>.ui-resizable-se,.grid-stack>.grid-stack-item>.ui-resizable-sw{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIEdlbmVyYXRvcjogQWRvYmUgSWxsdXN0cmF0b3IgMTYuMC4wLCBTVkcgRXhwb3J0IFBsdWctSW4gLiBTVkcgVmVyc2lvbjogNi4wMCBCdWlsZCAwKSAgLS0+CjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjE2cHgiIGhlaWdodD0iMTZweCIgdmlld0JveD0iMCAwIDUxMS42MjYgNTExLjYyNyIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTExLjYyNiA1MTEuNjI3OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTMyOC45MDYsNDAxLjk5NGgtMzYuNTUzVjEwOS42MzZoMzYuNTUzYzQuOTQ4LDAsOS4yMzYtMS44MDksMTIuODQ3LTUuNDI2YzMuNjEzLTMuNjE1LDUuNDIxLTcuODk4LDUuNDIxLTEyLjg0NSAgIGMwLTQuOTQ5LTEuODAxLTkuMjMxLTUuNDI4LTEyLjg1MWwtNzMuMDg3LTczLjA5QzI2NS4wNDQsMS44MDksMjYwLjc2LDAsMjU1LjgxMywwYy00Ljk0OCwwLTkuMjI5LDEuODA5LTEyLjg0Nyw1LjQyNCAgIGwtNzMuMDg4LDczLjA5Yy0zLjYxOCwzLjYxOS01LjQyNCw3LjkwMi01LjQyNCwxMi44NTFjMCw0Ljk0NiwxLjgwNyw5LjIyOSw1LjQyNCwxMi44NDVjMy42MTksMy42MTcsNy45MDEsNS40MjYsMTIuODUsNS40MjYgICBoMzYuNTQ1djI5Mi4zNThoLTM2LjU0MmMtNC45NTIsMC05LjIzNSwxLjgwOC0xMi44NSw1LjQyMWMtMy42MTcsMy42MjEtNS40MjQsNy45MDUtNS40MjQsMTIuODU0ICAgYzAsNC45NDUsMS44MDcsOS4yMjcsNS40MjQsMTIuODQ3bDczLjA4OSw3My4wODhjMy42MTcsMy42MTcsNy44OTgsNS40MjQsMTIuODQ3LDUuNDI0YzQuOTUsMCw5LjIzNC0xLjgwNywxMi44NDktNS40MjQgICBsNzMuMDg3LTczLjA4OGMzLjYxMy0zLjYyLDUuNDIxLTcuOTAxLDUuNDIxLTEyLjg0N2MwLTQuOTQ4LTEuODA4LTkuMjMyLTUuNDIxLTEyLjg1NCAgIEMzMzguMTQyLDQwMy44MDIsMzMzLjg1Nyw0MDEuOTk0LDMyOC45MDYsNDAxLjk5NHoiIGZpbGw9IiM2NjY2NjYiLz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8Zz4KPC9nPgo8L3N2Zz4K);background-repeat:no-repeat;background-position:center;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.grid-stack>.grid-stack-item>.ui-resizable-se{-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-ms-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg)}.grid-stack>.grid-stack-item>.ui-resizable-nw{cursor:nw-resize;width:20px;height:20px;left:10px;top:0}.grid-stack>.grid-stack-item>.ui-resizable-n{cursor:n-resize;height:10px;top:0;left:25px;right:25px}.grid-stack>.grid-stack-item>.ui-resizable-ne{cursor:ne-resize;width:20px;height:20px;right:10px;top:0}.grid-stack>.grid-stack-item>.ui-resizable-e{cursor:e-resize;width:10px;right:10px;top:15px;bottom:15px}.grid-stack>.grid-stack-item>.ui-resizable-se{cursor:se-resize;width:20px;height:20px;right:10px;bottom:0}.grid-stack>.grid-stack-item>.ui-resizable-s{cursor:s-resize;height:10px;left:25px;bottom:0;right:25px}.grid-stack>.grid-stack-item>.ui-resizable-sw{cursor:sw-resize;width:20px;height:20px;left:10px;bottom:0}.grid-stack>.grid-stack-item>.ui-resizable-w{cursor:w-resize;width:10px;left:10px;top:15px;bottom:15px}.grid-stack>.grid-stack-item.ui-draggable-dragging>.ui-resizable-handle{display:none!important}.grid-stack>.grid-stack-item[data-gs-width='1']{width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='1']{left:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='1']{min-width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='1']{max-width:8.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='2']{width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='2']{left:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='2']{min-width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='2']{max-width:16.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='3']{width:25%}.grid-stack>.grid-stack-item[data-gs-x='3']{left:25%}.grid-stack>.grid-stack-item[data-gs-min-width='3']{min-width:25%}.grid-stack>.grid-stack-item[data-gs-max-width='3']{max-width:25%}.grid-stack>.grid-stack-item[data-gs-width='4']{width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='4']{left:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='4']{min-width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='4']{max-width:33.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='5']{width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='5']{left:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='5']{min-width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='5']{max-width:41.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='6']{width:50%}.grid-stack>.grid-stack-item[data-gs-x='6']{left:50%}.grid-stack>.grid-stack-item[data-gs-min-width='6']{min-width:50%}.grid-stack>.grid-stack-item[data-gs-max-width='6']{max-width:50%}.grid-stack>.grid-stack-item[data-gs-width='7']{width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='7']{left:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='7']{min-width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='7']{max-width:58.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='8']{width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='8']{left:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='8']{min-width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='8']{max-width:66.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='9']{width:75%}.grid-stack>.grid-stack-item[data-gs-x='9']{left:75%}.grid-stack>.grid-stack-item[data-gs-min-width='9']{min-width:75%}.grid-stack>.grid-stack-item[data-gs-max-width='9']{max-width:75%}.grid-stack>.grid-stack-item[data-gs-width='10']{width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-x='10']{left:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-min-width='10']{min-width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-max-width='10']{max-width:83.3333333333%}.grid-stack>.grid-stack-item[data-gs-width='11']{width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-x='11']{left:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-min-width='11']{min-width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-max-width='11']{max-width:91.6666666667%}.grid-stack>.grid-stack-item[data-gs-width='12']{width:100%}.grid-stack>.grid-stack-item[data-gs-x='12']{left:100%}.grid-stack>.grid-stack-item[data-gs-min-width='12']{min-width:100%}.grid-stack>.grid-stack-item[data-gs-max-width='12']{max-width:100%}.grid-stack.grid-stack-animate,.grid-stack.grid-stack-animate .grid-stack-item{-webkit-transition:left .3s,top .3s,height .3s,width .3s;-moz-transition:left .3s,top .3s,height .3s,width .3s;-ms-transition:left .3s,top .3s,height .3s,width .3s;-o-transition:left .3s,top .3s,height .3s,width .3s;transition:left .3s,top .3s,height .3s,width .3s}.grid-stack.grid-stack-animate .grid-stack-item.grid-stack-placeholder,.grid-stack.grid-stack-animate .grid-stack-item.ui-draggable-dragging,.grid-stack.grid-stack-animate .grid-stack-item.ui-resizable-resizing{-webkit-transition:left 0s,top 0s,height 0s,width 0s;-moz-transition:left 0s,top 0s,height 0s,width 0s;-ms-transition:left 0s,top 0s,height 0s,width 0s;-o-transition:left 0s,top 0s,height 0s,width 0s;transition:left 0s,top 0s,height 0s,width 0s}.grid-stack.grid-stack-one-column-mode{height:auto!important}.grid-stack.grid-stack-one-column-mode>.grid-stack-item{position:relative!important;width:auto!important;left:0!important;top:auto!important;margin-bottom:20px;max-width:none!important}.grid-stack.grid-stack-one-column-mode>.grid-stack-item>.ui-resizable-handle{display:none} \ No newline at end of file diff --git a/advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css b/advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css new file mode 100644 index 000000000..6bc75f875 --- /dev/null +++ b/advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css @@ -0,0 +1,365 @@ +.row { + margin: 1rem; +} + +.o_dynamic_navbar { + margin: 1rem 0 1rem 0; +} + +.card { + background-color: transparent !important; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + border-radius: 5px !important; + cursor: pointer; + transition: transform 0.2s; +} + +.grid-stack-item { + position: absolute !important; + font-size: 100%; + overflow:hidden; +} + + +.card:hover { + transform: scale(1.05); +} + +.card-header { + border-radius: 0.5rem 0.5rem 0 0 !important; +} + +.container { + max-width: 100% !important; +} + +.tile-container { + padding: 0 0 0 10px; + border-radius: 0.5rem !important; +} + +.tile { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + border-radius: 5px; + cursor: pointer; + transition: transform 0.2s; +} + + +#search-input-chart { + margin-left: auto; + height: 2.4rem; +} + +#searchclear { + position: absolute; + margin: 0.3rem 0 0 13.5rem; +} + +.navbar-collapse { + margin-bottom: 8px !important; +} + +div.card-header { + color: #383838; + background-color: #70659647 !important; +} + +/* The toggle-btn - the box around the slider */ +.layout-switch { + font-size: 15px; + position: absolute; + left: 10.5em; + display: inline-block; + padding: 0 0 0 0; + border-radius: 0.5rem; +} + +.toggle-btn { + font-size: 15px; + position: absolute; + left: 18.2em; + display: inline-block; + padding: 4px 0 0 0; + border-radius: 0.5rem; +} + +.theme-text { + font-family: Arial, sans-serif; + font-size: 1em; + opacity: 70%; +} + +.search-group { + position: absolute; + right: 1.7em; +} + +/*!* Hide default HTML checkbox *!*/ +.toggle-btn input { + opacity: 0; + width: 0; + height: 0; +} + +/*!* The slider *!*/ +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .4s; + transition: .4s; +} + +.theme_icon { + font-weight: bold; +} + +.theme_icon:hover { + text-shadow: 2px 1px 20px #795db3; +} + +.block_setting { + position: absolute; + top: 7px; + left: 10px; +} + +.block_delete { + position: absolute; + top: 7px; + right: 20px; +} + +.export_option { + position: absolute; + top: 9px; + right: 520px; + font-size: 15px; +} + +#ExportMenu::after { + display: none; +} + +.tile_edit { + color: #d2d2d2; +} + +.block_edit { + color: #3f3f3f; +} + +.dropdown-export { + right: 0; + top: 1em; +} + +.block_setting, .block_delete, .block_export { + display: none; +} + +.grid-stack-item:hover .block_setting, +.grid-stack-item:hover .block_export, +.grid-stack-item:hover .block_delete { + display: block; +} + +.chart-edit { + position: absolute; + top: 0px; + left: 3px; + font-size: 16px; +} + +.chart-setting { + position: absolute; + top: 0px; + right: 3px; + font-size: 16px; +} + +.chart_title { + padding-top: 0.7em; + text-align: center; + font-size: 16px; +} + +input:checked + .slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +.move_slider { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; + margin: -1px 6px 11px 0; +} + +.slider.round:before { + border-radius: 50%; +} + +.bootbox .modal-footer .btn-danger:hover { + background-color: #ff595c; +} + +.bootbox .modal-footer .btn-danger { + box-shadow: none; + margin-left: 0.5rem; +} + +.bootbox .modal-header { + text-shadow: -1px 3px 5px #b4b4b4; +} + +.bootbox .modal-body { + font-size: 14px; + text-shadow: -1px 3px 5px #b4b4b4; + color: #000000; +} + +.dropdown-addblock, .o-dropdown-menu { + left: 2.5em; + top: 2.5em; +} +.navbar { + padding: 1.2rem 0 2.6rem 0 !important; + border-bottom: 1px solid #3f3f3f1a !important; + color: #444444; + background-color: #e1e2e26e !important; + border-bottom: 5px solid #eef0f0 !important; +} + +.theme_icon:hover { + text-shadow: 0px 0px 5px #9388ff; +} + +.navbar-style { + margin-top: 1.2em; + border-radius: 0.5em; +} + +.grid-stack > .grid-stack-item > .grid-stack-item-content { + overflow-x: unset !important; + overflow-y: unset !important; +} + + +.dropdown-add-items { + position: absolute; + color: #e4e4e4; + left: 2em; + font-size: 16px; + text-transform: uppercase; + background-color: #71639e; + border: 1px solid transparent; + padding: 0.375rem 0.75rem; + font-size: 1.08333333rem; + border-radius: 0.25rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +.dropdown-add-items:hover { + color: white; + background-color: #59507b; +} + + +@media (max-width: 767px) { + .navbar { + padding: 1.2rem 0 1.2rem 0; + } + + .navbar:focus, .navbar:active { + padding: 1.2rem 0 2rem 0; + } + + .search-group { + width: 50%; + position: absolute; + right: 3.7em; + } + + .o_web_client.o_touch_device .btn, .o_web_client.o_touch_device .btn .btn-sm, .o_web_client.o_touch_device .btn .btn-group-sm > .btn { + font-size: 1.08333333rem; + padding: 6px 8px; + margin-top: 39px; + margin-left: -39px; + } + + .grid-stack-item-content { + cursor: move; + width: 211px; + height: 63px; + } + + /* !* styles for mobile devices *!*/ + .grid-stack.grid-stack-one-column-mode > .grid-stack-item { + width: 100% !important; + } + + .dropdown-item { + font-size: 1.08333333rem; + font-weight: 500; + } + + .dropdown-addblock, .o-dropdown-menu { + left: -3.5em; + padding: 0em 7em; + margin-top: 38px; + width: 276px; + } + + .toggle-btn { + position: absolute; + margin-top: -16px; + margin-left: 56px; + left: 1.2em; + top: 2.3em; + height: 10px; + } + + #edit_layout { + display: none; + } + + #search-button { + position: relative; + left: 3.5em; + } + + .search-box { + top: -3em; + left: 7.5em; + margin: 0em -1.9em; + width: 79%; + position: relative; + } + .navbar-toggler { + margin: 0.2em 1em; + padding: 0.25rem 0.5rem; + } + + .dropdown-add-items { + position: absolute; + color: #e4e4e4; + top: -2.6em; + left: 3.5em; + } +} diff --git a/advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js b/advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js new file mode 100644 index 000000000..72db791c4 --- /dev/null +++ b/advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js @@ -0,0 +1,598 @@ +odoo.define('advanced_dynamic_dashboard.Dashboard', function (require) { + "use strict"; + var AbstractAction = require('web.AbstractAction'); + var ajax = require('web.ajax'); + var core = require('web.core'); + var rpc = require('web.rpc'); + var QWeb = core.qweb; + var Dialog = require('web.Dialog'); + var DynamicDashboard = AbstractAction.extend({ + template: 'advanced_dynamic_dashboard', + events: { + 'click .add_block': '_onClick_add_block', + 'click .block_setting': '_onClick_block_setting', + 'click .block_delete': '_onClick_block_delete', + 'click #search-button': 'search_chart', + 'click #searchclear': 'clear_search', + 'click #dropdownNavbar': 'navbar_toggle', + 'mouseenter #dropdownMenuButton': 'dropdown_toggle', + 'click .chart_item_export': 'export_item', + 'click #edit_layout': '_onClick_edit_layout', + 'click #save_layout': '_onClick_save_layout', + 'change #theme-toggle': 'switch_mode', + 'change #start-date': '_onchangeFilter', + 'change #end-date': '_onchangeFilter', + 'mouseenter #theme-change-icon': 'show_mode_text', + 'mouseleave #theme-change-icon': 'hide_mode_text', + 'click .tile': '_onClick_tile' + }, + //Function to Initializes all the values while loading the file + init: function (parent, context) { + this.action_id = context['id']; + this._super(parent, context); + this.block_ids = []; + }, + //Returns the function fetch_data when page load. + willStart: function () { + var self = this; + return $.when(this._super()).then(function () { + return self.fetch_data(); + }); + }, + //Function return render_dashboards() and gridstack_init() + start: function () { + self = this; + this.set("title", 'Dashboard'); + return this._super().then(function () { + self.render_dashboards(); + }); + }, + //Fetch data and call rpc query to create chart or tile. return block_ids + fetch_data: function () { + self = this; + var def1 = this._rpc({ + model: 'dashboard.block', + method: 'get_dashboard_vals', + args: [[], this.action_id] + }).then(function (result) { + self.block_ids = result; + }); + return $.when(def1); + }, + //Function change text of dark and light mode while clicking the dark and light button. + show_mode_text: function () { + this.$el.find('.theme_icon').next(this.el.querySelector('.theme-text')).remove(); + if ( this.$el.find('#theme-toggle').is(':checked')) {//Set text "Light Mode" + this.$el.find('.theme_icon').after('⠀Light Mode'); + } else { + //Set text "Dark Mode" + this.$el.find('.theme_icon').after('⠀Dark Mode'); + } + this.$el.find('.theme_icon').next(this.el.querySelector('.theme-text')).fadeIn(); + }, + //While click button, hide the mode icon and text + hide_mode_text: function () { + this.$el.find('.theme_icon').next(this.el.querySelector('.theme-text')).fadeOut(function () { + $(this).remove(); + }); + }, + //Function to change dashboard theme dark and light mode. + switch_mode: function (ev) { + this.$el.find('.theme_icon').next('.theme-text').remove(); + const isDarkTheme = this.$el.find('#theme-toggle').is(':checked'); + $(this.el.parentElement).toggleClass('dark-theme', isDarkTheme); + this.$el.find('.theme_icon').toggleClass('bi-sun-fill', isDarkTheme); + this.$el.find('.theme_icon').toggleClass('bi-moon-stars-fill', !isDarkTheme); + this.$el.find('.dropdown-export').toggleClass('dropdown-menu-dark', isDarkTheme); + }, + //Function for applying filter + _onchangeFilter: function() { + var start_date = this.$('#start-date').val(); + var end_date = this.$('#end-date').val(); + if (!start_date) { + start_date = "null"; + } + if (!end_date) { + end_date = "null"; + } + this._rpc({ + model: 'dashboard.block', + method: 'get_dashboard_vals', + args: [[], this.action_id, start_date, end_date], + }).then(function (result) { + self.block_ids = result; + // Reinitialize gridstack layout after updating data + self.gridstack_init(self); + self.$('.o_dynamic_dashboard').empty(); + self.render_dashboards(); + }); + }, + //Function fetch random color values and set chart color + get_colors: function (x_axis) { + return x_axis.map(() => `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`); + }, + //Set bar chart label, color, data and options. And return data and options + get_values_bar: function (block) { + var data = { + labels: block.x_axis, + datasets: [{ + data: block.y_axis, + backgroundColor: this.get_colors(block.x_axis), + borderColor: 'rgba(200, 200, 200, 0.75)', + borderWidth: 1 + }] + }; + var options = { + scales: { + y: { + beginAtZero: true + } + } + }; + return [data, options]; + }, + //Set pie chart data and options. And return data and options. + get_values_pie: function (block) { + var data = { + labels: block['x_axis'], + datasets: [{ + label: '', + data: block['y_axis'], + backgroundColor: this.get_colors(block['x_axis']), + hoverOffset: 4 + }] + }; + return [data, {}]; + }, + //Set line chart label, data and options. And return data and options. + get_values_line: function (block) { + var data = { + labels: block['x_axis'], + datasets: [{ + label: '', + data: block['y_axis'], + fill: false, + borderColor: 'rgb(75, 192, 192)', + tension: 0.1 + }] + }; + return [data, {}]; + }, + // Set doughnut chart data and options. And return data and options. + get_values_doughnut: function (block) { + var data = { + labels: block['x_axis'], + datasets: [{ + label: '', + data: block['y_axis'], + backgroundColor: this.get_colors(block['x_axis']), + hoverOffset: 4 + }] + }; + return [data, {}]; + }, + // Set radar chart data and options. And return data and options. + get_values_radar: function (block) { + var data = { + labels: block['x_axis'], + datasets: [{ + label: '', + data: block['y_axis'], + fill: true, + backgroundColor: 'rgba(255, 99, 132, 0.2)', + borderColor: 'rgb(255, 99, 132)', + pointBackgroundColor: 'rgb(255, 99, 132)', + pointBorderColor: '#fff', + pointHoverBackgroundColor: '#fff', + pointHoverBorderColor: 'rgb(255, 99, 132)' + }] + }; + var options = { + elements: { + line: { + borderWidth: 3 + } + } + } + return [data, options]; + }, + // Used gridstack to drag and resize chart and tile. + gridstack_init: function (self) {// Used gridstack to drag and resize chart and tile. + self.$('.grid-stack').gridstack({ + animate: true, + duration: 200, + handle: '.grid-stack-item-content', + draggable: { + handle: '.grid-stack-item-content', + scroll: true + }, + resizable:{ + aspectRatio:20/18, + }, + alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent), + float: true + }); + self.gridstack_off(self); + }, + // Enable move and resize functionality + gridstack_on: function (self) { + var gridstack = self.$('.grid-stack').data('gridstack'); + gridstack.enableMove(true); + gridstack.enableResize(true); + }, + // Disable move and resize functionality + gridstack_off: function (self) { + var gridstack = self.$('.grid-stack').data('gridstack'); + gridstack.enableMove(false); + gridstack.enableResize(false); + }, + //Function for rendering dashboards + render_dashboards: function () { + self.$("#save_layout").hide();//Hide save_layout button + _.each(this.block_ids, function (block) { + if (block['type'] == 'tile') { + self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardTile', {widget: block})); + // Add the new tile to the Gridstack layout with correct position and size + var newTile = self.$('.o_dynamic_dashboard').children().last(); + // Check if the Gridstack element is initialized + var gridstack = self.$('.grid-stack').data('gridstack'); + if (gridstack) { + gridstack.addWidget(newTile, block.x, block.y, block.width, block.height, block.autoPosition); + } + } else { + // Block type = 'chart' + self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardChart', {widget: block})); + if (!('x_axis' in block)) { + return false; + } + var type = block['graph_type']; + var chart_type = 'self.get_values_' + `${type}(block)`; + // Set up and render the chart using Chart.js + var newChartContainer = self.$('.o_dynamic_dashboard').children().last(); + new Chart(self.$('.chart_graphs').last(), { + type: block['graph_type'], + data: eval(chart_type)[0], + options: eval(chart_type)[1] + }); + // Check if the Gridstack element is initialized + var gridstack = self.$('.grid-stack').data('gridstack'); + if (gridstack) { + // Add the new chart container to the Gridstack layout at the original position + gridstack.addWidget(newChartContainer, block.x, block.y, block.width, block.height, block.autoPosition); + } + } + }); + // Toggling dropdown for exporting, clicked item, closing all others + // When clicked on one, also when mouse leaves parent. + self.$(".block_export").on({ + click: function () {//Show the export dropdown. + if ($(this).next(".dropdown-export").is(':visible')) { + $(this).next(".dropdown-export").hide(); + } else { + $(this).next('.dropdown-export').hide(); + $(this).next(".dropdown-export").show(); + } + } + }); + //Function to hide dropdown-export list while mouse leave the block. + self.$(".grid-stack-item").on({ + mouseleave: function () { + self.$('.dropdown-export').hide(); + } + }); + //Function to hide dropdown-addblock list if mouse leave dropdown + //list. + self.$(".dropdown-addblock").on({ + mouseleave: function () { + self.$(".dropdown-addblock").hide(); + } + }); + self.gridstack_init(self); + if (localStorage.getItem("toggleState") == 'true') { + self.$(".toggle").prop('checked', true) + $(self.el.parentElement).addClass('dark-theme'); + self.$(".theme_icon").removeClass('bi-moon-stars-fill'); + self.$(".theme_icon").addClass('bi-sun-fill'); + self.$(".dropdown-export").addClass('dropdown-menu-dark'); + } else { + $(self.el.parentElement).removeClass('dark-theme'); + self.$(".theme_icon").removeClass('bi-sun-fill'); + self.$(".theme_icon").addClass('bi-moon-stars-fill'); + self.$(".dropdown-export").removeClass('dropdown-menu-dark'); + } + }, + //Function to toggle the navbar. + navbar_toggle: function () { + this.$('.navbar-collapse').toggle(); + }, + //Function to export chart into jpg, png or csv formate. + export_item: function (e) { + var type = $(e.currentTarget).attr('data-type'); + var canvas = $(e.currentTarget).closest('.export_option').siblings('.row').find('#canvas')[0]; + var dataTitle = canvas.getAttribute("data-title"); + // Create a new canvas with a white background + var bgCanvas = document.createElement("canvas"); + bgCanvas.width = canvas.width; + bgCanvas.height = canvas.height; + var bgCtx = bgCanvas.getContext("2d"); + bgCtx.fillStyle = "white"; + bgCtx.fillRect(0, 0, canvas.width, canvas.height); + // Draw the chart onto the new canvas + bgCtx.drawImage(canvas, 0, 0); + // Export the new canvas as an image + var imgData = bgCanvas.toDataURL("image/png"); + if (type === 'png') { + this.$el.find('.chart_png_export').attr({ + href: imgData, + download: `${dataTitle}.png` + }); + } + if (type === 'pdf') { + var pdf = new jsPDF(); + pdf.addImage(bgCanvas.toDataURL("image/png"), 'PNG', 0, 0); + pdf.save(`${dataTitle}.pdf`); + } + if (type === 'csv') { + var rows = []; + // Check if the id inside the object is equal to this id + for (var obj of this.block_ids) { + if (obj.id == $(e.currentTarget).attr('data-id')) { + rows.push(obj.x_axis); + rows.push(obj.y_axis); + } + } + let csvContent = "data:text/csv;charset=utf-8,"; + rows.forEach(function (rowArray) { + let row = rowArray.join(","); + csvContent += row + "\r\n"; + }); + var link = document.createElement("a"); + link.setAttribute("href", encodeURI(csvContent)); + link.setAttribute("download", `${dataTitle}.csv`); + document.body.appendChild(link); // Required for FF + link.click(); + } + }, + //Function to toggle the button Add Items. + dropdown_toggle: function () { + this.$el.find('.dropdown-addblock').show(); + }, + //Function return all block in exact position. + on_reverse_breadcrumb: function () { + this.fetch_data().then(function () {//Fetch all datas + self.render_dashboards(); + self.gridstack_init(self); + location.reload(); + }); + }, + // Fetch search input value and filter the chart and tile. + search_chart: function (e) { + e.stopPropagation(); + var self = this; + // Hide certain elements + self.$(this).next("#theme-change-icon").hide(); + self.$("#edit_layout").hide(); + self.$("#save_layout").hide(); + self.$(".date-inputs").hide(); + // Clear existing Gridstack layout + self.$('.grid-stack').data('gridstack').removeAll(); + // Empty the dynamic dashboard container + self.$('.o_dynamic_dashboard').empty(); + // Fetch filtered data using Ajax + ajax.jsonRpc("/custom_dashboard/search_input_chart", 'call', { + 'search_input': self.$("#search-input-chart").val() + }).then(function (res) { + // Iterate through block_ids + _.each(self.block_ids, function (block) { + if (res.includes(block['id'])) { + // Check block type and render accordingly + if (block['type'] == 'tile') { + self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardTile', {widget: block})); + // Add the new tile to the Gridstack layout + var newTile = self.$('.o_dynamic_dashboard').children().last(); + self.$('.grid-stack').data('gridstack').addWidget(newTile, block.x, block.y, block.width, block.height, block.autoPosition); + } else { // Block type = 'chart' + self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardChart', {widget: block})); + // Check if 'x_axis' is present in block + if (!('x_axis' in block)) { + return false; + } + // Set up and render the chart using Chart.js + var type = block['graph_type']; + var newChartContainer = self.$('.o_dynamic_dashboard').children().last(); + var chart_type = 'self.get_values_' + `${block['graph_type']}(block)` + new Chart(self.$('.chart_graphs').last(), { + type: block['graph_type'], + data: eval(chart_type)[0], + options: eval(chart_type)[1] + }); + // Add the new chart container to the Gridstack layout at the original position + self.$('.grid-stack').data('gridstack').addWidget(newChartContainer, block.x, block.y, block.width, block.height, block.autoPosition); + } + } + }); + }); + // Initialize Gridstack + self.gridstack_init(self); + }, + //Function to clear search box and call the functon on_reverse_breadcrumb(). + clear_search: function () { + self.$("#search-input-chart").val(""); + self.$("#theme-change-icon").show(); + self.$("#edit_layout").show(); + self.$("#save_layout").hide(); + self.$(".date-inputs").show(); + self.block_ids = []; + self.on_reverse_breadcrumb(); + }, + //Function to edit blocks and redirect to the model dashboard.block + _onClick_block_setting: function (event) { + event.stopPropagation(); + this.do_action({ + type: 'ir.actions.act_window', + res_model: 'dashboard.block', + view_mode: 'form', + res_id: parseInt($(event.currentTarget).closest('.block').attr('data-id')), + views: [[false, 'form']], + context: {'form_view_initial_mode': 'edit'}, + }, {on_reverse_breadcrumb: self.on_reverse_breadcrumb}) + }, + //While click on cross icon, the block will be deleted. + _onClick_block_delete: function (event) { + event.stopPropagation(); + bootbox.confirm({//Popup to conform delete + message: "Are you sure you want to delete this item?", + title: "Delete confirmation", + buttons: { + cancel: { + label: 'NO, GO BACK', + className: 'btn-primary' + }, + confirm: { + label: 'YES, I\'M SURE', + className: 'btn-danger' + } + }, + //Function to unlink block + callback: function (result) { + if (result) { + rpc.query({ + model: 'dashboard.block', + method: 'unlink', + args: [parseInt($(event.currentTarget).closest('.block').attr('data-id'))], // ID of the record to unlink + }).then(function (result) { + location.reload() + self.on_reverse_breadcrumb(); + }).catch(function (error) { + }); + } else { + // Do nothing + } + } + }); + }, + // Method for converting to camel case + convertToCamelCase: function (chartType) { + switch (chartType) { + case "bar": + return "Bar"; + case "radar": + return "Radar"; + case "pie": + return "Pie"; + case "line": + return "Line"; + case "doughnut": + return "Doughnut"; + default: + // If the chart type is not recognized, you can handle it accordingly + return chartType; + } + }, + //Fetch data and create chart or tile + _onClick_add_block: function (e) { + var type = $(e.currentTarget).attr('data-type'); + if (type == 'graph') { + var chart_type = $(e.currentTarget).attr('data-chart_type'); + } + if (type === 'tile') { + var randomColor = '#' + ('000000' + Math.floor(Math.random() * 16777216).toString(16)).slice(-6); + this.do_action({// Redirect to dashboard.block + type: 'ir.actions.act_window', + res_model: 'dashboard.block', + view_mode: 'form', + views: [[false, 'form']], + context: { + 'form_view_initial_mode': 'edit', + 'default_name': 'New Tile', + 'default_type': type, + 'default_height': 2, + 'default_width': 2, + 'default_tile_color': randomColor, + 'default_text_color': '#FFFFFF', + 'default_fa_icon': 'fa fa-bar-chart', + 'default_client_action_id': parseInt(self.action_id) + }, + on_close: function () { + window.location.reload(); + } + }); + } else { + this.do_action({ + type: 'ir.actions.act_window', + res_model: 'dashboard.block', + view_mode: 'form', + views: [[false, 'form']], + context: { + 'form_view_initial_mode': 'edit', + 'default_name': 'New ' + self.convertToCamelCase(chart_type), + 'default_type': type, + 'default_height': 5, + 'default_width': 4, + 'default_graph_type': chart_type, + 'default_graph_size': 'col-lg-4', + 'default_fa_icon': 'fa fa-bar-chart', + 'default_client_action_id': parseInt(self.action_id) + }, + on_close: function(){ + window.location.reload(); + } + }); + } + // Fetching saved layout from localstorage memory. + }, + // Function to hide edit_layout button and show save_layout button. and also work the function gridstack_on(self) + _onClick_edit_layout: function (e) { + e.stopPropagation(); + self.$(".date-inputs").hide(); + self.$("#edit_layout").hide(); + self.$("#save_layout").show(); + self.gridstack_on(self); + }, + //Function to save the edited value + _onClick_save_layout: function (e) { + e.stopPropagation(); + self.$(".date-inputs").show(); + self.$("#edit_layout").show(); + self.$("#save_layout").hide(); + var grid_data_list = []; + this.$el.find('.grid-stack-item').each(function () { + grid_data_list.push({ + 'id': $(this).data('id'), + 'x': $(this).data('gs-x'), + 'y': $(this).data('gs-y'), + 'width': $(this).data('gs-width'), + 'height': $(this).data('gs-height') + }) + }); + this._rpc({ + model: 'dashboard.block', + method: 'get_save_layout', + args: [[], this.action_id, grid_data_list] + }); + self.gridstack_off(self); + }, + // Function to view the tree view of the tile. + _onClick_tile: function (e) { + e.stopPropagation(); + ajax.jsonRpc('/tile/details', 'call', { + 'id': $(e.currentTarget).attr('data-id') + }).then(function (result) { + if (result['model_name']) { + self.do_action({ + name: result['model_name'], + type: 'ir.actions.act_window', + res_model: result['model'], + view_mode: 'tree,form', + views: [[false, 'list'], [false, 'form']], + domain: result['filter'] + }); + } else { + Dialog.alert(this, "Configure the tile's model and parameters."); + } + }); + }, + }); + core.action_registry.add('advanced_dynamic_dashboard', DynamicDashboard); + return DynamicDashboard; +}); diff --git a/advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss b/advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss new file mode 100644 index 000000000..f5133f7a0 --- /dev/null +++ b/advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss @@ -0,0 +1,171 @@ + +:root { + /* Colors */ + --green: #00C689; + --blue: #3DA5F4; + --red: #F1536E; + --yellow: #FDA006; + /*Fonts*/ + --primary-font: 'Roboto', sans-serif; +} + +html .o_web_client > .o_action_manager { + overflow: auto; +} + +.bg-green { + background-color: var(--green); +} + +.bg-blue { + background-color: var(--blue); +} + +.bg-red { + background-color: var(--red); +} + +.bg-yellow { + background-color: var(--yellow); +} + +.text-color-yellow { + color: var(--yellow); +} + +.text-color-green { + color: var(--green); +} + +.text-color-blue { + color: var(--blue); +} + +.text-color-red { + color: var(--red); +} + +.text-color-yellow { + color: var(--yellow); +} + +.tile-container__icon-container { + border-radius: 50%; + width: 4.75rem; + height: 4.75rem; + font-size: 28px; +} + +.tile-container__status-container { + margin-left: 2em; +} + +.status-container__title { + font-family: var(--primary-font); + font-weight: 500; + font-size: 1.5rem; + line-height: 1.5rem; +} + +.status-container__figures { + font-family: var(--primary-font); +} + +.status-container__figures > h3 { + font-weight: 700; + font-size: 1.5rem; + line-height: 1.813rem; +} + +.tile-container__setting-icon { + top: 0.638rem; + right: 1rem; +} + + .dark-theme { + /* Add dark theme styles here */ + .block_edit { + color: #b7b7b7 !important; + } + + .navbar { + padding: 1.2rem 0 2.6rem 0 !important; + border-bottom: 1px solid #3f3f3f1a !important; + } + + .theme_icon:hover { + text-shadow: 0px 0px 5px #9388ff; + } +.add_block{ + color: #dfdfdf; +} + #ExportMenu { + color: #626262; + } + + .dropdown-export { + background-color: #2a2a2a; + color: #dfdfdf; + } + + .chart_title { + color: #dfdfdf; + margin: -0.5em 0 2em 0; + } + + .btn-search_edit, { + color: #313131; + border: none; + background-color: #979797 !important; + } + + #search-input-chart { + color: #ffffff; + border: 1px solid #4e4e4e; + background-color: #2A2A2A !important; + } + + #search-clear { + color: #1f1f1f !important; + } + + div.navbar { + color: #909090; + background-color: #2A2A2A !important; + } + + .navbar-collapse { + margin-bottom: 12px !important; + } + + h3 { + color: #909090; + } + + div.dropdown-addblock { + color: #909090; + background-color: #2A2A2A !important; + } + + #dropdownMenuButton { + color: #313131; + background-color: #979797 !important; + } + + div.card-body { + border-radius: 0.5em !important; + background-color: #2a2a2a !important; + } + + .o_kanban_renderer { + background-color: #e8e8e8 !important; + } + + background-color: #1C1B1B; + @media (max-width: 767px) { + .navbar-light .navbar-toggler { + color: #A7A7A72D; + border-color: #F6F6F621; + } + } +} diff --git a/advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml b/advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml new file mode 100644 index 000000000..c38c5c5ca --- /dev/null +++ b/advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml @@ -0,0 +1,196 @@ + + + + +
+ +
+
+
+
+ + +
+
+
+ + + + + + +
+
+
+ +
+
+

+ +

+
+

+ +

+
+
+
+
+
+
+ + +
+
+
+
+ +
+ +
+ +
+

+ +

+
+
+ +
+
+
+
+
+
+
diff --git a/advanced_dynamic_dashboard/views/dashboard_menu_views.xml b/advanced_dynamic_dashboard/views/dashboard_menu_views.xml new file mode 100644 index 000000000..dd3a4d0a0 --- /dev/null +++ b/advanced_dynamic_dashboard/views/dashboard_menu_views.xml @@ -0,0 +1,63 @@ + + + + + dashboard.menu.view.kanban + dashboard.menu + + + + + +
+

+ Name: + +

+
+
+
+ Parent: +
+
+ +
+
+
+
+
+
+
+
+ + + dashboard.menu.view.form + dashboard.menu + +
+ + + + + + + + + + +
+
+
+ + + Dashboards Menu + ir.actions.act_window + dashboard.menu + kanban,form + + + +
diff --git a/advanced_dynamic_dashboard/views/dashboard_views.xml b/advanced_dynamic_dashboard/views/dashboard_views.xml new file mode 100644 index 000000000..a64ed22c7 --- /dev/null +++ b/advanced_dynamic_dashboard/views/dashboard_views.xml @@ -0,0 +1,13 @@ + + + + + Dashboard + advanced_dynamic_dashboard + + + + diff --git a/advanced_dynamic_dashboard/views/dynamic_block_views.xml b/advanced_dynamic_dashboard/views/dynamic_block_views.xml new file mode 100644 index 000000000..9e11f2689 --- /dev/null +++ b/advanced_dynamic_dashboard/views/dynamic_block_views.xml @@ -0,0 +1,74 @@ + + + + + dashboard.block.view.form + dashboard.block + +
+ + + +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + dashboard.block.view.tree + dashboard.block + + + + + + + + +
diff --git a/advanced_dynamic_dashboard/views/dynamic_dashboard_views.xml b/advanced_dynamic_dashboard/views/dynamic_dashboard_views.xml new file mode 100644 index 000000000..2ff642126 --- /dev/null +++ b/advanced_dynamic_dashboard/views/dynamic_dashboard_views.xml @@ -0,0 +1,30 @@ + + +