@ -0,0 +1,46 @@ |
|||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Advanced Dynamic Dashboard |
|||
========================== |
|||
* Helps to create configurable dashboards easily. |
|||
|
|||
Configuration |
|||
============= |
|||
* No additional configurations needed |
|||
|
|||
License |
|||
------- |
|||
Affero General Public License, Version 3 (AGPL v3). |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
Developer: (V15) Unnimaya C O, Contact : odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import controllers |
|||
from . import models |
@ -0,0 +1,65 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
{ |
|||
'name': "Advanced Dynamic Dashboard", |
|||
'version': '15.0.1.0.0', |
|||
'category': 'Productivity', |
|||
'summary': """Helps to create configurable dashboards easily.""", |
|||
'description': """This module helps to create configurable advanced dynamic |
|||
dashboard to get the information that are relevant to your business, |
|||
department or a specific process or need.""", |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': "https://www.cybrosys.com", |
|||
'depends': ['web'], |
|||
'data': [ |
|||
'security/ir.model.access.csv', |
|||
'views/dashboard_views.xml', |
|||
'views/dynamic_block_views.xml', |
|||
'views/dashboard_menu_views.xml', |
|||
], |
|||
'assets': { |
|||
'web.assets_backend': [ |
|||
'advanced_dynamic_dashboard/static/lib/css/gridstack.min.css', |
|||
'advanced_dynamic_dashboard/static/src/css/dynamic_dashboard.css', |
|||
'advanced_dynamic_dashboard/static/src/scss/dynamic_dashboard.scss', |
|||
"https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.3/font/bootstrap-icons.css", |
|||
'https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.2.6/gridstack.min.js', |
|||
'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.js', |
|||
"https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js", |
|||
"https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js", |
|||
'https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js', |
|||
'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js', |
|||
'advanced_dynamic_dashboard/static/src/js/dynamic_dashboard.js', |
|||
'https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700' |
|||
], |
|||
'web.assets_qweb': [ |
|||
'advanced_dynamic_dashboard/static/src/xml/dynamic_dashboard_template.xml', |
|||
], |
|||
}, |
|||
'images': ['static/description/banner.png'], |
|||
'license': "AGPL-3", |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': True, |
|||
} |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import advanced_dynamic_dashboard |
@ -0,0 +1,44 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import http |
|||
from odoo.http import request |
|||
|
|||
|
|||
class DynamicDashboard(http.Controller): |
|||
"""Class to search and filter values in dashboard""" |
|||
|
|||
@http.route('/tile/details', type='json', auth='user') |
|||
def tile_details(self, **kw): |
|||
"""Function to get tile details""" |
|||
tile_id = request.env['dashboard.block'].sudo().browse( |
|||
int(kw.get('id'))) |
|||
if tile_id: |
|||
return {'model': tile_id.model_id.model, 'filter': tile_id.filter, |
|||
'model_name': tile_id.model_id.name} |
|||
return False |
|||
|
|||
@http.route('/custom_dashboard/search_input_chart', type='json', |
|||
auth="public", website=True) |
|||
def dashboard_search_input_chart(self, search_input): |
|||
"""Function to filter search input in dashboard""" |
|||
return request.env['dashboard.block'].search([ |
|||
('name', 'ilike', search_input)]).ids |
@ -0,0 +1,7 @@ |
|||
## Module <advanced_dynamic_dashboard> |
|||
|
|||
#### 21.12.2023 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
|
|||
- Initial commit for Advanced Dynamic Dashboard |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from . import dashboard_block |
|||
from . import dashboard_menu |
|||
from . import models |
@ -0,0 +1,185 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from ast import literal_eval |
|||
from datetime import datetime |
|||
from odoo import api, fields, models |
|||
from odoo.osv import expression |
|||
|
|||
|
|||
class DashboardBlock(models.Model): |
|||
"""Class is used to create charts and tiles in dashboard""" |
|||
_name = "dashboard.block" |
|||
_description = "Dashboard Blocks" |
|||
|
|||
def get_default_action(self): |
|||
"""Function to get values from dashboard if action_id is true return |
|||
id else return false""" |
|||
action_id = self.env.ref( |
|||
'advanced_dynamic_dashboard.dashboard_view_action') |
|||
if action_id: |
|||
return action_id.id |
|||
return False |
|||
|
|||
name = fields.Char(string="Name", help='Name of the block') |
|||
fa_icon = fields.Char(string="Icon", help="Add icon for tile") |
|||
graph_size = fields.Selection( |
|||
selection=[("col-lg-4", "Small"), ("col-lg-6", "Medium"), |
|||
("col-lg-12", "Large")], |
|||
string="Graph Size", default='col-lg-4', help="Select the graph size") |
|||
operation = fields.Selection( |
|||
selection=[("sum", "Sum"), ("avg", "Average"), ("count", "Count")], |
|||
string="Operation", |
|||
help='Tile Operation that needs to bring values for tile', |
|||
required=True) |
|||
graph_type = fields.Selection( |
|||
selection=[("bar", "Bar"), ("radar", "Radar"), ("pie", "Pie"), |
|||
("line", "Line"), |
|||
("doughnut", "Doughnut")], |
|||
string="Chart Type", help='Type of Chart') |
|||
measured_field_id = fields.Many2one("ir.model.fields", |
|||
string="Measured Field", |
|||
help="Select the Measured") |
|||
client_action_id = fields.Many2one('ir.actions.client', |
|||
string="Client action", |
|||
default=get_default_action, |
|||
help="Choose the client action") |
|||
type = fields.Selection( |
|||
selection=[("graph", "Chart"), ("tile", "Tile")], string="Type", |
|||
help='Type of Block ie, Chart or Tile') |
|||
x_axis = fields.Char(string="X-Axis", help="Chart X-axis") |
|||
y_axis = fields.Char(string="Y-Axis", help="Chart Y-axis") |
|||
x_pos = fields.Integer(string="X-Position", help="Chart X-axis position") |
|||
y_pos = fields.Integer(string="Y-Position", help="Chart Y-axis position") |
|||
height = fields.Integer(string="Height", help="Chart height") |
|||
width = fields.Integer(string="Width", help="Chart width") |
|||
group_by_id = fields.Many2one("ir.model.fields", store=True, |
|||
string="Group by(Y-Axis)", |
|||
help='Field value for Y-Axis') |
|||
tile_color = fields.Char(string="Tile Color", help='Primary color of Tile') |
|||
text_color = fields.Char(string="Text Color", help='Text color of Tile') |
|||
val_color = fields.Char(string="Value Color", help='Value color of Tile') |
|||
fa_color = fields.Char(string="Icon Color", help='Icon color of Tile') |
|||
filter = fields.Char(string="Filter", help="Add filter") |
|||
model_id = fields.Many2one('ir.model', string='Model', |
|||
help="Select the module name") |
|||
model_name = fields.Char(related='model_id.model', string="Model Name", |
|||
help="Added model_id model") |
|||
edit_mode = fields.Boolean(string="Edit Mode", |
|||
help="Enable to edit chart and tile", |
|||
invisible=True) |
|||
|
|||
@api.onchange('model_id') |
|||
def _onchange_model_id(self): |
|||
"""Method to work when the value in the field model_id changes""" |
|||
self.operation = False |
|||
self.measured_field_id = False |
|||
self.group_by_id = False |
|||
|
|||
def get_dashboard_vals(self, action_id, start_date=None, end_date=None): |
|||
"""Fetch block values from js and create chart""" |
|||
block_id = [] |
|||
for rec in self.sudo().search( |
|||
[('client_action_id', '=', int(action_id))]): |
|||
if rec.filter is False: |
|||
rec.filter = "[]" |
|||
filter_list = literal_eval(rec.filter) |
|||
# Remove existing date filters if any exist |
|||
filter_list = [filter_item for filter_item in filter_list if not ( |
|||
isinstance(filter_item, tuple) and filter_item[0] == |
|||
'create_date')] |
|||
if start_date and start_date != 'null': |
|||
start_date_obj = datetime.strptime(start_date, |
|||
'%Y-%m-%d') |
|||
filter_list.append( |
|||
('create_date', '>=', start_date_obj.strftime('%Y-%m-%d'))) |
|||
if end_date and end_date != 'null': |
|||
end_date_obj = datetime.strptime(end_date, '%Y-%m-%d') |
|||
filter_list.append( |
|||
('create_date', '<=', end_date_obj.strftime('%Y-%m-%d'))) |
|||
rec.filter = repr(filter_list) |
|||
vals = {'id': rec.id, 'name': rec.name, 'type': rec.type, |
|||
'graph_type': rec.graph_type, 'icon': rec.fa_icon, |
|||
'cols': rec.graph_size, |
|||
'color': 'background-color: %s;' % rec.tile_color |
|||
if rec.tile_color else '#1f6abb;', |
|||
'text_color': 'color: %s;' % rec.text_color |
|||
if rec.text_color else '#FFFFFF;', |
|||
'val_color': 'color: %s;' % rec.val_color |
|||
if rec.val_color else '#FFFFFF;', |
|||
'icon_color': 'color: %s;' % rec.tile_color |
|||
if rec.tile_color else '#1f6abb;', |
|||
'x_pos': rec.x_pos, 'y_pos': rec.y_pos, |
|||
'height': rec.height, |
|||
'width': rec.width} |
|||
domain = [] |
|||
if rec.filter: |
|||
domain = expression.AND([literal_eval(rec.filter)]) |
|||
if rec.model_name: |
|||
if rec.type == 'graph': |
|||
self._cr.execute(self.env[rec.model_name]. |
|||
get_query(domain, rec.operation, |
|||
rec.measured_field_id, |
|||
group_by=rec.group_by_id)) |
|||
records = self._cr.dictfetchall() |
|||
x_axis = [] |
|||
for record in records: |
|||
if record.get('name') and type( |
|||
record.get('name')) == dict: |
|||
x_axis.append(record.get('name')[self._context.get( |
|||
'lang') or 'en_US']) |
|||
else: |
|||
x_axis.append(record.get(rec.group_by_id.name)) |
|||
y_axis = [] |
|||
for record in records: |
|||
y_axis.append(record.get('value')) |
|||
vals.update({'x_axis': x_axis, 'y_axis': y_axis}) |
|||
else: |
|||
self._cr.execute(self.env[rec.model_name]. |
|||
get_query(domain, rec.operation, |
|||
rec.measured_field_id)) |
|||
records = self._cr.dictfetchall() |
|||
magnitude = 0 |
|||
total = records[0].get('value') |
|||
while abs(total) >= 1000: |
|||
magnitude += 1 |
|||
total /= 1000.0 |
|||
# add more suffixes if you need them |
|||
val = '%.2f%s' % ( |
|||
total, ['', 'K', 'M', 'G', 'T', 'P'][magnitude]) |
|||
records[0]['value'] = val |
|||
vals.update(records[0]) |
|||
block_id.append(vals) |
|||
return block_id |
|||
|
|||
def get_save_layout(self, act_id, grid_data_list): |
|||
"""Function fetch edited values while edit layout of the chart or tile |
|||
and save values in a database""" |
|||
for block in self.env['dashboard.block'].sudo().search( |
|||
[('client_action_id', '=', int(act_id))]): |
|||
for data in grid_data_list: |
|||
if block['id'] == data['id']: |
|||
block.write({ |
|||
'x_pos': int(data['x']), |
|||
'y_pos': int(data['y']), |
|||
'height': int(data['height']), |
|||
'width': int(data['width']), |
|||
}) |
@ -0,0 +1,79 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class DashboardMenu(models.Model): |
|||
"""Class to create new dashboard menu""" |
|||
_name = "dashboard.menu" |
|||
_description = "Dashboard Menu" |
|||
|
|||
name = fields.Char(string="Name", |
|||
help="Enter a name for the dashboard menu") |
|||
menu_id = fields.Many2one('ir.ui.menu', string="Parent Menu", |
|||
help="Parent Menu Location of New Dashboard", |
|||
ondelete='cascade') |
|||
group_ids = fields.Many2many('res.groups', string='Groups', |
|||
related='menu_id.groups_id', |
|||
help="User need to be at least in one of " |
|||
"these groups to see the menu") |
|||
client_action_id = fields.Many2one('ir.actions.client', |
|||
string="Client Action", |
|||
help="Client action") |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Function to create new dashboard menu""" |
|||
action_id = self.env['ir.actions.client'].create({ |
|||
'name': vals['name'], |
|||
'tag': 'advanced_dynamic_dashboard', |
|||
}) |
|||
vals['client_action_id'] = action_id.id |
|||
self.env['ir.ui.menu'].create({ |
|||
'name': vals['name'], |
|||
'parent_id': vals['menu_id'], |
|||
'action': 'ir.actions.client,%d' % (action_id.id,) |
|||
}) |
|||
return super().create(vals) |
|||
|
|||
def write(self, vals): |
|||
"""Function to save edited data in dashboard menu""" |
|||
for rec in self: |
|||
client_act_id = rec['client_action_id'].id |
|||
self.env['ir.ui.menu'].search( |
|||
[('parent_id', '=', rec['menu_id'].id), |
|||
('action', '=', f'ir.actions.client,{client_act_id}')]).write( |
|||
{'name': vals['name'] if 'name' in vals.keys() else rec['name'], |
|||
'parent_id': vals['menu_id'] if 'menu_id' in vals.keys() else |
|||
rec['menu_id'], |
|||
'action': f'ir.actions.client,{client_act_id}' |
|||
}) |
|||
return super().write(vals) |
|||
|
|||
def unlink(self): |
|||
"""Delete dashboard along with menu item""" |
|||
for rec in self: |
|||
self.env['ir.ui.menu'].search( |
|||
[('parent_id', '=', rec['menu_id'].id), |
|||
('action', '=', |
|||
f'ir.actions.client,{rec["client_action_id"].id}')]).unlink() |
|||
return super().unlink() |
@ -0,0 +1,59 @@ |
|||
# -*- coding: utf-8 -*- |
|||
################################################################################ |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Unnimaya C O (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
################################################################################ |
|||
from odoo import models |
|||
|
|||
|
|||
def get_query(self, args, operation, field, group_by=False, |
|||
apply_ir_rules=False): |
|||
"""Method for creating query for fetching data to be displayed on the |
|||
dashboard block""" |
|||
query = self._where_calc(args) |
|||
if apply_ir_rules: |
|||
self._apply_ir_rules(query, 'read') |
|||
join = '' |
|||
group_by_str = '' |
|||
if operation and field: |
|||
data = 'COALESCE(%s("%s".%s),0) AS value' % (operation.upper(), |
|||
self._table, field.name) |
|||
if group_by: |
|||
if group_by.ttype == 'many2one': |
|||
relation_model = group_by.relation.replace('.', '_') |
|||
join = ' INNER JOIN %s on "%s".id = "%s".%s' % ( |
|||
relation_model, relation_model, self._table, group_by.name) |
|||
rec_name = self.env[group_by.relation]._rec_name_fallback() |
|||
data = data + ',"%s".%s AS %s' % (relation_model, rec_name, |
|||
group_by.name) |
|||
group_by_str = ' Group by "%s".%s' % (relation_model, rec_name) |
|||
else: |
|||
data = data + ',"%s".%s' % (self._table, group_by.name) |
|||
group_by_str = ' Group by "%s".%s' % (self._table, |
|||
str(group_by.name)) |
|||
else: |
|||
data = '"%s".id' % self._table |
|||
from_clause, where_clause, where_clause_params = query.get_sql() |
|||
where_str = where_clause and (" WHERE %s" % where_clause) or '' |
|||
query_str = ('SELECT %s FROM ' % data + from_clause + join + where_str + |
|||
group_by_str) |
|||
return query_str % tuple( |
|||
map(lambda x: "'" + str(x) + "'", where_clause_params)) |
|||
|
|||
models.BaseModel.get_query = get_query |
|
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 156 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 155 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 163 KiB |
After Width: | Height: | Size: 342 KiB |
After Width: | Height: | Size: 158 KiB |
After Width: | Height: | Size: 185 KiB |
After Width: | Height: | Size: 157 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 8.7 KiB |
@ -0,0 +1,735 @@ |
|||
<div class="container" |
|||
style="padding: 1rem !important; margin-bottom: 1rem !important;"> |
|||
<div class="row"> |
|||
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between" |
|||
style="border-bottom: 1px solid #d5d5d5;"> |
|||
<div class="my-3"> |
|||
<img src="./assets/icons/logo.png" |
|||
style="width: auto !important; height: 40px !important;"> |
|||
</div> |
|||
<div class="my-3 d-flex align-items-center"> |
|||
<div |
|||
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> |
|||
<i class="fa fa-check mr-1"></i>Community |
|||
</div> |
|||
<div |
|||
style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> |
|||
<i class="fa fa-check mr-1"></i>Enterprise |
|||
</div> |
|||
<div |
|||
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> |
|||
<i class="fa fa-check mr-1"></i>Odoo.sh |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="container" style="padding: 0rem 1.5rem 4rem !important"> |
|||
<div class="row" style="height: 900px !important;"> |
|||
<div class="col-sm-12 col-md-12 col-lg-12" |
|||
style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;"> |
|||
<h1 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important; font-size: 3.5rem !important; text-align: center !important;"> |
|||
Advanced Dynamic Dashboard</h1> |
|||
<p |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important; font-size: 1.4rem !important; text-align: center !important;"> |
|||
Facilitates the Seamless Creation of Customizable Dashboards. |
|||
</p> |
|||
<img src="./assets/screenshots/hero.gif" class="img-responsive" |
|||
width="100%" height="auto"/> |
|||
</div> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-md-12" |
|||
style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important"> |
|||
<h2 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> |
|||
<i class="fa fa-compass mr-2"></i>Explore this module |
|||
</h2> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<a href="#overview" style="text-decoration: none !important;"> |
|||
<div class="row" |
|||
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> |
|||
<div class="col-8"> |
|||
<h3 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> |
|||
Overview</h3> |
|||
<p |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> |
|||
Learn more about this module</p> |
|||
</div> |
|||
<div class="col-4 text-right d-flex justify-content-end align-items-center"> |
|||
<i class="fa fa-chevron-right" |
|||
style="color: #714B67 !important;"></i> |
|||
</div> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<a href="#features" style="text-decoration: none !important;"> |
|||
<div class="row" |
|||
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> |
|||
<div class="col-8"> |
|||
<h3 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> |
|||
Features</h3> |
|||
<p |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> |
|||
View features of this module</p> |
|||
</div> |
|||
<div class="col-4 text-right d-flex justify-content-end align-items-center"> |
|||
<i class="fa fa-chevron-right" |
|||
style="color: #714B67 !important;"></i> |
|||
</div> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<a href="#screenshots" style="text-decoration: none !important;"> |
|||
<div class="row" |
|||
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> |
|||
<div class="col-8"> |
|||
<h3 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> |
|||
Screenshots</h3> |
|||
<p |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> |
|||
See key screenshots of this module</p> |
|||
</div> |
|||
<div class="col-4 text-right d-flex justify-content-end align-items-center"> |
|||
<i class="fa fa-chevron-right" |
|||
style="color: #714B67 !important;"></i> |
|||
</div> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="row" id="overview"> |
|||
<div class="col-md-12" |
|||
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> |
|||
<h2 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> |
|||
<i class="fa fa-pie-chart mr-2"></i>Overview |
|||
</h2> |
|||
</div> |
|||
<div class="col-mg-12 pl-3"> |
|||
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;"> |
|||
The Advanced Dynamic Dashboard module empowers users to |
|||
customize,arrange, and access real-time data relevant to their |
|||
business, |
|||
department, or specific processes, facilitating informed |
|||
decision-making and optimized performance. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
<div class="row" id="features"> |
|||
<div class="col-md-12" |
|||
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> |
|||
<h2 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> |
|||
<i class="fa fa-star mr-2"></i>Features |
|||
</h2> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Effortlessly generate interactive Charts and Tiles.</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Available Dark mode and Light mode</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Feasible to establish a Dashboard Menu in any |
|||
model.</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Charts can be exported as Images, PDFs, and CSVs.</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Enable dragging and resizing of Charts and Tiles for |
|||
flexible layouts.</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6 pl-3 py-3 d-flex"> |
|||
<div> |
|||
<img src="assets/icons/check.png"> |
|||
</div> |
|||
<div> |
|||
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Edit and configure Charts and Tiles</h4> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="row" id="screenshots"> |
|||
<div class="col-md-12" |
|||
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> |
|||
<h2 |
|||
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> |
|||
<i class="fa fa-image mr-2"></i>Screenshots |
|||
</h2> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Click ADD ITEMS to add Graphs and Tiles to the Dashboard.</h4> |
|||
<img src="assets/screenshots/1.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Add required details for creating a Tile</h4> |
|||
<img src="assets/screenshots/2.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
New Tiles on the dashboard.</h4> |
|||
<img src="assets/screenshots/3.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Create new Chart</h4> |
|||
<img src="assets/screenshots/4.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Charts added to the dashboard.</h4> |
|||
<img src="assets/screenshots/5.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Dashboard based on the date filter. |
|||
</h4> |
|||
<img src="assets/screenshots/6.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
It is possible to Search the name of chart or tile.</h4> |
|||
<img src="assets/screenshots/8.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Click the marked button for enabling Dark Mode.</h4> |
|||
<img src="assets/screenshots/9.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Dashboard in Dark Mode.</h4> |
|||
<img src="assets/screenshots/10.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Click EDIT LAYOUT for editing the dashboard layout.</h4> |
|||
<img src="assets/screenshots/s15.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
It is possible to change size of chart and tile by clicking the |
|||
marked icon, also we can drag them to any position.</h4> |
|||
<img src="assets/screenshots/s17.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Click on the 3 dots icon for exporting the graphs.</h4> |
|||
<img src="assets/screenshots/s18.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Graph exported as image.</h4> |
|||
<img src="assets/screenshots/s19.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Graph exported as pdf.</h4> |
|||
<img src="assets/screenshots/s20.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Navigate to Dashboards menu to add the dashboard menu under any |
|||
menu.</h4> |
|||
<img src="assets/screenshots/11.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
Choose the menu name and parent menu.</h4> |
|||
<img src="assets/screenshots/12.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
New menu added in Inventory module.</h4> |
|||
<img src="assets/screenshots/13.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
<div class="col-lg-12 my-2"> |
|||
<h4 class="mt-2" |
|||
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> |
|||
We can create new dashboard here.</h4> |
|||
<img src="assets/screenshots/14.png" |
|||
class="img-responsive img-thumbnail border" width="100%" |
|||
height="auto"/> |
|||
</div> |
|||
</div> |
|||
<!-- SUGGESTED PRODUCTS --> |
|||
<div class="row"> |
|||
<div class="col-lg-12 d-flex flex-column justify-content-center" |
|||
style="text-align: center; padding: 2.5rem 1rem !important;"> |
|||
<h2 style="color: #212529 !important;">Suggested Products</h2> |
|||
<hr |
|||
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
|||
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
|||
<!-- The slideshow --> |
|||
<div class="carousel-inner"> |
|||
<div class="carousel-item active" style="min-height:0px"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/project_dashboard_odoo/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/dash.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/agriculture_management_odoo/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/l2.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/product_to_quotation/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/multi_product.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item" style="min-height:0px"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/systray_world_clock/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/systray.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/shopify_odoo_connector/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/shopify.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/woo_commerce/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/woocomp_connector.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Left and right controls --> |
|||
<a class="carousel-control-prev" href="#demo1" data-slide="prev" |
|||
style="left:-25px;width: 35px;color: #000;"> |
|||
<span class="carousel-control-prev-icon"><i |
|||
class="fa fa-chevron-left" |
|||
style="font-size:24px"></i></span> </a> |
|||
<a class="carousel-control-next" href="#demo1" data-slide="next" |
|||
style="right:-25px;width: 35px;color: #000;"> |
|||
<span class="carousel-control-next-icon"><i |
|||
class="fa fa-chevron-right" |
|||
style="font-size:24px"></i></span> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SUGGESTED PRODUCTS --> |
|||
<!-- OUR SERVICES --> |
|||
<section class="container" style="margin-top: 6rem !important;"> |
|||
<div class="row"> |
|||
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
|||
<h2 style="color: #212529 !important;">Our Services</h2> |
|||
<hr |
|||
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/cogs.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Customization</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/wrench.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/lifebuoy.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Support</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/user.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Hire |
|||
Odoo |
|||
Developer</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/puzzle.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Integration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/update.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Migration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/consultation.png" |
|||
class="img-responsive" height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Consultancy</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/training.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/license.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Licensing Consultancy</h6> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<!-- END OF OUR SERVICES --> |
|||
<!-- OUR INDUSTRIES --> |
|||
<section class="container" style="margin-top: 6rem !important;"> |
|||
<div class="row"> |
|||
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
|||
<h2 style="color: #212529 !important;">Our Industries</h2> |
|||
<hr |
|||
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/trading-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Trading |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easily procure |
|||
and |
|||
sell your products</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/pos-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
POS |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easy |
|||
configuration |
|||
and convivial experience</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/education-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Education |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
A platform for |
|||
educational management</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/manufacturing-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Manufacturing |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Plan, track and |
|||
schedule your operations</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/ecom-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
E-commerce & Website |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Mobile |
|||
friendly, |
|||
awe-inspiring product pages</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/service-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Service Management |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Keep track of |
|||
services and invoice</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/restaurant-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Restaurant |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Run your bar or |
|||
restaurant methodically</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="./assets/icons/hotel-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Hotel Management |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
An |
|||
all-inclusive |
|||
hotel management application</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<!--END OF OUR INDUSTRIES --> |
|||
<!-- FOOTER --> |
|||
<!-- Footer Section --> |
|||
<section class="container" style="margin: 5rem auto 2rem;"> |
|||
<div class="row" style="max-width:1540px;"> |
|||
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> |
|||
<h2 style="color: #212529 !important;">Need Help?</h2> |
|||
<hr |
|||
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> |
|||
</div> |
|||
</div> |
|||
<!-- Contact Cards --> |
|||
<div class="row d-flex justify-content-center align-items-center" |
|||
style="max-width:1540px; margin: 0 auto 2rem auto;"> |
|||
<div class="col-lg-12" |
|||
style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; "> |
|||
<div class="row mt-4"> |
|||
<div class="col-lg-6"> |
|||
<a href="mailto:odoo@cybrosys.com" target="_blank" |
|||
class="btn btn-block mb-2 deep_hover" |
|||
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i |
|||
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<a href="https://api.whatsapp.com/send?phone=918606827707" |
|||
target="_blank" |
|||
class="btn btn-block mb-2 deep_hover" |
|||
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i |
|||
class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
<!-- End of Contact Cards --> |
|||
</section> |
|||
<!-- Footer --> |
|||
<section class="oe_container" style="padding: 2rem 3rem 1rem;"> |
|||
<div class="row" |
|||
style="max-width:1540px; margin: 0 auto; margin-right: 3rem; "> |
|||
<!-- Logo --> |
|||
<div class="col-lg-12 d-flex justify-content-center align-items-center" |
|||
style="margin-top: 3rem;"> |
|||
<img src="https://www.cybrosys.com/images/logo.png" |
|||
width="200px" height="auto"/> |
|||
</div> |
|||
<!-- End of Logo --> |
|||
<div class="col-lg-12"> |
|||
<hr |
|||
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;"> |
|||
<!-- End of Footer Section --> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
<!-- END OF FOOTER --> |
|||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" |
|||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" |
|||
crossorigin="anonymous"></script> |
|||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" |
|||
integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" |
|||
crossorigin="anonymous"></script> |
@ -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; |
|||
} |
|||
} |
@ -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; |
|||
}); |
@ -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; |
|||
} |
|||
} |
|||
} |
@ -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> |
@ -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> |
@ -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> |
@ -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> |