Browse Source

Apr 23 [ADD] : Initial Commit 'advanced_dynamic_dashboard'

pull/164/merge
AjmalCybro 1 year ago
parent
commit
b92b82fe15
  1. 46
      advanced_dynamic_dashboard/README.rst
  2. 23
      advanced_dynamic_dashboard/__init__.py
  3. 50
      advanced_dynamic_dashboard/__manifest__.py
  4. 22
      advanced_dynamic_dashboard/controllers/__init__.py
  5. 45
      advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py
  6. 6
      advanced_dynamic_dashboard/doc/RELEASE_NOTES.md
  7. 24
      advanced_dynamic_dashboard/models/__init__.py
  8. 184
      advanced_dynamic_dashboard/models/dashboard_block.py
  9. 79
      advanced_dynamic_dashboard/models/dashboard_menu.py
  10. 60
      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/cogs.png
  14. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/consultation.png
  15. 1
      advanced_dynamic_dashboard/static/description/assets/icons/down.svg
  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/faq.png
  19. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/feature.png
  20. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/hotel-black.png
  21. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/license.png
  22. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/lifebuoy.png
  23. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/manufacturing-black.png
  24. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/pos-black.png
  25. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/puzzle.png
  26. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/restaurant-black.png
  27. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/screenshot.png
  28. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/service-black.png
  29. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/support.png
  30. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/test-2.png
  31. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/trading-black.png
  32. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/training.png
  33. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/update.png
  34. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/user.png
  35. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/video.png
  36. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/whatsapp.png
  37. BIN
      advanced_dynamic_dashboard/static/description/assets/icons/wrench.png
  38. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/categories.png
  39. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/check-box.png
  40. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/compass.png
  41. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/corporate.png
  42. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/customer-support.png
  43. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/cybrosys-logo.png
  44. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/features.png
  45. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/logo.png
  46. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/pictures.png
  47. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/pie-chart.png
  48. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/right-arrow.png
  49. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/star.png
  50. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/support.png
  51. BIN
      advanced_dynamic_dashboard/static/description/assets/misc/whatsapp.png
  52. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/1.png
  53. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/2.png
  54. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/3.gif
  55. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/3.png
  56. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/4.png
  57. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/5.png
  58. BIN
      advanced_dynamic_dashboard/static/description/assets/modules/6.png
  59. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/1.png
  60. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/10.png
  61. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/11.png
  62. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/12.png
  63. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/13.png
  64. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/2.png
  65. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/3.png
  66. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/4.png
  67. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/5.png
  68. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/6.png
  69. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/7.png
  70. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/8.png
  71. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/9.png
  72. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/hero.gif
  73. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s15.png
  74. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s17.png
  75. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s18.png
  76. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s19.png
  77. BIN
      advanced_dynamic_dashboard/static/description/assets/screenshots/s20.png
  78. BIN
      advanced_dynamic_dashboard/static/description/banner.png
  79. BIN
      advanced_dynamic_dashboard/static/description/icon.png
  80. 714
      advanced_dynamic_dashboard/static/description/index.html
  81. 1
      advanced_dynamic_dashboard/static/lib/css/gridstack.min.css
  82. 365
      advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css
  83. 598
      advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js
  84. 171
      advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss
  85. 196
      advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml
  86. 63
      advanced_dynamic_dashboard/views/dashboard_menu_views.xml
  87. 13
      advanced_dynamic_dashboard/views/dashboard_views.xml
  88. 74
      advanced_dynamic_dashboard/views/dynamic_block_views.xml
  89. 30
      advanced_dynamic_dashboard/views/dynamic_dashboard_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
-------
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: (V14) Unnimaya C O, Contact : odoo@cybrosys.com
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <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) 2024-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

50
advanced_dynamic_dashboard/__manifest__.py

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-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': '14.0.1.0.0',
'category': 'Productivity',
'summary': """Helps to create configurable dashboards easily.""",
'description': """This module helps to create configurable advanced dynamic
dashboard to get the information that are relevant to your business,
department or a specific process or need.""",
'author': 'Cybrosys Techno Solutions',
'website': "https://www.cybrosys.com",
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'depends': ['web'],
'data': [
'security/ir.model.access.csv',
'views/dashboard_views.xml',
'views/dynamic_block_views.xml',
'views/dashboard_menu_views.xml',
'views/dynamic_dashboard_views.xml'
],
'qweb': [
'static/src/xml/dynamic_dashboard_template.xml',
],
'images': ['static/description/banner.png'],
'license': "AGPL-3",
'installable': True,
'auto_install': False,
'application': True,
}

22
advanced_dynamic_dashboard/controllers/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-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

45
advanced_dynamic_dashboard/controllers/advanced_dynamic_dashboard.py

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<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}
else:
return False
@http.route('/custom_dashboard/search_input_chart', type='json',
auth="public", website=True)
def dashboard_search_input_chart(self, search_input):
"""Function to filter search input in dashboard"""
return request.env['dashboard.block'].search([
('name', 'ilike', search_input)]).ids

