You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
550 lines
25 KiB
550 lines
25 KiB
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',
|
|
'click #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',
|
|
},
|
|
init: function (parent, context) {//Function to Initializes all the values while loading the file
|
|
this.action_id = context['id'];
|
|
this._super(parent, context);
|
|
this.block_ids = [];
|
|
},
|
|
willStart: function () {//Returns the function fetch_data when page load.
|
|
var self = this;
|
|
return $.when(this._super()).then(function () {
|
|
return self.fetch_data();
|
|
});
|
|
},
|
|
start: function () {//Function return render_dashboards() and gridstack_init()
|
|
self = this;
|
|
this.set("title", 'Dashboard');
|
|
return this._super().then(function () {
|
|
self.render_dashboards();
|
|
// self.gridstack_init(self);
|
|
});
|
|
},
|
|
fetch_data: function () {//Fetch data and call rpc query to create chart or tile. return block_ids
|
|
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);
|
|
},
|
|
show_mode_text: function () {//Function change text of dark and light mode while clicking the dark and light button.
|
|
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();
|
|
},
|
|
hide_mode_text: function () {//While click button, hide the mode icon and text
|
|
this.$el.find('.theme_icon').next(this.el.querySelector('.theme-text')).fadeOut(function () {
|
|
$(this).remove();
|
|
});
|
|
},
|
|
switch_mode: function (ev) {//Function to change dashboard theme dark and light mode.
|
|
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);
|
|
},
|
|
_onchangeFilter: function() {
|
|
this.$('#edit_layout').show();
|
|
var start_date = $('#start-date').val();
|
|
var end_date = $('#end-date').val();
|
|
var self = this;
|
|
if (!start_date) {
|
|
start_date = "null";
|
|
}
|
|
if (!end_date) {
|
|
end_date = "null";
|
|
}
|
|
console.log(start_date,"start")
|
|
console.log(end_date,"end")
|
|
this._rpc({
|
|
model: 'dashboard.block',
|
|
method: 'get_dashboard_vals',
|
|
args: [[], this.action_id, start_date, end_date],
|
|
}).then(function (result) {
|
|
console.log(result,"res")
|
|
self.block_ids = result;
|
|
self.$('.o_dynamic_dashboard').empty(); // Clear existing blocks before rendering
|
|
self.render_dashboards(); // Re-render the dashboard with updated data
|
|
// var gridstack = self.$('.grid-stack').data('gridstack');
|
|
// gridstack.enableMove(true);
|
|
// gridstack.enableResize(true);
|
|
// console.log(gridstack,"selffffffff")
|
|
// self.gridstack_init(self);
|
|
// self.gridstack_on(self);
|
|
// self.gridstack_init(self); // Reinitialize gridstack after rendering
|
|
});
|
|
},
|
|
get_colors: function (x_axis) {//Function fetch random color values and set chart color
|
|
return x_axis.map(() => `rgb(${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)}, ${Math.floor(Math.random() * 255)})`);
|
|
},
|
|
|
|
get_values_bar: function (block) {//Set bar chart label, color, data and options. And return data and options
|
|
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];
|
|
},
|
|
get_values_pie: function (block) {//Set pie chart data and options. And return data and options.
|
|
var data = {
|
|
labels: block['x_axis'],
|
|
datasets: [{
|
|
label: '',
|
|
data: block['y_axis'],
|
|
backgroundColor: this.get_colors(block['x_axis']),
|
|
hoverOffset: 4
|
|
}]
|
|
};
|
|
return [data, {}];
|
|
},
|
|
get_values_line: function (block) {//Set line chart label, data and options. And return data and options.
|
|
var data = {
|
|
labels: block['x_axis'],
|
|
datasets: [{
|
|
label: '',
|
|
data: block['y_axis'],
|
|
fill: false,
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
tension: 0.1
|
|
}]
|
|
};
|
|
return [data, {}];
|
|
},
|
|
get_values_doughnut: function (block) {// Set doughnut chart data and options. And return data and options.
|
|
var data = {
|
|
labels: block['x_axis'],
|
|
datasets: [{
|
|
label: '',
|
|
data: block['y_axis'],
|
|
backgroundColor: this.get_colors(block['x_axis']),
|
|
hoverOffset: 4
|
|
}]
|
|
};
|
|
return [data, {}];
|
|
},
|
|
get_values_polarArea: function (block) {// Set polarArea chart data and options. And return data and options.
|
|
var data = {
|
|
labels: block['x_axis'],
|
|
datasets: [{
|
|
label: '',
|
|
data: block['y_axis'],
|
|
backgroundColor: this.get_colors(block['x_axis']),
|
|
hoverOffset: 4
|
|
}]
|
|
};
|
|
return [data, {}];
|
|
},
|
|
get_values_radar: function (block) {// Set radar chart data and options. And return data and options.
|
|
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];
|
|
},
|
|
gridstack_init: function (self) {// Used gridstack to drag and resize chart and tile.
|
|
console.log(self,"selfselfselfselfself")
|
|
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,
|
|
// autoHide: false,
|
|
},
|
|
alwaysShowResizeHandle: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
|
|
float: true
|
|
});
|
|
self.gridstack_off(self);
|
|
},
|
|
gridstack_on: function (self) {// Enable move and resize functionality
|
|
console.log(self,"---")
|
|
var gridstack = self.$('.grid-stack').data('gridstack');
|
|
console.log(gridstack,"gridddddd")
|
|
gridstack.enableMove(true);
|
|
gridstack.enableResize(true);
|
|
console.log(gridstack,"selffffffff")
|
|
},
|
|
gridstack_off: function (self) {// Disable move and resize functionality
|
|
var gridstack = self.$('.grid-stack').data('gridstack');
|
|
gridstack.enableMove(false);
|
|
gridstack.enableResize(false);
|
|
},
|
|
render_dashboards: function () {
|
|
console.log(this.block_ids,"prefghj")
|
|
self = this;
|
|
self.$("#save_layout").hide();//Hide save_layout button
|
|
_.each(this.block_ids, function (block) {//Loop all chart and tile
|
|
if (block['type'] == 'tile') {
|
|
self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardTile', {widget: block}));
|
|
} 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)`
|
|
new Chart(self.$('.chart_graphs').last(), {
|
|
type: type,
|
|
data: eval(chart_type)[0],
|
|
options: eval(chart_type)[1]
|
|
});
|
|
}
|
|
});
|
|
// 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();
|
|
}
|
|
}
|
|
});
|
|
self.$(".grid-stack-item").on({//Function to hide dropdown-export list while mouse leave the block.
|
|
mouseleave: function () {
|
|
self.$('.dropdown-export').hide();
|
|
}
|
|
});
|
|
self.$(".dropdown-addblock").on({//Function to hide dropdown-addblock list if mouse leave dropdown list.
|
|
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');
|
|
}
|
|
},
|
|
navbar_toggle: function () {//Function to toggle the navbar.
|
|
this.$('.navbar-collapse').toggle();
|
|
},
|
|
export_item: function (e) {//Function to export chart into jpg, png or csv formate.
|
|
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();
|
|
}
|
|
},
|
|
dropdown_toggle: function () {//Function to toggle the button Add Items.
|
|
this.$el.find('.dropdown-addblock').toggle();
|
|
},
|
|
on_reverse_breadcrumb: function () {//Function return all block in exact position.
|
|
self = this;
|
|
this.fetch_data().then(function () {//Fetch all datas
|
|
self.render_dashboards();
|
|
self.gridstack_init(self);
|
|
location.reload();
|
|
});
|
|
},
|
|
search_chart: function (e) {// Fetch search input value and filter the chart and tile.
|
|
e.stopPropagation()
|
|
self = this;
|
|
$(this).next("#theme-change-icon").hide();
|
|
this.$("#edit_layout").hide();
|
|
this.$("#save_layout").hide();
|
|
this.myDiv = this.$('.o_dynamic_dashboard');
|
|
this.$('.o_dynamic_dashboard').empty();
|
|
ajax.jsonRpc("/custom_dashboard/search_input_chart", 'call', {//Ajax call to get filtered data
|
|
'search_input': self.$("#search-input-chart").val()
|
|
}).then(function (res) {
|
|
_.each(self.block_ids, function (block) {
|
|
if (res.includes(block['id'])) {
|
|
if (block['type'] == 'tile') {
|
|
self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardTile', {widget: block}));
|
|
} else {
|
|
self.$('.o_dynamic_dashboard').append(QWeb.render('DynamicDashboardChart', {widget: block}));
|
|
if (!('x_axis' in block)) {
|
|
return false
|
|
}
|
|
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]
|
|
});
|
|
}
|
|
}
|
|
});
|
|
});
|
|
},
|
|
clear_search: function () {//Function to clear search box and call the functon on_reverse_breadcrumb().
|
|
self = this;
|
|
self.$("#search-input-chart").val("");
|
|
self.$("#theme-change-icon").show();
|
|
self.$("#edit_layout").show();
|
|
self.$("#save_layout").hide();
|
|
this.block_ids = [];
|
|
self.on_reverse_breadcrumb();
|
|
},
|
|
_onClick_block_setting: function (event) {//Function to edit blocks and redirect to the model dashboard.block
|
|
event.stopPropagation();
|
|
self = this;
|
|
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})
|
|
},
|
|
_onClick_block_delete: function (event) {//While click on cross icon, the block will be deleted.
|
|
event.stopPropagation();
|
|
self = this;
|
|
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'
|
|
}
|
|
},
|
|
callback: function (result) {//Function to unlink block
|
|
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) {
|
|
console.log('Error unlinking record: ', error);
|
|
});
|
|
} else {
|
|
// Do nothing
|
|
}
|
|
}
|
|
});
|
|
},
|
|
_onClick_add_block: function (e) {//Fetch data and create chart or tile
|
|
self = this;
|
|
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 ' + 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 LOCAL STORAGE MEMORY
|
|
},
|
|
_onClick_edit_layout: function (e) {// Function to hide edit_layout button and show save_layout button. and also work the function gridstack_on(self)
|
|
console.log(e,"oooo")
|
|
e.stopPropagation();
|
|
self = this;
|
|
self.$("#edit_layout").hide();
|
|
self.$("#save_layout").show();
|
|
self.gridstack_on(self);
|
|
},
|
|
_onClick_save_layout: function (e) {//Function to save the edited value
|
|
e.stopPropagation();
|
|
self = this;
|
|
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);
|
|
},
|
|
_onClick_tile: function (e) {// Function to view the tree view of the tile.
|
|
e.stopPropagation();
|
|
self = this;
|
|
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;
|
|
});
|
|
|