Browse Source

Jan 08 : [ADD] Initial Commit 'advanced_dynamic_dashboard'

pull/254/merge
RisvanaCybro 1 year ago
parent
commit
7c925e29e4
  1. 46
      advanced_dynamic_dashboard/README.rst
  2. 23
      advanced_dynamic_dashboard/__init__.py
  3. 65
      advanced_dynamic_dashboard/__manifest__.py
  4. 22
      advanced_dynamic_dashboard/controllers/__init__.py
  5. 44
      advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py
  6. 7
      advanced_dynamic_dashboard/doc/RELEASE_NOTES.md
  7. 24
      advanced_dynamic_dashboard/models/__init__.py
  8. 185
      advanced_dynamic_dashboard/models/dashboard_block.py
  9. 79
      advanced_dynamic_dashboard/models/dashboard_menu.py
  10. 59
      advanced_dynamic_dashboard/models/models.py
  11. 3
      advanced_dynamic_dashboard/security/ir.model.access.csv
  12. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/check.png
  13. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/chevron.png
  14. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/cogs.png
  15. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/consultation.png
  16. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/ecom-black.png
  17. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/education-black.png
  18. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png
  19. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/license.png
  20. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png
  21. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/logo.png
  22. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png
  23. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png
  24. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png
  25. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png
  26. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/service-black.png
  27. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png
  28. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/training.png
  29. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/update.png
  30. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/user.png
  31. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/wrench.png
  32. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/dash.png
  33. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/l2.png
  34. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/multi_product.png
  35. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/shopify.png
  36. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/systray.png
  37. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/woocomp_connector.png
  38. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/1.png
  39. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/10.png
  40. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/11.png
  41. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/12.png
  42. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/13.png
  43. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/14.png
  44. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/2.png
  45. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/3.png
  46. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/4.png
  47. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/5.png
  48. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/6.png
  49. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/8.png
  50. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/9.png
  51. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif
  52. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png
  53. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png
  54. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png
  55. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png
  56. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png
  57. BIN
      advanced_dynamic_dashboard/static/description/banner.png
  58. BIN
      advanced_dynamic_dashboard/static/description/icon.png
  59. 735
      advanced_dynamic_dashboard/static/description/index.html
  60. 1
      advanced_dynamic_dashboard/static/lib/css/gridstack.min.css
  61. 365
      advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css
  62. 598
      advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js
  63. 171
      advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss
  64. 196
      advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml
  65. 63
      advanced_dynamic_dashboard/views/dashboard_menu_views.xml
  66. 13
      advanced_dynamic_dashboard/views/dashboard_views.xml
  67. 74
      advanced_dynamic_dashboard/views/dynamic_block_views.xml

46
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
-------
Affero General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
Developer: (V15) 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 <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

23
advanced_dynamic_dashboard/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
from . import controllers
from . import models

65
advanced_dynamic_dashboard/__manifest__.py

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
{
'name': "Advanced Dynamic Dashboard",
'version': '15.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',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'depends': ['web'],
'data': [
'security/ir.model.access.csv',
'views/dashboard_views.xml',
'views/dynamic_block_views.xml',
'views/dashboard_menu_views.xml',
],
'assets': {
'web.assets_backend': [
'advanced_dynamic_dashboard/static/lib/css/gridstack.min.css',
'advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css',
'advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss',
"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css",
'https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.2.6/gridstack.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js',
"https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js",
"https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js",
'https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js',
'advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js',
'https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700'
],
'web.assets_qweb': [
'advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml',
],
},
'images': ['static/description/banner.png'],
'license': "AGPL-3",
'installable': True,
'auto_install': False,
'application': True,
}

22
advanced_dynamic_dashboard/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
from . import advanced_dynamic_dashboard

44
advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py

@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
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}
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