6
advanced_dynamic_dashboard/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <advanced_dynamic_dashboard>
#### 05.02.2024
#### Version 14.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) 2024-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

184
advanced_dynamic_dashboard/models/dashboard_block.py

@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-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):
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) 2024-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()

60
advanced_dynamic_dashboard/models/models.py

@ -0,0 +1,60 @@
# -*- coding: utf-8 -*-
################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-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/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

1
advanced_dynamic_dashboard/static/description/assets/icons/down.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svgjs="http://svgjs.com/svgjs" width="512" height="512" x="0" y="0" viewBox="0 0 24 24" style="enable-background:new 0 0 512 512" xml:space="preserve" class=""><g><g id="Layer_2" data-name="Layer 2"><path d="m12 1a11 11 0 1 0 11 11 11.013 11.013 0 0 0 -11-11zm5.707 9.707-5 5a1 1 0 0 1 -1.414 0l-5-5a1 1 0 0 1 1.414-1.414l4.293 4.293 4.293-4.293a1 1 0 0 1 1.414 1.414z" fill="#781d96" data-original="#000000" class=""></path></g></g></svg>

After

Width:  |  Height:  |  Size: 542 B

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/faq.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

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/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/screenshot.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

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/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/icons/test-2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

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/video.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

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/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
advanced_dynamic_dashboard/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

BIN
advanced_dynamic_dashboard/static/description/assets/modules/3.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 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.1 KiB

714
advanced_dynamic_dashboard/static/description/index.html

@ -0,0 +1,714 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42"
style="width: 42px; height: 42px;"/>
<div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Advanced Dynamic Dashboard
</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">
Facilitates the Seamless Creation of Customizable
Dashboards.</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Overview
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
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.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Features
</h2>
</div>
<div class="row"
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Effortlessly generate interactive Charts and Tiles.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Available Dark mode and Light mode.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Feasible to establish a Dashboard Menu in any
model.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Charts can be exported as Images, PDFs, and CSVs.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Enable dragging and resizing of Charts and Tiles for
flexible layouts.</span>
</div>
<div class="d-flex align-items-center"
style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span
style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Edit and configure Charts and Tiles</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"
id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Click ADD ITEMS to add Graphs and Tiles to the Dashboard.
</h3>
<img src="assets/screenshots/1.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Add required details for creating a Tile.
</h3>
<img src="assets/screenshots/2.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
New Tiles on the dashboard.
</h3>
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Create new Chart.
</h3>
<img src="assets/screenshots/4.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Charts added to the dashboard.
</h3>
<img src="assets/screenshots/5.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Dashboard based on the date filter.
</h3>
<img src="assets/screenshots/6.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
It is possible to Search the name of chart or tile.
</h3>
<img src="assets/screenshots/7.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Click the marked button for enabling Dark Mode.
</h3>
<img src="assets/screenshots/8.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Dashboard in Dark Mode.
</h3>
<img src="assets/screenshots/9.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Click EDIT LAYOUT for editing the dashboard layout.
</h3>
<img src="assets/screenshots/s15.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
It is possible to change size of chart and tile by clicking the
marked icon, also we can drag them to any position.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
</p>
<img src="assets/screenshots/s17.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Click on the 3 dots icon for exporting the graphs.
</h3>
<img src="assets/screenshots/s18.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Graph exported as image.
</h3>
<img src="assets/screenshots/s19.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Graph exported as pdf.
</h3>
<img src="assets/screenshots/s20.png" class="img-thumbnail">
</div> <div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Navigate to Dashboards menu to add the dashboard menu under any
menu.
</h3>
<img src="assets/screenshots/10.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
Choose the menu name and parent menu.
</h3>
<img src="assets/screenshots/11.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
New menu added in Inventory module.
</h3>
<img src="assets/screenshots/12.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">
We can create new dashboard here.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">
</p>
<img src="assets/screenshots/13.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/project_dashboard_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/1.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/14.0/pdf_report_with_sign/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/2.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/14.0/magic_note/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/3.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active"
style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/odoo11_magento2/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/4.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/14.0/custom_gantt_view/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/5.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/14.0/odoo_dynamic_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="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="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 RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<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>
</div>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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: 0px; 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>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

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>

30
advanced_dynamic_dashboard/views/dynamic_dashboard_views.xml

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="assets_backend" name="advanced dynamic dashboard assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet"
href="advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css"/>
<link rel="stylesheet"
href='advanced_dynamic_dashboard/static/lib/css/gridstack.min.css'/>
<link rel="stylesheet"
href='advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss'/>
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css"/>
<script type="text/javascript"
src="/advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js"/>
<script type="text/javascript"
src='https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.2.6/gridstack.min.js'/>
<script type="text/javascript"
src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js'/>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js"/>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"/>
<script type="text/javascript"
src='https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js'/>
<script type="text/javascript"
src='https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js'/>
</xpath>
</template>
</odoo>
Loading…
Cancel
Save