7
advanced_dynamic_dashboard/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <advanced_dynamic_dashboard>
#### 21.12.2023
#### Version 15.0.1.0.0
#### ADD
- Initial commit for Advanced Dynamic Dashboard

24
advanced_dynamic_dashboard/models/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
from . import dashboard_block
from . import dashboard_menu
from . import models

185
advanced_dynamic_dashboard/models/dashboard_block.py

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
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):
"""Method to work when the value in the field model_id changes"""
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']),
})

79
advanced_dynamic_dashboard/models/dashboard_menu.py

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
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()

59
advanced_dynamic_dashboard/models/models.py

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
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

3
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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_dashboard_block_user access.dashboard.block.user model_dashboard_block base.group_user 1 1 1 1
3 access_dashboard_menu_user access.dashboard.menu.user model_dashboard_menu base.group_user 1 1 1 1

BIN
advanced_dynamic_dashboard/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
advanced_dynamic_dashboard/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/dash.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/l2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/multi_product.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/shopify.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/systray.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/woocomp_connector.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
advanced_dynamic_dashboard/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
advanced_dynamic_dashboard/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

735
advanced_dynamic_dashboard/static/description/index.html

@ -0,0 +1,735 @@
<div class="container"
style="padding: 1rem !important; margin-bottom: 1rem !important;">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between"
style="border-bottom: 1px solid #d5d5d5;">
<div class="my-3">
<img src="./assets/icons/logo.png"
style="width: auto !important; height: 40px !important;">
</div>
<div class="my-3 d-flex align-items-center">
<div
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
</div>
</div>
<div class="container" style="padding: 0rem 1.5rem 4rem !important">
<div class="row" style="height: 900px !important;">
<div class="col-sm-12 col-md-12 col-lg-12"
style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;">
<h1
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important; font-size: 3.5rem !important; text-align: center !important;">
Advanced Dynamic Dashboard</h1>
<p
style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important; font-size: 1.4rem !important; text-align: center !important;">
Facilitates the Seamless Creation of Customizable Dashboards.
</p>
<img src="./assets/screenshots/hero.gif" class="img-responsive"
width="100%" height="auto"/>
</div>
</div>
<div class="row">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-compass mr-2"></i>Explore this module
</h2>
</div>
<div class="col-md-6">
<a href="#overview" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Overview</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
Learn more about this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#features" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Features</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
View features of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#screenshots" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Screenshots</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
See key screenshots of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
</div>
<div class="row" id="overview">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-pie-chart mr-2"></i>Overview
</h2>
</div>
<div class="col-mg-12 pl-3">
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;">
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.
</p>
</div>
</div>
<div class="row" id="features">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-star mr-2"></i>Features
</h2>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Effortlessly generate interactive Charts and Tiles.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Available Dark mode and Light mode</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Feasible to establish a Dashboard Menu in any
model.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Charts can be exported as Images, PDFs, and CSVs.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Enable dragging and resizing of Charts and Tiles for
flexible layouts.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Edit and configure Charts and Tiles</h4>
</div>
</div>
</div>
</div>
<div class="row" id="screenshots">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-image mr-2"></i>Screenshots
</h2>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Click ADD ITEMS to add Graphs and Tiles to the Dashboard.</h4>
<img src="assets/screenshots/1.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Add required details for creating a Tile</h4>
<img src="assets/screenshots/2.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
New Tiles on the dashboard.</h4>
<img src="assets/screenshots/3.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Create new Chart</h4>
<img src="assets/screenshots/4.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Charts added to the dashboard.</h4>
<img src="assets/screenshots/5.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Dashboard based on the date filter.
</h4>
<img src="assets/screenshots/6.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
It is possible to Search the name of chart or tile.</h4>
<img src="assets/screenshots/8.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Click the marked button for enabling Dark Mode.</h4>
<img src="assets/screenshots/9.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Dashboard in Dark Mode.</h4>
<img src="assets/screenshots/10.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Click EDIT LAYOUT for editing the dashboard layout.</h4>
<img src="assets/screenshots/s15.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
It is possible to change size of chart and tile by clicking the
marked icon, also we can drag them to any position.</h4>
<img src="assets/screenshots/s17.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Click on the 3 dots icon for exporting the graphs.</h4>
<img src="assets/screenshots/s18.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Graph exported as image.</h4>
<img src="assets/screenshots/s19.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Graph exported as pdf.</h4>
<img src="assets/screenshots/s20.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Navigate to Dashboards menu to add the dashboard menu under any
menu.</h4>
<img src="assets/screenshots/11.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Choose the menu name and parent menu.</h4>
<img src="assets/screenshots/12.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
New menu added in Inventory module.</h4>
<img src="assets/screenshots/13.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
We can create new dashboard here.</h4>
<img src="assets/screenshots/14.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
</div>
<!-- SUGGESTED PRODUCTS -->
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center"
style="text-align: center; padding: 2.5rem 1rem !important;">
<h2 style="color: #212529 !important;">Suggested Products</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/project_dashboard_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/dash.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/agriculture_management_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/l2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/product_to_quotation/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/multi_product.png">
</div>
</a>
</div>
</div>
<div class="carousel-item" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/systray_world_clock/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/systray.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/shopify_odoo_connector/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/shopify.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/woo_commerce/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/woocomp_connector.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="left:-25px;width: 35px;color: #000;">
<span class="carousel-control-prev-icon"><i
class="fa fa-chevron-left"
style="font-size:24px"></i></span> </a>
<a class="carousel-control-next" href="#demo1" data-slide="next"
style="right:-25px;width: 35px;color: #000;">
<span class="carousel-control-next-icon"><i
class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF SUGGESTED PRODUCTS -->
<!-- OUR SERVICES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Services</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png"
class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive"
height="48px" width="48px">
</div>
<h6 class="text-center"
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</section>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Industries</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/trading-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/pos-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/education-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/manufacturing-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/ecom-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;">
<img src="./assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</section>
<!--END OF OUR INDUSTRIES -->
<!-- FOOTER -->
<!-- Footer Section -->
<section class="container" style="margin: 5rem auto 2rem;">
<div class="row" style="max-width:1540px;">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Need Help?</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</div>
</div>
<!-- Contact Cards -->
<div class="row d-flex justify-content-center align-items-center"
style="max-width:1540px; margin: 0 auto 2rem auto;">
<div class="col-lg-12"
style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; ">
<div class="row mt-4">
<div class="col-lg-6">
<a href="mailto:odoo@cybrosys.com" target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a>
</div>
<div class="col-lg-6">
<a href="https://api.whatsapp.com/send?phone=918606827707"
target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i
class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a>
</div>
</div>
</div>
</div>
<!-- End of Contact Cards -->
</section>
<!-- Footer -->
<section class="oe_container" style="padding: 2rem 3rem 1rem;">
<div class="row"
style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
<!-- Logo -->
<div class="col-lg-12 d-flex justify-content-center align-items-center"
style="margin-top: 3rem;">
<img src="https://www.cybrosys.com/images/logo.png"
width="200px" height="auto"/>
</div>
<!-- End of Logo -->
<div class="col-lg-12">
<hr
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;">
<!-- End of Footer Section -->
</div>
</div>
</section>
<!-- END OF FOOTER -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
crossorigin="anonymous"></script>

1
advanced_dynamic_dashboard/static/lib/css/gridstack.min.css

File diff suppressed because one or more lines are too long

365
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;
}
}

598
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('<span style="color: #d6e7ff" class="theme-text">⠀Light Mode</span>');
} else {
//Set text "Dark Mode"
this.$el.find('.theme_icon').after('<span style="color: #000000" class="theme-text">⠀Dark Mode</span>');
}
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;
});

171
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;
}
}
}

196
advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<!--Dashboard view with navigation bar and grid stack template-->
<t t-name="advanced_dynamic_dashboard">
<div class="container mx-auto">
<div class="navbar navbar-expand-md navbar-light bg-light mb-4 navbar-style border-bottom"
role="navigation">
<button class="navbar-toggler" id="dropdownNavbar" type="button"
data-toggle="collapse"
data-target="#navbarCollapse"
aria-controls="navbarCollapse" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"/>
</button>
<div class="collapse navbar-collapse"
aria-labelledby="dropdownNavbar">
<ul class="navbar-nav mr-auto">
<label class="navbar-items dropdown drop-down-add">
<button class="btn dropdown-add-items dropdown-toggle"
type="button" id="dropdownMenuButton"
data-toggle="dropdown" aria-haspopup="true"
aria-expanded="false">
<i class="bi bi-plus-circle-fill"/>
<span>⠀Add Items</span>
</button>
<div class="dropdown-menu dropdown-addblock"
aria-labelledby="dropdownMenuButton">
<a class="dropdown-item add_block"
data-type="tile">Tile</a>
<a class="dropdown-item add_block"
data-type="graph" data-chart_type="bar">Bar Chart</a>
<a class="dropdown-item add_block"
data-type="graph" data-chart_type="doughnut">Doughnut Chart</a>
<a class="dropdown-item add_block"
data-type="graph"
data-chart_type="line">Line Chart</a>
<a class="dropdown-item add_block"
data-type="graph" data-chart_type="pie">Pie Chart</a>
<a class="dropdown-item add_block"
data-type="graph"
data-chart_type="radar">Radar Chart</a>
</div>
</label>
<label class="navbar-items layout-switch"
id="edit-layout-label">
<button class="navbar-items btn-search_edit btn btn-primary my-2 mx-2 my-sm-0"
type="button"
id="edit_layout">Edit Layout</button>
<button class="navbar-items btn-search_edit btn btn-primary my-2 mx-2 my-sm-0"
type="button"
id="save_layout">Save Layout</button>
</label>
<label class="navbar-items toggle-btn"
id="theme-change-icon">
<input type="checkbox" class="toggle"
id="theme-toggle"/>
<i class="theme_icon bi bi-moon-stars-fill"/>
</label>
<div class="search-group" style="margin-right: 30px;">
<!-- Search Bar -->
<div class="navbar-items btn-group search-box">
<input class="form-control mr-sm-2" type="text"
placeholder="Search"
id="search-input-chart"
aria-label="Search"/>
<span id="searchclear">
<i class="fa fa-times search-clear"/>
</span>
</div>
<button class="navbar-items btn-search_edit btn btn-outline-primary my-2 my-sm-0 search-btn"
type="button"
id="search-button">Search</button>
</div>
<!-- Date Inputs -->
<div class="date-inputs navbar-items btn-group"
style="position: absolute; right: 50.5em;">
<label for="start-date"
style="color: black; margin-right: 5px;">Start Date:</label>
<input type="date" id="start-date" name="start-date"
style="color: black; border: 1px solid #4e4e4e; background-color: white; border-radius: 5px; margin-right: 10px;"/>
<label for="end-date"
style="color: black; margin-right:5px;">End Date:</label>
<input type="date" id="end-date" name="end-date"
style="color: black; border: 1px solid #4e4e4e; background-color: white; border-radius: 5px;"/>
</div>
</ul>
</div>
</div>
<div class="o_dynamic_dashboard row m-2 grid-stack"
name="gridstack">
</div>
</div>
</t>
<t t-name="DynamicDashboardTile">
<!--Tile building template-->
<div t-att-class="'grid-stack-item ' + widget.name"
t-att-data-gs-y="widget.y_pos"
t-att-data-gs-x="widget.x_pos" t-att-data-gs-width="widget.width"
t-att-data-gs-height="widget.height"
t-att-data-id="widget.id">
<div class="grid-stack-item-content tile block"
t-att-data-id="widget.id"
t-att-style="widget.color+widget.text_color">
<div t-att-style="widget.color+widget.text_color"
class="tile-container d-flex align-items-center w-100 my-3">
<a class="block_setting tile_edit tile-container__setting-icon">
<i class="fa fa-edit"/>
</a>
<a class="block_delete tile_edit tile-container__delete-icon">
<i class="fa fa-times"/>
</a>
<div>
</div>
<div t-att-style="widget.icon_color"
class="tile-container__icon-container bg-white d-flex justify-content-center align-items-center">
<i t-att-class="widget.icon"/>
</div>
<div t-att-style="widget.text_color"
class="tile-container__status-container">
<h2 t-att-style="widget.text_color"
class="status-container__title">
<t t-esc="widget.name"/>
</h2>
<div class="status-container__figures d-flex flex-wrap align-items-baseline">
<h3 class="mb-0 mb-md-1 mb-lg-0 mr-1"
t-att-style="widget.val_color">
<t t-esc="widget.value"/>
</h3>
</div>
</div>
</div>
</div>
</div>
</t>
<t t-name="DynamicDashboardChart">
<!-- Chart building template-->
<div t-att-class="'grid-stack-item ' + widget.name"
t-att-data-gs-x="widget.x_pos"
t-att-data-gs-y="widget.y_pos" t-att-data-gs-width="widget.width"
t-att-data-gs-height="widget.height"
t-att-data-id="widget.id">
<div class="grid-stack-item-content block card"
t-att-data-id="widget.id">
<div class="card-body mt-1" id="in_ex_body_hide">
<div class="block_edit block_setting">
<i title="Configuration"
class="fa fa-pencil block_setting chart-edit"/>
</div>
<div class="dropdown export_option">
<div class="block_edit fa fa-ellipsis-v block_export dropdown-toggle"
type="button"
id="ExportMenu" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
</div>
<div class="dropdown-menu dropdown-export"
aria-labelledby="ExportMenu">
<div class="m-2 chart_export_menu_header">
<span>Export</span>
</div>
<a class="dropdown-item chart_item_export chart_png_export"
data-type="png">
<i class="fa fa-file-image-o"/>
<span>Save as Image</span>
</a>
<button class="dropdown-item chart_pdf_export chart_item_export"
data-type="pdf">
<i class="fa fa-file-pdf-o"/>
<span>Save as PDF</span>
</button>
<button class="dropdown-item chart_csv_export chart_item_export"
data-type="csv"
t-att-data-id="widget.id">
<i class="fa fa-file-code-o"/>
<span>Export to CSV</span>
</button>
</div>
</div>
<div class="block_edit block_delete">
<i title="Delete"
class="fa fa-times block_delete chart-setting"/>
</div>
<h3 class="chart_title">
<t t-esc="widget.name"/>
</h3>
<div class="row">
<div class="col-md-12 chart_canvas" id="chart_canvas"
t-att-data-id="widget.id">
<canvas id="canvas" class="chart_graphs"
t-att-data-title="widget.name"/>
</div>
</div>
</div>
</div>
</div>
</t>
</templates>

63
advanced_dynamic_dashboard/views/dashboard_menu_views.xml

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Kanban view of the dashboard menu-->
<record id="dashboard_menu_view_kanban" model="ir.ui.view">
<field name="name">dashboard.menu.view.kanban</field>
<field name="model">dashboard.menu</field>
<field name="arch" type="xml">
<kanban>
<field name="name"/>
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_global_click">
<h3 class="my-2 ms-3">
Name:
<field name="name"/>
</h3>
<div class="row">
<hr class="mt4 mb4"/>
<div class="col-6 text-center">
<strong>Parent:</strong>
</div>
<div class="col-6 text-center">
<field name="menu_id"/>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<!--Form view of the dashboard menu-->
<record id="dashboard_menu_view_form" model="ir.ui.view">
<field name="name">dashboard.menu.view.form</field>
<field name="model">dashboard.menu</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<group>
<field name="name" class="oe_inline"/>
<field name="menu_id" class="oe_inline"/>
<field name="group_ids" widget="many2many_tags"
invisible="1"/>
<field name="client_action_id" invisible="1"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!-- Action specified for the dashboard menu-->
<record id="dashboard_menu_action" model="ir.actions.act_window">
<field name="name">Dashboards Menu</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">dashboard.menu</field>
<field name="view_mode">kanban,form</field>
</record>
<!-- Dashboards Menu-->
<menuitem id="dashboard_menu_menu" name="Dashboards"
parent="advanced_dynamic_dashboard.dashboard_menu_root"
sequence="0" action="dashboard_menu_action"/>
</odoo>

13
advanced_dynamic_dashboard/views/dashboard_views.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- The client action record to view the Dashboard-->
<record id="dashboard_menu_root_action" model="ir.actions.client">
<field name="name">Dashboard</field>
<field name="tag">advanced_dynamic_dashboard</field>
</record>
<!-- Dynamic Dashboards menu-->
<menuitem id="dashboard_menu_root" name="Dynamic Dashboards"
action="dashboard_menu_root_action"
web_icon="advanced_dynamic_dashboard,static/description/icon.png"
sequence="-1"/>
</odoo>

74
advanced_dynamic_dashboard/views/dynamic_block_views.xml

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Form view of the dashboard block-->
<record id="dashboard_block_view_form" model="ir.ui.view">
<field name="name">dashboard.block.view.form</field>
<field name="model">dashboard.block</field>
<field name="arch" type="xml">
<form>
<sheet>
<group>
<group>
<div>
<field name="name" class="oe_inline"
style="font-size: 30px;"
placeholder="Block Name" required="1"/>
</div>
</group>
</group>
<group>
<group>
<field name="model_id"
attrs="{'required':[('edit_mode','=', True)]}"/>
<field name="client_action_id" invisible="1"/>
<field name="model_name" invisible="1"/>
<field name="edit_mode" invisible="1"/>
<field name="operation"
attrs="{'required':[('edit_mode','=', True)]}"/>
<field name="measured_field_id" required="1"
domain="[('model_id','=',model_id), ('ttype','in',['float','integer','monetary']), ('store', '=', True)]"
attrs="{'required':[('edit_mode','=', True)]}"/>
<field name="filter" widget="domain"
options="{'model': 'model_name'}"/>
</group>
</group>
<group string="Block Information">
<group>
<field name="type" required="1"/>
<field name="graph_type"
attrs="{'invisible': [('type','!=', 'graph')]}"/>
<field name="graph_size"
attrs="{'invisible': [('type','!=', 'graph')]}"/>
<field name="fa_icon"
attrs="{'invisible': [('type','!=', 'tile')]}"/>
<field name="group_by_id"
attrs="{'invisible': [('type','!=', 'graph')], 'required':[('type','=','graph')]}"
domain="[('model_id','=',model_id),('relation','!=','res.users'), ('ttype','not in',['one2many','many2many']), ('store', '=', True)]"/>
<field name="tile_color"
attrs="{'invisible': [('type','!=', 'tile')]}"
widget="color" class="mb-4 o_im_livechat_field_widget_color"/>
<field name="val_color"
attrs="{'invisible': [('type','!=', 'tile')]}"
widget="color"/>
<field name="text_color"
attrs="{'invisible': [('type','!=', 'tile')]}"
widget="color"/>
</group>
</group>
</sheet>
</form>
</field>
</record>
<!--Tree view of the dashboard block-->
<record id="dashboard_block_view_tree" model="ir.ui.view">
<field name="name">dashboard.block.view.tree</field>
<field name="model">dashboard.block</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="model_id"/>
<field name="type"/>
</tree>
</field>
</record>
</odoo>
Loading…
Cancel
Save