Tower: upload ks_dashboard_ninja 18.0.1.1.7 (was 18.0.1.1.7, via marketplace)
This commit is contained in:
556
addons/ks_dashboard_ninja/static/src/components/Header/Header.js
Normal file
556
addons/ks_dashboard_ninja/static/src/components/Header/Header.js
Normal file
@@ -0,0 +1,556 @@
|
||||
/**@odoo-module **/
|
||||
|
||||
import { Component, useState} from "@odoo/owl";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { useForwardRefToParent } from "@web/core/utils/hooks";
|
||||
import { download } from "@web/core/network/download";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { KsDateFilter } from '@ks_dashboard_ninja/components/date_filter/date_filter';
|
||||
import { ks_get_current_gridstack_config } from '@ks_dashboard_ninja/js/ks_global_functions'
|
||||
import { DNFilter } from '@ks_dashboard_ninja/components/dn_filter/dn_filter';
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { FormViewDialog} from '@web/views/view_dialogs/form_view_dialog';
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { eraseAllCookies } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
|
||||
export class KsHeader extends Component{
|
||||
static props = {
|
||||
dashboard_data: {type:Object, optional:true },
|
||||
mode : { type: String },
|
||||
headerRootRef: { type: Function, optional: true },
|
||||
}
|
||||
static components = { Dropdown, DropdownItem, KsDateFilter, DNFilter }
|
||||
static template = "ks_dashboard_ninja.Ks_dashboard_ninja_header"
|
||||
|
||||
|
||||
setup(){
|
||||
// super.setup()
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.action = this.env.services.action
|
||||
this.uiService = useService("ui");
|
||||
this.action = useService("action");
|
||||
this.notification = useService("notification");
|
||||
this._rpc = rpc
|
||||
this.ks_dashboard_id = this.ks_dashboard_data.ks_dashboard_id
|
||||
this.isMobile = isMobileOS();
|
||||
this.headerRootRef = useForwardRefToParent("headerRootRef");
|
||||
this.items_length = this.ks_dashboard_data.ks_dashboard_items_ids.length
|
||||
this.state = useState({
|
||||
mode: this.props.mode , // types - [ "manager", "user", "mobile", "layout", "custom_date" ]
|
||||
isDashboardBookmarked: this.ks_dashboard_data.is_bookmarked
|
||||
});
|
||||
this.dialogService = this.env.services.dialog
|
||||
|
||||
this.tempSelectedLayoutId = JSON.parse(JSON.stringify(this.ks_dashboard_data.ks_selected_board_id))
|
||||
this.tempDashboardName = JSON.parse(JSON.stringify(this.ks_dashboard_data.name))
|
||||
|
||||
this.dropdowns = [
|
||||
{ name: "Edit Layout", modes: ["manager", "custom_date"],
|
||||
func: ()=>this.onKsEditLayoutClick(), svg: "ks_dashboard_ninja.header_edit_svg" },
|
||||
{ name: "Bookmark Dashboard", modes: ["manager", "user", "custom_date"],
|
||||
func: ()=>this.updateBookmark(), svg: "ks_dashboard_ninja.bookmark" },
|
||||
{ name: "Capture Dashboard", modes: ["manager", "user", "custom_date"],
|
||||
func: ()=> this.dashboardImageUpdate(), svg: "ks_dashboard_ninja.capture" },
|
||||
{ name: "Settings", svg: "ks_dashboard_ninja.setting", modes: ["manager", "custom_date"],
|
||||
dropdown_items: [ {name: "Dashboard Settings" , svg: "ks_dashboard_ninja.setting-2", func: (ev)=>this.ksOnDashboardSettingClick(ev), class : '', modes: ["manager", "custom_date"],},
|
||||
{name: "Delete the Dashboard", svg: "ks_dashboard_ninja.trash_svg", func: this.ksOnDashboardDeleteClick.bind(this), class : '', modes: ["manager", "custom_date"],},
|
||||
{name: "Create New Dashboard", svg: "ks_dashboard_ninja.add-square", func:()=>this.ksOnDashboardCreateClick(), class : '', modes: ["manager", "custom_date"],},
|
||||
{name: "Generate Dashboard with AI", svg: "ks_dashboard_ninja.illustrator", func:()=>this.kscreateaidashboard(), class : '', modes: ["manager", "custom_date"],},
|
||||
{name: "Duplicate Current Dashboard", svg: "ks_dashboard_ninja.copy", func:(ev)=>this.ksOnDashboardDuplicateClick(ev), class : '', modes: ["manager", "custom_date"],}], },
|
||||
{ name: "More", svg: "ks_dashboard_ninja.more", modes: ["manager", "user", "custom_date"],
|
||||
dropdown_items: [ {name: "Import Item" , svg: "ks_dashboard_ninja.download_svg", func: () => this.ksImportItemJson(), class : '', modes: ["manager", "custom_date"],},
|
||||
{name: "Export Dashboard", svg: "ks_dashboard_ninja.document-upload", func:()=>this.ksOnDashboardExportClick(), class : '', modes: ["manager","user", "custom_date"],},
|
||||
{name: "Import Dashboard", svg: "ks_dashboard_ninja.download_svg", func:()=>this.ksOnDashboardImportClick(), class : '', modes: ["manager", "custom_date"],}] },
|
||||
]
|
||||
|
||||
this.header_mode_buttons = { "edit" : { buttons : [{ name: "Discard", callback: this._onDiscardLayoutChanges.bind(this), classes: 'dash-default-btn bg-white me-2', shouldVisible: true },
|
||||
{ name: "Save as New Layout", callback: this.onSaveNewLayoutClick.bind(this), classes: 'dash-btn-red me-2 ks-bg-violet', shouldVisible: this.props.dashboard_data.multi_layouts },
|
||||
{ name: "Save Layout", callback: this._onKsSaveLayoutClick.bind(this), classes: 'dash-btn-red', shouldVisible: true } ] },
|
||||
"layout": { buttons : [{ name: "Set Default Layout", callback: this._ksSetLayoutAsDefault.bind(this), classes: 'dash-btn-red', shouldVisible: true},
|
||||
{ name: "Discard", callback: this.discardLayoutSelection.bind(this), classes: 'dash-default-btn bg-white', shouldVisible: true}] } }
|
||||
|
||||
}
|
||||
|
||||
update_mode(mode){
|
||||
this.state.mode = mode
|
||||
}
|
||||
|
||||
dashboardImageUpdate(){
|
||||
let image_element = document.querySelector('.ks_dashboard_main_content');
|
||||
if(!document.querySelector('.ks_dashboard_main_content')?.childNodes.length){
|
||||
image_element = document.querySelector('.main-box');
|
||||
}
|
||||
let self = this;
|
||||
this.uiService.block();
|
||||
let canvas = html2canvas(image_element, {
|
||||
height: image_element.clientHeight + 186,
|
||||
width: image_element.clientWidth,
|
||||
windowWidth: image_element.scrollWidth,
|
||||
windowHeight: image_element.scrollHeight,
|
||||
scrollY: 0,
|
||||
scrollX: 0,
|
||||
x: image_element.scrollLeft,
|
||||
y: image_element.scrollTop < 600 ? image_element.scrollTop < 50 ? image_element.scrollTop :
|
||||
image_element.scrollTop - 150 : image_element.scrollTop - 650,
|
||||
}).then((canvas) => {
|
||||
let image = canvas.toDataURL("image/png");
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/saveImage",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'save_dashboard_image',
|
||||
args: [[self.ks_dashboard_id]],
|
||||
kwargs:{image: image},
|
||||
}).then((result) => {
|
||||
this.uiService.unblock();
|
||||
});
|
||||
});
|
||||
this.notification.add(_t('Dashboard image updated successfully!'),{
|
||||
title:_t("Dashboard Image Refreshed"),
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
|
||||
restoreController(){
|
||||
let self = this;
|
||||
let js_id = self.action.currentController.jsId
|
||||
self.action.restore(js_id)
|
||||
}
|
||||
|
||||
_onDiscardLayoutChanges(){
|
||||
this.restoreController();
|
||||
}
|
||||
|
||||
async updateBookmark(){
|
||||
let updatedBookmarks = await this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/update_bookmarks",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'update_bookmarks',
|
||||
args: [[this.ks_dashboard_id]],
|
||||
kwargs:{},
|
||||
});
|
||||
updatedBookmarks = updatedBookmarks[1]
|
||||
this.state.isDashboardBookmarked = !this.state.isDashboardBookmarked
|
||||
this.notification.add(_t(`Dashboard ${ updatedBookmarks ? "added to" : "removed from"} your bookmarks`),{
|
||||
title:_t(`Bookmark ${ updatedBookmarks ? "Added" : "Removed"}`), type: 'success'});
|
||||
}
|
||||
|
||||
|
||||
|
||||
onCreateNewChartClick() {
|
||||
|
||||
let self = this;
|
||||
self.dialogService.add(FormViewDialog,{
|
||||
resModel: 'ks_dashboard_ninja.item',
|
||||
is_expand_icon_visible: true,
|
||||
context: {
|
||||
'ks_dashboard_id': self.ks_dashboard_data.ks_dashboard_id,
|
||||
'ks_dashboard_item_type': 'ks_tile',
|
||||
'form_view_ref': 'ks_dashboard_ninja.item_form_view',
|
||||
'form_view_initial_mode': 'edit',
|
||||
'ks_set_interval': self.ks_dashboard_data.ks_set_interval,
|
||||
'ks_data_formatting':self.ks_dashboard_data.ks_data_formatting,
|
||||
'ks_form_view' : true
|
||||
},
|
||||
onRecordSaved:()=>{
|
||||
var js_id = self.env.services.action.currentController.jsId
|
||||
self.env.services.action.restore(js_id)
|
||||
},
|
||||
size: "fs",
|
||||
title: "Create New Chart"
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onDashboardLayoutSelect(selected_board_id){
|
||||
this.state.mode = 'layout'
|
||||
this.tempSelectedLayoutId = selected_board_id
|
||||
this.setLayoutGrid(selected_board_id);
|
||||
}
|
||||
|
||||
setLayoutGrid(layout_id){
|
||||
let grid_stack = this.env.gridStackRootRef.el.gridstack
|
||||
let selected_layout_grid_config = this.ks_dashboard_data.ks_child_boards[layout_id][1];
|
||||
selected_layout_grid_config = JSON.parse(selected_layout_grid_config);
|
||||
Object.entries(selected_layout_grid_config).forEach((x,y)=>{
|
||||
grid_stack.update($(this.env.gridStackRootRef.el).find(".grid-stack-item[gs-id=" + x[0] + "]")[0],{ x:x[1]['x'], y:x[1]['y'], w:x[1]['w'], h:x[1]['h'], autoPosition:false});
|
||||
});
|
||||
}
|
||||
|
||||
discardLayoutSelection(){
|
||||
this.state.mode = this.ks_dashboard_data.ks_dashboard_manager ? "manager" : "user"
|
||||
this.tempSelectedLayoutId = this.ks_dashboard_data.ks_selected_board_id
|
||||
this.setLayoutGrid(this.ks_dashboard_data.ks_selected_board_id);
|
||||
}
|
||||
|
||||
_ksSetLayoutAsDefault(){
|
||||
let self = this;
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/update_child_board",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'update_child_board',
|
||||
args: ['update', self.ks_dashboard_id, {
|
||||
"ks_selected_board_id": this.tempSelectedLayoutId ? this.tempSelectedLayoutId : this.ks_dashboard_data.ks_selected_board_id,
|
||||
}],
|
||||
kwargs:{},
|
||||
}).then(function(result){
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
checkItemsPresence(){
|
||||
if(!this.items_length){
|
||||
this.notification.add(_t('No Items!'),{ title:_t("Create some items"), type: 'info'});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onKsEditLayoutClick(e) {
|
||||
if(this.checkItemsPresence()) return;
|
||||
let dashboard_data = this.ks_dashboard_data
|
||||
this.tempDashboardName = dashboard_data.multi_layouts && dashboard_data.ks_child_boards ?
|
||||
dashboard_data.ks_child_boards[dashboard_data.ks_selected_board_id]?.[0] : dashboard_data.name
|
||||
this.env.gridStackRootRef.el.gridstack.setStatic(false);
|
||||
this.env.update_dashboard_mode('edit');
|
||||
this.env.gridStackRootRef?.el.gridstack?.enable();
|
||||
this.state.mode = "edit"
|
||||
}
|
||||
|
||||
_onKsSaveLayoutClick(){
|
||||
let self = this;
|
||||
let grid_stack = this.env.gridStackRootRef.el.gridstack
|
||||
grid_stack.setStatic(true);
|
||||
let dashboard_title = this.tempDashboardName
|
||||
if (dashboard_title != false && dashboard_title != 0) {
|
||||
let model = 'ks_dashboard_ninja.board';
|
||||
let rec_id = self.ks_dashboard_data.ks_dashboard_id;
|
||||
|
||||
if(this.ks_dashboard_data.multi_layouts && this.ks_dashboard_data.ks_child_boards){
|
||||
this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][0] = dashboard_title;
|
||||
if (this.ks_dashboard_data.ks_selected_board_id !== 'ks_default'){
|
||||
rec_id = parseInt(this.ks_dashboard_data.ks_selected_board_id);
|
||||
this.env.services.orm.write("ks_dashboard_ninja.child_board", [rec_id], { 'name': dashboard_title });
|
||||
}
|
||||
else{
|
||||
this.ks_dashboard_data.name = this.tempDashboardName;
|
||||
this.env.services.orm.write("ks_dashboard_ninja.board", [rec_id], { 'name': dashboard_title });
|
||||
}
|
||||
}
|
||||
else{
|
||||
self.ks_dashboard_data.name = dashboard_title;
|
||||
this.env.services.orm.write("ks_dashboard_ninja.board", [rec_id], { 'name': dashboard_title });
|
||||
}
|
||||
|
||||
}
|
||||
if (this.ks_dashboard_data.ks_item_data) self._ksSaveCurrentLayout();
|
||||
this.env.update_dashboard_mode('active')
|
||||
|
||||
grid_stack.disable();
|
||||
grid_stack.commit();
|
||||
this.state.mode = this.ks_dashboard_data.ks_dashboard_manager ? "manager" : "user"
|
||||
}
|
||||
|
||||
_ksSaveCurrentLayout() {
|
||||
let self = this;
|
||||
let grid_config = ks_get_current_gridstack_config(this.env.gridStackRootRef.el);
|
||||
let model = 'ks_dashboard_ninja.child_board';
|
||||
let rec_id = self.ks_dashboard_data.ks_gridstack_config_id;
|
||||
self.ks_dashboard_data.ks_gridstack_config = JSON.stringify(grid_config);
|
||||
if(this.ks_dashboard_data.ks_selected_board_id && this.ks_dashboard_data.ks_child_boards){
|
||||
this.ks_dashboard_data.ks_child_boards[this.ks_dashboard_data.ks_selected_board_id][1] = JSON.stringify(grid_config);
|
||||
if (this.ks_dashboard_data.ks_selected_board_id !== 'ks_default'){
|
||||
rec_id = parseInt(this.ks_dashboard_data.ks_selected_board_id)
|
||||
}
|
||||
}
|
||||
if (!isMobileOS()) { // Do not save in Mobile view , due to column mode enable
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.child_board/write",{
|
||||
model: model,
|
||||
method: 'write',
|
||||
args: [parseInt(rec_id), {
|
||||
"ks_gridstack_config": JSON.stringify(grid_config)
|
||||
}],
|
||||
kwargs:{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
onSaveNewLayoutClick() {
|
||||
let self = this;
|
||||
let grid_stack = this.env.gridStackRootRef.el.gridstack
|
||||
grid_stack.setStatic(true);
|
||||
var dashboard_title = $('#ks_dashboard_title_input').val();
|
||||
if (dashboard_title === "") {
|
||||
self.notification.add(_t("Dashboard Name is required to save as New Layout"), { type: 'warning' });
|
||||
} else{
|
||||
if (!self.ks_dashboard_data.ks_child_boards){
|
||||
self.ks_dashboard_data.ks_child_boards = {
|
||||
'ks_default': [ this.ks_dashboard_data.name, self.ks_dashboard_data.ks_gridstack_config ]
|
||||
}
|
||||
}
|
||||
this.ks_dashboard_data.name = dashboard_title;
|
||||
|
||||
let grid_config = ks_get_current_gridstack_config(this.env.gridStackRootRef.el);
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/update_child_board",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'update_child_board',
|
||||
args: ['create', self.ks_dashboard_id, {
|
||||
"ks_gridstack_config": JSON.stringify(grid_config),
|
||||
"ks_dashboard_ninja_id": self.ks_dashboard_id,
|
||||
"name": dashboard_title,
|
||||
"ks_active": true,
|
||||
"company_id": self.ks_dashboard_data.ks_company_id,
|
||||
}],
|
||||
kwargs : {},
|
||||
}).then(function(res_id){
|
||||
self.ks_update_child_board_value(dashboard_title, res_id, grid_config),
|
||||
// self._ksRenderActiveMode();
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ks_update_child_board_value(dashboard_title, res_id, grid_config){
|
||||
let self = this;
|
||||
let child_board_id = res_id.toString();
|
||||
self.ks_dashboard_data.ks_selected_board_id = child_board_id;
|
||||
let update_data = {};
|
||||
update_data[child_board_id] = [dashboard_title, JSON.stringify(grid_config)];
|
||||
self.ks_dashboard_data.ks_child_boards = Object.assign(update_data, self.ks_dashboard_data.ks_child_boards);
|
||||
}
|
||||
|
||||
ksOnDashboardSettingClick(ev){
|
||||
let self = this;
|
||||
let dashboard_id = this.ks_dashboard_id;
|
||||
// TODO : Apply such functionlity that we donot have to give name of the name of the filter as string to erase cookies Also dont need to remove all cookies"
|
||||
eraseAllCookies(this.ks_dashboard_id, ['PFilter', 'PFilterDataObj', 'Filter', 'CFilter', 'FilterDateData', 'ChartFilter', 'FFilter']);
|
||||
let action = {
|
||||
name: _t('Dashboard Settings'),type: 'ir.actions.act_window',
|
||||
res_model: 'ks_dashboard_ninja.board', res_id: dashboard_id,
|
||||
domain: [],context: {'create':false},
|
||||
views: [
|
||||
[false, 'form']
|
||||
],view_mode: 'form',target: 'new',
|
||||
}
|
||||
// self.action.doAction(action)
|
||||
self.action.doAction(action).then(function(result){
|
||||
// self.eraseCookie('FilterOrderData' + self.ks_dashboard_id);
|
||||
});
|
||||
}
|
||||
|
||||
ksOnDashboardExportClick(){
|
||||
// ev.preventDefault();
|
||||
let self= this;
|
||||
let dashboard_id = JSON.stringify(this.ks_dashboard_id);
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_dashboard_export", {
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: "ks_dashboard_export",
|
||||
args: [dashboard_id],
|
||||
kwargs: {dashboard_id: dashboard_id}
|
||||
}).then(function(result) {
|
||||
var name = "dashboard_ninja";
|
||||
var data = {"header": name, "dashboard_data":result,}
|
||||
download({
|
||||
data: { data:JSON.stringify(data) },
|
||||
url: '/ks_dashboard_ninja/export/dashboard_json',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ksOnDashboardDeleteClick(ev){
|
||||
let dashboard_id = this.ks_dashboard_id;
|
||||
let self= this;
|
||||
self.dialogService.add(ConfirmationDialog, {
|
||||
body: _t("Are you sure you want to delete this dashboard ?"),
|
||||
confirmLabel: _t("Delete Dashboard"),
|
||||
title: _t("Delete Dashboard"),
|
||||
confirm: () => {
|
||||
this._rpc("/web/dataset/call_kw/ks.dashboard.delete.wizard/ks_delete_record", {
|
||||
model: 'ks.dashboard.delete.wizard',
|
||||
method: "ks_delete_record",
|
||||
args: [dashboard_id],
|
||||
kwargs: {dashboard_id: dashboard_id}
|
||||
}).then((result)=>{
|
||||
self.env.services.menu.reload();
|
||||
let currentAppId = self.env.services.menu?.getCurrentApp()?.id;
|
||||
self.env.services.menu.selectMenu(currentAppId).then(()=>{
|
||||
self.notification.add(_t('Dashboard Deleted Successfully'),{
|
||||
title:_t("Deleted"),
|
||||
type: 'success',
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
ksOnDashboardCreateClick(){
|
||||
var self= this;
|
||||
var action = {
|
||||
name: _t('Add New Dashboard'), type: 'ir.actions.act_window',
|
||||
res_model: 'ks.dashboard.wizard', domain: [],
|
||||
context: {}, views: [ [false, 'form']],
|
||||
view_mode: 'form', target: 'new',
|
||||
}
|
||||
self.action.doAction(action)
|
||||
}
|
||||
|
||||
ksOnDashboardDuplicateClick(){
|
||||
let self= this;
|
||||
let dashboard_id = this.ks_dashboard_id;
|
||||
this._rpc('/web/dataset/call_kw/ks.dashboard.duplicate.wizard/DuplicateDashBoard', {
|
||||
model: 'ks.dashboard.duplicate.wizard', method: "DuplicateDashBoard",
|
||||
args: [this.ks_dashboard_id], kwargs: {}
|
||||
}).then((result)=>{
|
||||
self.action.doAction(result)
|
||||
});
|
||||
}
|
||||
|
||||
kscreateaidashboard(){
|
||||
let self= this;
|
||||
let action = {
|
||||
name: _t('Generate Dashboard with AI'), type: 'ir.actions.act_window',
|
||||
res_model: 'ks_dashboard_ninja.ai_dashboard',domain: [],
|
||||
context: {'ks_dashboard_id': this.ks_dashboard_id},
|
||||
views: [ [false, 'form']],
|
||||
view_mode: 'form', target: 'new',
|
||||
}
|
||||
self.action.doAction(action)
|
||||
}
|
||||
|
||||
kscreateaiitem(ev){
|
||||
var self= this;
|
||||
self.dialogService.add(FormViewDialog,{
|
||||
resModel: 'ks_dashboard_ninja.arti_int', title: 'Generate items with AI',
|
||||
is_expand_icon_visible: true,
|
||||
context: {
|
||||
'ks_dashboard_id': this.ks_dashboard_id, 'ks_form_view' : true,
|
||||
'generate_dialog' : true, dialog_size: 'extra-large',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ksOnDashboardImportClick(){
|
||||
let self = this;
|
||||
let dashboard_id = this.ks_dashboard_id;
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_open_import", {
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_open_import',
|
||||
args: [dashboard_id],
|
||||
kwargs: {
|
||||
dashboard_id: dashboard_id
|
||||
}
|
||||
}).then((result)=>{
|
||||
self.action.doAction(result)
|
||||
});
|
||||
}
|
||||
|
||||
ksImportItemJson() {
|
||||
var self = this;
|
||||
$('.ks_input_import_item_button').click();
|
||||
}
|
||||
|
||||
ksImportItem(e) {
|
||||
var self = this;
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() {
|
||||
$('.ks_input_import_item_button').val('');
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_import_item", {
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_import_item',
|
||||
args: [self.ks_dashboard_id],
|
||||
kwargs: {
|
||||
file: fileReader.result,
|
||||
dashboard_id: self.ks_dashboard_id
|
||||
}
|
||||
}).then(function(result) {
|
||||
if (result === "Success") {
|
||||
var js_id = self.action.currentController.jsId
|
||||
self.action.restore(js_id)
|
||||
}
|
||||
});
|
||||
};
|
||||
fileReader.readAsText($('.ks_input_import_item_button').prop('files')[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
ks_gen_ai_analysis(ev){
|
||||
var self = this;
|
||||
this.state.dialog_header = false;
|
||||
var ks_items = Object.values(self.ks_dashboard_data.ks_item_data);
|
||||
var ks_items_explain = []
|
||||
var ks_rest_items = []
|
||||
if (ks_items.length>0){
|
||||
ks_items.map((item)=>{
|
||||
ks_items_explain.push({
|
||||
name:item.name,
|
||||
id:item.id,
|
||||
ks_chart_data:item.ks_chart_data?{...JSON.parse(item.ks_chart_data),...{domains:[],previous_domain:[]}}:item.ks_chart_data,
|
||||
ks_list_view_data: typeof item.ks_list_view_data === 'string' ? JSON.parse(item.ks_list_view_data) : item.ks_list_view_data,
|
||||
item_type:item.ks_dashboard_item_type,
|
||||
groupedby:item.ks_chart_relation_groupby_name,
|
||||
subgroupedby:item.ks_chart_relation_sub_groupby_name,
|
||||
stacked_bar_chart:item.ks_bar_chart_stacked,
|
||||
count_type:item.ks_record_count_type,
|
||||
count:item.ks_record_count,
|
||||
model_name:item.ks_model_display_name,
|
||||
kpi_data:item.ks_kpi_data
|
||||
})
|
||||
});
|
||||
this.dialogService.add(ConfirmationDialog, {
|
||||
body: _t("Do you agree that AI should be used to produce the explanation? It will take a few minutes to finish the process?"),
|
||||
title:_t("Explain with AI"),
|
||||
cancel: () => {},
|
||||
confirmLabel: _t("Confirm"),
|
||||
confirm: () => {
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_generate_analysis",{
|
||||
model: 'ks_dashboard_ninja.arti_int',
|
||||
method: 'ks_generate_analysis',
|
||||
args: [ks_items_explain,ks_rest_items,self.ks_dashboard_id],
|
||||
kwargs:{},
|
||||
}).then(function(result) {
|
||||
if (result){
|
||||
self.action.doAction({
|
||||
type: "ir.actions.client",
|
||||
name: _t("Explain with AI"),
|
||||
target: "new",
|
||||
tag: 'ks_dashboard_ninja',
|
||||
params:{
|
||||
ks_dashboard_id: self.ks_dashboard_id,
|
||||
on_dialog: true,
|
||||
explain_ai_whole: true,
|
||||
explainWithAi: true,
|
||||
dashboard_data: self.ks_dashboard_data,
|
||||
},
|
||||
context: {
|
||||
dialog_size: 'extra-large'
|
||||
}
|
||||
},{
|
||||
onClose: ()=>{
|
||||
return self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_switch_default_dashboard",{
|
||||
model: 'ks_dashboard_ninja.arti_int',
|
||||
method: 'ks_switch_default_dashboard',
|
||||
args: [self.ks_dashboard_id],
|
||||
kwargs:{},
|
||||
})
|
||||
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}else{
|
||||
self.notification.add(_t('Please make few items to explain with AI'),{
|
||||
title:_t("Failed"),
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<template>
|
||||
<t t-name="ks_dashboard_ninja.Ks_dashboard_ninja_header" owl="1">
|
||||
<section class="screen-info mb-2 container-fluid" t-ref="headerRootRef">
|
||||
<div class="d-flex align-items-center justify-content-between info gap-1 flex-wrap w-100 ks_dashboard_top_menu-new">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
|
||||
<div id="ks_dashboard_title" class="user-template-title dash-dd-2">
|
||||
<t t-if="['manager', 'user', 'layout'].includes(state.mode)" t-call="ks_dashboard_ninja.ks_dn_layout_container"/>
|
||||
<div class="form-input-box form-control ps-4" t-if="['edit'].includes(state.mode)">
|
||||
<input id="ks_dashboard_title_input" type="text" maxlength="35"
|
||||
t-att-value="tempDashboardName" t-model="this.tempDashboardName"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-if="!isMobile" t-call="ks_dashboard_ninja.ks_header_dropdowns"/>
|
||||
<KsDateFilter t-if="['manager', 'user', 'custom_date'].includes(state.mode) && items_length"
|
||||
dashboard_data="this.ks_dashboard_data" update_mode.bind="update_mode"/>
|
||||
<DNFilter t-if="['manager', 'user'].includes(state.mode) && !isMobile && items_length"
|
||||
dashboard_data="this.ks_dashboard_data"/>
|
||||
|
||||
<t t-if="ks_dashboard_data.ks_dashboard_manager">
|
||||
<div class="ks_dashboard_top_settings dropdown d-none d-lg-block">
|
||||
<input accept=".json " t-attf-id="file_#{_id}"
|
||||
name="file" class="ks_input_import_item_button" type="file" style="display:none;"
|
||||
t-on-change="ksImportItem"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<t t-if="['manager'].includes(state.mode) && !isMobile">
|
||||
<div class="new-features ks_dashboard_top_settings hide-in-edit d-flex align-items-center ms-auto">
|
||||
<div class="d-lg-flex d-none">
|
||||
<div class="dropdown dash-dd-2 magic-star-dd" title="AI Features">
|
||||
<a class="text-decoration-none dropdown-toggle img-bg info me-lg-2 me-1" href="#"
|
||||
role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.01757 5.03498C8.24044 4.43268 9.09232 4.43268 9.31519 5.03498L10.7982 9.04271C10.8683 9.23208 11.0176 9.38137 11.2069 9.45144L15.2147 10.9344C15.817 11.1573 15.817 12.0092 15.2147 12.2321L11.2069 13.7151C11.0176 13.7851 10.8683 13.9344 10.7982 14.1238L9.31519 18.1315C9.09232 18.7338 8.24044 18.7338 8.01757 18.1315L6.53457 14.1238C6.4645 13.9344 6.31521 13.7851 6.12585 13.7151L2.11811 12.2321C1.51581 12.0092 1.51581 11.1573 2.11811 10.9344L6.12585 9.45144C6.31521 9.38137 6.4645 9.23208 6.53457 9.04271L8.01757 5.03498Z" fill="" stroke="" stroke-width="1.25"/>
|
||||
<path d="M17.6239 5L13.6239 5" stroke="" stroke-width="1.25" stroke-linecap="round"/>
|
||||
<path d="M15.6244 7L15.6244 3" stroke="" stroke-width="1.25" stroke-linecap="round"/>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu py-0 ks-dropdown-menu">
|
||||
<li>
|
||||
<button class="feature-btn dropdown-item" t-on-click="kscreateaiitem" title="Generate the charts of a particular model using AI">
|
||||
<span>
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" class="me-2">
|
||||
<path d="M13.3996 4.62671C13.3996 4.98671 13.2063 5.31337 12.8996 5.48004L11.7396 6.10671L10.7529 6.63337L8.70628 7.74004C8.48628 7.86004 8.24628 7.92004 7.99961 7.92004C7.75294 7.92004 7.51294 7.86004 7.29294 7.74004L3.09961 5.48004C2.79294 5.31337 2.59961 4.98671 2.59961 4.62671C2.59961 4.26671 2.79294 3.94004 3.09961 3.77337L4.41294 3.06671L5.45961 2.50004L7.29294 1.51337C7.73294 1.27337 8.26628 1.27337 8.70628 1.51337L12.8996 3.77337C13.2063 3.94004 13.3996 4.26671 13.3996 4.62671Z" fill="#6789C6"/>
|
||||
<path d="M6.59917 8.52664L2.69917 6.57997C2.39917 6.42664 2.0525 6.44664 1.76583 6.61997C1.47917 6.79331 1.3125 7.09997 1.3125 7.4333V11.12C1.3125 11.76 1.66583 12.3333 2.23917 12.62L6.13917 14.5666C6.2725 14.6333 6.41917 14.6666 6.56583 14.6666C6.73917 14.6666 6.9125 14.62 7.06583 14.52C7.3525 14.3466 7.51917 14.04 7.51917 13.7066V10.02C7.52583 9.38664 7.1725 8.8133 6.59917 8.52664Z" fill="#6789C6"/>
|
||||
<path d="M14.686 7.43338V11.12C14.686 11.7534 14.3327 12.3267 13.7593 12.6134L9.85932 14.5667C9.72599 14.6334 9.57932 14.6667 9.43266 14.6667C9.25932 14.6667 9.08599 14.62 8.92599 14.52C8.64599 14.3467 8.47266 14.04 8.47266 13.7067V10.0267C8.47266 9.38671 8.82599 8.81338 9.39932 8.52671L10.8327 7.81338L11.8327 7.31338L13.2993 6.58004C13.5993 6.42671 13.946 6.44004 14.2327 6.62004C14.5127 6.79338 14.686 7.10004 14.686 7.43338Z" fill="#6789C6"/>
|
||||
<path d="M11.7407 6.10667L10.7541 6.63333L4.41406 3.06667L5.46073 2.5L11.5807 5.95333C11.6474 5.99333 11.7007 6.04667 11.7407 6.10667Z" fill="#6789C6"/>
|
||||
<path d="M11.834 7.31335V8.82669C11.834 9.10002 11.6073 9.32669 11.334 9.32669C11.0607 9.32669 10.834 9.10002 10.834 8.82669V7.81335L11.834 7.31335Z" fill="#6789C6"/>
|
||||
</svg>
|
||||
</span>
|
||||
Generate with AI
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button class="feature-btn dropdown-item" t-on-click="ks_gen_ai_analysis">
|
||||
<span>
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/convertshape.png" alt="convertshape"
|
||||
class="img-fluid me-2" loading="lazy"/>
|
||||
</span>
|
||||
Explain with AI
|
||||
</button>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<button class="feature-btn d-xl-none d-block dark dropdown-item" t-on-click="onCreateNewChartClick">
|
||||
<span>
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/Graph 1.svg" alt="Graph" class="img-fluid me-1"
|
||||
loading="lazy"/>
|
||||
</span>
|
||||
Create New Chart
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button class="feature-btn dark d-xl-block d-none me-0" t-on-click="onCreateNewChartClick" title="Add the Charts to Dashboard">
|
||||
<span>
|
||||
<svg width="25" height="23" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg" class="">
|
||||
<mask id="mask0_9094_3795" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="20" height="21">
|
||||
<rect y="0.5" width="20" height="20" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_9094_3795)">
|
||||
<path d="M8.54411 5.40375L8.77611 8.85371L8.89128 10.5877C8.89253 10.766 8.92045 10.9432 8.97436 11.1135C9.11345 11.444 9.44811 11.654 9.81219 11.6393L15.3599 11.2764C15.6001 11.2725 15.8321 11.3623 16.0048 11.5262C16.1487 11.6628 16.2416 11.8415 16.2709 12.0336L16.2808 12.1503C16.0512 15.3292 13.7164 17.9807 10.5441 18.6651C7.37174 19.3495 4.11866 17.9037 2.55104 15.1125C2.0991 14.3016 1.81682 13.4104 1.72076 12.491C1.68064 12.2188 1.66297 11.9439 1.66793 11.6689C1.66297 8.26074 4.09 5.31426 7.48739 4.60394C7.89629 4.54026 8.29714 4.75673 8.46111 5.12974C8.50353 5.21612 8.53153 5.30864 8.54411 5.40375Z" fill="#04A9CC"/>
|
||||
<path opacity="0.4" d="M18.3333 8.67687L18.3275 8.70403L18.3107 8.74352L18.313 8.85196C18.3043 8.99554 18.2488 9.13371 18.1533 9.24538C18.0537 9.36163 17.9177 9.44079 17.768 9.47154L17.6767 9.48404L11.276 9.89879C11.0631 9.91979 10.8511 9.85113 10.6928 9.70996C10.5608 9.59221 10.4765 9.43338 10.4527 9.26221L10.0231 2.87084C10.0156 2.84923 10.0156 2.82581 10.0231 2.80419C10.0289 2.62802 10.1065 2.46149 10.2384 2.34182C10.3702 2.22214 10.5456 2.15929 10.725 2.16731C14.5249 2.26398 17.7186 4.99645 18.3333 8.67687Z" fill="#04A9CC"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
<span class="ellipsis-content max-width-medium-130">Create New Chart</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="['edit', 'layout'].includes(state.mode) && !isMobile">
|
||||
<t t-call="ks_dashboard_ninja.header_mode_buttons">
|
||||
<t t-set="buttons_condition" t-value="['edit', 'layout'].includes(state.mode)"/>
|
||||
<t t-set="buttons" t-value="header_mode_buttons[state.mode].buttons"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_header_dropdowns">
|
||||
<t t-foreach="dropdowns" t-as="dropdown" t-key="dropdown_index">
|
||||
<t t-if="dropdown.dropdown_items">
|
||||
<Dropdown menuClass="'ks-dropdown-menu'" t-if="dropdown.modes.includes(state.mode)">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem
|
||||
t-foreach="dropdown.dropdown_items"
|
||||
t-as="dropdown_item" t-key="dropdown_item_index"
|
||||
class="{ '': true }"
|
||||
t-if="dropdown_item.modes.includes(state.mode)"
|
||||
onSelected="dropdown_item.func">
|
||||
<span class="me-2">
|
||||
<t t-call="{{ dropdown_item.svg }}" />
|
||||
</span>
|
||||
<t t-esc="dropdown_item.name"/>
|
||||
</DropdownItem>
|
||||
</t>
|
||||
<span class="img-bg info">
|
||||
<t t-call="{{ dropdown.svg }}"/>
|
||||
</span>
|
||||
|
||||
</Dropdown>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<DropdownItem class="{ 'img-bg info cursor-pointer': true,
|
||||
'nav-active': dropdown.name === 'Bookmark Dashboard' && state.isDashboardBookmarked }"
|
||||
onSelected="dropdown.func" t-if="dropdown.modes.includes(state.mode)">
|
||||
<t t-call="{{ dropdown.svg }}" />
|
||||
</DropdownItem>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.header_mode_buttons">
|
||||
<div t-att-class=" 'd-flex gap-2 ' + btn_container_classes " t-if="buttons_condition">
|
||||
<t t-foreach="buttons" t-as="button" t-key="button_index">
|
||||
<button type="button" t-if="button.shouldVisible" t-att-class="button.classes" title="" t-on-click="button.callback">
|
||||
<span><t t-out="button.name"/></span>
|
||||
</button>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_dn_layout_container">
|
||||
<t t-if="props.dashboard_data.multi_layouts && props.dashboard_data.ks_child_boards">
|
||||
<Dropdown menuClass="'ks-dropdown-menu'" disabled="isMobile || !items_length || !ks_dashboard_data.ks_dashboard_manager">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem t-foreach="ks_dashboard_data.ks_child_boards" t-as="child_board" t-key="child_board_index"
|
||||
class="{ 'global-active': child_board === tempSelectedLayoutId }"
|
||||
onSelected="() => { this.onDashboardLayoutSelect(child_board) } "
|
||||
t-esc="ks_dashboard_data.ks_child_boards[child_board][0]"/>
|
||||
</t>
|
||||
<div class=" bg-transparent">
|
||||
<span class="ellipsis-content max-width-medium-25vw" t-esc="ks_dashboard_data.ks_child_boards[tempSelectedLayoutId][0]"
|
||||
t-att-class="isMobile || !items_length || !ks_dashboard_data.ks_dashboard_manager ? ' ks-dropdown-no--caret': ''"/>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span id="ks_dashboard_title_label" class="ks_am_element dash-dd-2 ellipsis-content max-width-medium-25vw"
|
||||
t-if="['manager', 'user'].includes(state.mode)" t-att-data-tooltip="props.dashboard_data.name">
|
||||
<t t-esc="props.dashboard_data.name"/>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
|
||||
</template>
|
||||
@@ -0,0 +1,295 @@
|
||||
.ks_body_class {
|
||||
.screen-info {
|
||||
background-color: $color-nav-bg;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 40px;
|
||||
|
||||
@include max-992 {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
@include max-575 {
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
// .ks_dashboard_top_menu-new {}
|
||||
|
||||
.user-template-title {
|
||||
.ks_body_class .ks_am_element.dash-dd-2 {
|
||||
font-size: $font-16;
|
||||
color: $color-black;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
span {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
// &::after {
|
||||
// content: '';
|
||||
// display: block;
|
||||
// position: absolute;
|
||||
// height: 20px;
|
||||
// width: 20px;
|
||||
// right: 2px;
|
||||
// background-image: url(../../images/icons/down-arrow.svg);
|
||||
// background-repeat: no-repeat;
|
||||
// top: 43%;
|
||||
// transition: all 350ms ease-in-out;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .img-bg {
|
||||
display: flex;
|
||||
justify-content: center !important;
|
||||
padding: 0 !important;
|
||||
align-items: center !important;
|
||||
background-color: $color-secondary-bg;
|
||||
border: 0.5px solid $color-E5E7EB;
|
||||
border-radius: 50% !important;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
|
||||
button{
|
||||
border: none;
|
||||
background:transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
&.info {
|
||||
background-color: $color-white !important;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
&.hover-item {
|
||||
background-color: $color-bg-main;
|
||||
|
||||
&.kpi-tile-img {
|
||||
background-color: $color-white !important;
|
||||
margin: 0;
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&:hover {
|
||||
transition: 0.2s linear;
|
||||
transform: scale(1.1);
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
svg {
|
||||
fill: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-white !important;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
&.dropdown-toggle::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
&.info svg {
|
||||
fill: none !important;
|
||||
stroke: $color-black !important;
|
||||
|
||||
@include max-992 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.info.active, &.info.nav-active,
|
||||
&.info:hover {
|
||||
border: 0.5px solid transparent !important;
|
||||
background-color: $color-6789C6 !important;
|
||||
|
||||
svg {
|
||||
stroke: $color-white !important;
|
||||
}
|
||||
}
|
||||
|
||||
@include max-992 {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
||||
& img {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// &.more-img {
|
||||
// svg {
|
||||
// fill: $color-black !important;
|
||||
// stroke: none !important;
|
||||
// }
|
||||
//
|
||||
// &.active,
|
||||
// &:hover {
|
||||
// svg {
|
||||
// fill: $color-white !important;
|
||||
// stroke: none !important;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
.ks_body_class .ks_chart_heading {
|
||||
width: 75% !important;
|
||||
}
|
||||
|
||||
.ks_body_class #ks_dashboard_title_input {
|
||||
width: 450px;
|
||||
}
|
||||
|
||||
.ks_body_class .ks_dashboard_layout_event {
|
||||
span.df_selection_text {
|
||||
padding: 0 6px !important;
|
||||
|
||||
|
||||
}
|
||||
|
||||
&.ks_layout_selected {
|
||||
span {
|
||||
&::before {
|
||||
left: -12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .magic-star-dd {
|
||||
.feature-btn {
|
||||
// border-bottom: 1px solid $color-E5E7EB;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.img-bg {
|
||||
border-radius: 10px !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: $color-FFF5F5 !important;
|
||||
min-height: 45px !important;
|
||||
width: 42px !important;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: $color-ABC8E7;
|
||||
stroke: $color-6789C6;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 1px solid $color-6789C6 !important;
|
||||
background-color: $color-FFF5F5 !important;
|
||||
// svg {
|
||||
// path {
|
||||
// fill: $color-white;
|
||||
// stroke: $color-white;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.img-bg.info svg.fill-black-stroke-none{
|
||||
fill: $color-black !important;
|
||||
stroke: none !important;
|
||||
|
||||
&.active,
|
||||
&:hover {
|
||||
fill: $color-white !important;
|
||||
stroke: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
#ks_dashboard_title_label {
|
||||
padding: 12px 15px;
|
||||
border: 0.5px solid #E5E7EB;
|
||||
color: #241C1D;
|
||||
border-radius: 10px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
// text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// overflow: hidden;
|
||||
// max-width: 187px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
button.ks-bg-violet {
|
||||
background-color: $color-6789C6 !important;
|
||||
border: 1px solid $color-6789C6 !important;
|
||||
|
||||
&:hover {
|
||||
background-color: $color-597ebe !important;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-btn {
|
||||
font-size: $font-16;
|
||||
font-weight: 500;
|
||||
line-height: 21px;
|
||||
text-align: left;
|
||||
color: $color-paragraph;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid $color-E5E7EB;
|
||||
outline: none;
|
||||
background-color: $color-white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
|
||||
|
||||
@include minmax1260 {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $color-secondary-bg;
|
||||
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $color-E7495E;
|
||||
}
|
||||
|
||||
&.light {
|
||||
background-color: $color-FFF5F5;
|
||||
|
||||
@include max-575 {
|
||||
padding: 6px 10px;
|
||||
font-size: $font-8;
|
||||
|
||||
& img {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
&.dark {
|
||||
background-color: $color-D9F1FD;
|
||||
|
||||
&:hover {
|
||||
background-color: #c4e4f3 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, onMounted, useRef } from "@odoo/owl";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { FormViewDialog } from '@web/views/view_dialogs/form_view_dialog';
|
||||
import { download } from "@web/core/network/download";
|
||||
import { BlockUI } from "@web/core/ui/block_ui";
|
||||
import { ks_get_current_gridstack_config } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
|
||||
|
||||
export class KsItemButton extends Component{
|
||||
static props = { item_data : { type: Object, optional:true },
|
||||
item_classes : { type: String, optional:true },
|
||||
itemRootRef : { type: Object },
|
||||
}
|
||||
static template = "ks_dashboard_ninja.ks_chart_buttons";
|
||||
|
||||
setup(){
|
||||
this.common_classes = 'ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover chart_button_container d-flex '
|
||||
this.ks_company = this.env.services.company.currentCompany.name
|
||||
this.isMobile = isMobileOS()
|
||||
this.item_data = this.props.item_data
|
||||
this.ks_button_color = this._ks_get_rgba_format(this.item_data.ks_button_color)
|
||||
this.id = this.props.item_data.id
|
||||
this.rootRef = useRef('rootRef')
|
||||
this.ksChartColorOptions = ["default", "dark", "moonrise", "material"]
|
||||
this.chart_list = ['ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_pie_chart',
|
||||
'ks_doughnut_chart', 'ks_polarArea_chart', 'ks_radialBar_chart', 'ks_scatter_chart', 'ks_funnel_chart',
|
||||
'ks_bullet_chart', 'ks_flower_view', 'ks_radar_view']
|
||||
this.isExportListVisible = [ ...this.chart_list, 'ks_map_view', 'ks_list_view'].includes(this.item_data.ks_dashboard_item_type)
|
||||
|
||||
this.store = useService("mail.store");
|
||||
this.showButtons = !this.env.inDialog
|
||||
this.selectedDashboardId = this.item_data.ks_dashboard_list[0]['id']
|
||||
|
||||
this.setItemDescription(this.item_data.ks_info)
|
||||
|
||||
}
|
||||
|
||||
_ks_get_rgba_format(val){
|
||||
let rgba = val.split(',')[0].match(/[A-Za-z0-9]{2}/g);
|
||||
rgba = rgba.map(function(v) {
|
||||
return parseInt(v, 16)
|
||||
}).join(",");
|
||||
return "rgba(" + rgba + "," + val.split(',')[1] + ")";
|
||||
}
|
||||
|
||||
setItemDescription(item_description){
|
||||
let item_description_list = item_description.replace?.(/\\n/g, '\n').split?.('\n').filter(element => element !== '');
|
||||
this.item_data.ks_info = item_description_list?.join?.(' ') ?? false
|
||||
this.ks_item_description_list = item_description_list ?? false
|
||||
}
|
||||
|
||||
handleDropdowns(ev){
|
||||
let targetDropdown = ev.target.closest('.dropdown-toggle')
|
||||
this.rootRef.el.querySelectorAll('.dropdown-toggle').forEach((dropdown) => {
|
||||
targetDropdown !== dropdown ? Dropdown.getInstance(dropdown)?.hide() : ''
|
||||
})
|
||||
}
|
||||
|
||||
onEditItemTypeClick() {
|
||||
var self = this;
|
||||
self.env.services.dialog.add(FormViewDialog,{
|
||||
resModel: 'ks_dashboard_ninja.item',
|
||||
title: 'Edit Chart',
|
||||
resId : self.id,
|
||||
is_expand_icon_visible: true,
|
||||
context: {
|
||||
'form_view_ref': 'ks_dashboard_ninja.item_form_view',
|
||||
'form_view_initial_mode': 'edit',
|
||||
'ks_form_view' :true
|
||||
},
|
||||
onRecordSaved: () => {
|
||||
var js_id = self.env.services.action.currentController.jsId
|
||||
self.env.services.action.restore(js_id)
|
||||
},
|
||||
onRecordDiscarded: () => {
|
||||
},
|
||||
size: 'fs'
|
||||
});
|
||||
}
|
||||
|
||||
async ksChartExportXlsCsv(e) {
|
||||
let chart_id = this.id;
|
||||
let name = this.item_data.name;
|
||||
let context = this.env.getContext();
|
||||
let data = {}
|
||||
if (this.item_data.ks_dashboard_item_type === 'ks_list_view'){
|
||||
let params = this.env.ksGetParamsForItemFetch(chart_id);
|
||||
data = {
|
||||
"header": name,
|
||||
"chart_data": typeof this.item_data.ks_list_view_data === 'string' ? this.item_data.ks_list_view_data : JSON.stringify(this.item_data.ks_list_view_data),
|
||||
"ks_item_id": chart_id,
|
||||
"ks_export_boolean": true,
|
||||
"context": context,
|
||||
'params': params,
|
||||
}
|
||||
}else{
|
||||
data = {
|
||||
"header": name,
|
||||
"chart_data": this.item_data.ks_chart_data,
|
||||
}
|
||||
}
|
||||
const blockUI = new BlockUI();
|
||||
await download({
|
||||
url: '/ks_dashboard_ninja/export/' + e.currentTarget.dataset.format,
|
||||
data: {
|
||||
data: JSON.stringify(data)
|
||||
},
|
||||
complete: () => unblockUI,
|
||||
error: (error) => self.call('crash_manager', 'rpc_error', error),
|
||||
});
|
||||
}
|
||||
|
||||
ksChartExportPdf (e){
|
||||
var self = this;
|
||||
var chart_id = this.id;
|
||||
var name = this.item_data.name;
|
||||
var base64_image;
|
||||
base64_image = $($(e.target).parentsUntil(".grid-stack-item").slice(-1)[0]).find('.ks_chart_card_body')[0]
|
||||
var $ks_el = $($($(self.props.itemRootRef.el).find(".grid-stack-item[gs-id=" + chart_id + "]")).find('.ks_chart_card_body'));
|
||||
var ks_height = $ks_el.height()
|
||||
html2canvas(base64_image, {useCORS: true, allowTaint: false}).then(function(canvas){
|
||||
var ks_image = canvas.toDataURL("image/png");
|
||||
var ks_image_def = {
|
||||
content: [{
|
||||
image: ks_image,
|
||||
width: 500,
|
||||
height: ks_height > 750 ? 750 : ks_height,
|
||||
}],
|
||||
images: {
|
||||
bee: ks_image
|
||||
}
|
||||
};
|
||||
pdfMake.createPdf(ks_image_def).download(name + '.pdf');
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
ksChartExportimage(e){
|
||||
var self = this;
|
||||
var chart_id = this.id;
|
||||
var name = this.item_data.name;
|
||||
var base64_image
|
||||
base64_image = $($(e.target).parentsUntil(".grid-stack-item").slice(-1)[0]).find(".ks_chart_card_body")[0]
|
||||
html2canvas(base64_image,{useCORS: true, allowTaint: false}).then(function(canvas){
|
||||
var ks_image = canvas.toDataURL("image/png");
|
||||
const link = document.createElement('a');
|
||||
link.href = ks_image;
|
||||
link.download = name + 'png'
|
||||
document.body.appendChild(link);
|
||||
link.click()
|
||||
document.body.removeChild(link);
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
async ksItemExportJson(e) {
|
||||
var itemId = this.id;
|
||||
var name = this.item_data.name;
|
||||
var data = { 'header': name, item_id: itemId, }
|
||||
const blockUI = new BlockUI();
|
||||
await download({
|
||||
url: '/ks_dashboard_ninja/export/item_json',
|
||||
data: { data: JSON.stringify(data) },
|
||||
complete: () => unblockUI,
|
||||
error: (error) => self.call('crash_manager', 'rpc_error', error),
|
||||
});
|
||||
}
|
||||
|
||||
async openChatWizard(ev){
|
||||
ev.stopPropagation();
|
||||
let internal_chat_thread;
|
||||
let channelId = await rpc("/web/dataset/call_kw/discuss.channel/getId",{
|
||||
model: 'discuss.channel',
|
||||
method: 'ks_chat_wizard_channel_id',
|
||||
args: [[]],
|
||||
kwargs:{
|
||||
item_id: this.id,
|
||||
dashboard_id: this.item_data.ks_dashboard_id,
|
||||
dashboard_name: this.item_data.ks_dashboard_name,
|
||||
item_name: this.item_data.name,
|
||||
}
|
||||
})
|
||||
|
||||
// FIXME : Dont close all chat popover windows . only close those ones belong belongs to dashboard
|
||||
|
||||
|
||||
this.store.chatHub.opened?.forEach?.( (visibleChatWindow) => {
|
||||
visibleChatWindow.close?.()
|
||||
})
|
||||
|
||||
//
|
||||
if(channelId) internal_chat_thread = await this.store.Thread.getOrFetch({ model: "discuss.channel", id: channelId})
|
||||
if(internal_chat_thread){
|
||||
if(internal_chat_thread.name) internal_chat_thread.name = this.item_data.ks_dashboard_name + ' - ' + this.item_data.name
|
||||
internal_chat_thread.open()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onKsDuplicateItemClick(e) {
|
||||
var self = this;
|
||||
var ks_item_id = this.id;
|
||||
var dashboard_id = parseInt(this.selectedDashboardId);
|
||||
var dashboard_name = this.item_data.ks_dashboard_list.filter( (dashboard) => dashboard.id === dashboard_id)[0]?.name;
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/copy",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'copy',
|
||||
args: [ks_item_id, {
|
||||
'ks_dashboard_ninja_board_id': dashboard_id
|
||||
}],
|
||||
kwargs:{},
|
||||
}).then(function(result) {
|
||||
self.env.services.notification.add(_t('Selected item is duplicated to ' + dashboard_name + ' .'),{
|
||||
title:_t("Item Duplicated"), type: 'success', });
|
||||
var js_id = self.env.services.action.currentController.jsId
|
||||
self.env.services.action.restore(js_id)
|
||||
})
|
||||
}
|
||||
|
||||
onKsMoveItemClick(e) {
|
||||
let self = this;
|
||||
let dashboard_id = parseInt(this.selectedDashboardId);
|
||||
let dashboard_name = this.item_data.ks_dashboard_list.filter( (dashboard) => dashboard.id === dashboard_id)[0]?.name;
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/write",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'write',
|
||||
args: [this.id, {
|
||||
'ks_dashboard_ninja_board_id': dashboard_id
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(function(result) {
|
||||
self.env.services.notification.add(_t('Selected item is moved to ' + dashboard_name + ' .'), {
|
||||
title:_t("Item Moved"), type: 'success', });
|
||||
let js_id = self.env.services.action.currentController.jsId
|
||||
self.env.services.action.restore(js_id)
|
||||
});
|
||||
}
|
||||
|
||||
onKsDeleteItemClick(e) {
|
||||
let self = this;
|
||||
let item = $($(e.currentTarget).parentsUntil('.grid-stack').slice(-1)[0])
|
||||
this.env.services.dialog.add(ConfirmationDialog, {
|
||||
body: _t("Are you sure that you want to remove this item?"),
|
||||
confirmLabel: _t("Delete Item"),
|
||||
title: _t("Delete Dashboard Item"),
|
||||
confirm: () => {
|
||||
self.ks_delete_item(self.id , item);
|
||||
},
|
||||
cancel: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
ks_delete_item(id, item) {
|
||||
let self = this;
|
||||
let dashboard_data = self.env.getDashboardDataAsObj(['ks_item_data'])
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/unlink", {
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'unlink',
|
||||
args: [id],
|
||||
kwargs:{}
|
||||
}).then(function(result) {
|
||||
// Clean Item Remove Process. // TODO
|
||||
// self.ks_remove_update_interval(); // IMPORTANT
|
||||
delete self.props.item_data;
|
||||
self.env.gridStackRootRef.el.gridstack?.removeWidget(item);
|
||||
if (Object.keys(dashboard_data.ks_item_data).length > 0) {
|
||||
self._ksSaveCurrentLayout();
|
||||
}
|
||||
let js_id = self.env.services.action.currentController.jsId
|
||||
self.env.services.action.restore(js_id)
|
||||
});
|
||||
}
|
||||
|
||||
_ksSaveCurrentLayout() {
|
||||
let self = this;
|
||||
let grid_config = ks_get_current_gridstack_config(this.env.gridStackRootRef.el);
|
||||
let dashboard_data = self.env.getDashboardDataAsObj(['ks_gridstack_config_id'])
|
||||
let model = 'ks_dashboard_ninja.child_board';
|
||||
let rec_id = dashboard_data.ks_gridstack_config_id;
|
||||
|
||||
if (!isMobileOS()) {
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.child_board/write",{
|
||||
model: model,
|
||||
method: 'write',
|
||||
args: [rec_id, {
|
||||
"ks_gridstack_config": JSON.stringify(grid_config)
|
||||
}],
|
||||
kwargs:{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ksRenderChartColorOptions(e) {
|
||||
let self = this;
|
||||
// FIXME : Correct this later.
|
||||
this.__owl__.parent.component.ksRenderChartColorOptions(e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
.ks_dashboard_menu_container {
|
||||
&.form-control.form-input-box.encapsulated-form-arrow {
|
||||
width: auto !important;
|
||||
|
||||
&::after {
|
||||
top: 41% !important;
|
||||
right: 13px !important;
|
||||
}
|
||||
|
||||
select {
|
||||
font-size: $font-14;
|
||||
/* width: 100%; */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
justify-content: center;
|
||||
|
||||
.dash-btn-red {
|
||||
font-size: $font-12 !important;
|
||||
font-weight: $f-w-600;
|
||||
min-height: 32px !important;
|
||||
height: 100%;
|
||||
margin-right: 8px;
|
||||
padding: 0 12px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="ks_dashboard_ninja.ks_chart_buttons">
|
||||
<div t-att-class=" common_classes + props.item_classes"
|
||||
t-if="showButtons" t-att-data-item_id="id" t-on-click.stop="handleDropdowns" t-ref="rootRef">
|
||||
<t t-if="item_data.ksIsDashboardManager">
|
||||
<div class="ks_chart_inner_buttons" t-if="chart_list.includes(item_data.ks_dashboard_item_type) && !isMobile">
|
||||
<button title="Color Palette" data-bs-toggle="dropdown"
|
||||
class="ks_dashboard_item_action ks_dashboard_color_option dropdown-toggle o-no-caret img-bg hover-item me-2"
|
||||
type="button" aria-expanded="true">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/brush.svg" alt="create" class="img-fluid" loading="lazy"/>
|
||||
</button>
|
||||
<ul role="menu" class="dropdown-menu ks-dropdown-menu dropdown-menu-right ks_color_pallate"
|
||||
t-att-data-item-id="id"
|
||||
t-att-data-chart-type="chart_type" t-att-data-chart-family="chart_family">
|
||||
<t t-foreach="ksChartColorOptions" t-as="color_option" t-key="color_option_index">
|
||||
<li t-att-class="'ks_li_'+color_option">
|
||||
<span t-att-class="color_option + ' ks_chart_color_options'"
|
||||
t-att-data-chart-color="color_option" t-on-click="ksRenderChartColorOptions">
|
||||
<t t-esc="color_option"/>
|
||||
</span>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="ks_chart_inner_buttons">
|
||||
<button title="Move/Duplicate" data-bs-toggle="dropdown" t-if="!isMobile"
|
||||
class="ks_dashboard_item_action dropdown-toggle img-bg hover-item me-2" type="button"
|
||||
aria-expanded="true" t-att-style="'color:'+ ks_button_color + ';'">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.59351 3.92004H3.40682C2.26682 3.92004 1.3335 4.85337 1.3335 5.99337V13.5667C1.3335 14.5334 2.02683 14.9467 2.87349 14.4734L5.49349 13.0134C5.77349 12.86 6.22683 12.86 6.50016 13.0134L9.12016 14.4734C9.96682 14.9467 10.6602 14.5334 10.6602 13.5667V5.99337C10.6668 4.85337 9.73351 3.92004 8.59351 3.92004Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.6668 5.99337V13.5667C10.6668 14.5334 9.9735 14.94 9.12683 14.4734L6.50684 13.0134C6.22684 12.86 5.77349 12.86 5.49349 13.0134L2.87349 14.4734C2.02683 14.94 1.3335 14.5334 1.3335 13.5667V5.99337C1.3335 4.85337 2.26682 3.92004 3.40682 3.92004H8.59351C9.73351 3.92004 10.6668 4.85337 10.6668 5.99337Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M14.6668 3.4067V10.98C14.6668 11.9467 13.9735 12.3534 13.1268 11.8867L10.6668 10.5134V5.99337C10.6668 4.85337 9.73351 3.92004 8.59351 3.92004H5.3335V3.4067C5.3335 2.2667 6.26682 1.33337 7.40682 1.33337H12.5935C13.7335 1.33337 14.6668 2.2667 14.6668 3.4067Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<ul role="menu" class="ks_dashboard_menu_container form-input-box form-control encapsulated-form-arrow dropdown-menu ks-dropdown-menu dropdown-menu-right">
|
||||
<li class="ks_md_heading m-2">
|
||||
<span>Select Dashboard</span>
|
||||
</li>
|
||||
<li class="m-2" t-on-click.stop="() => {}">
|
||||
<select class="o_input o_group_selector o_add_group ks_dashboard_select" t-model="this.selectedDashboardId">
|
||||
<t t-foreach="item_data.ks_dashboard_list" t-as="ks_dashboard"
|
||||
t-key="ks_dashboard_index">
|
||||
<option t-att-value="ks_dashboard['id']">
|
||||
<t t-esc="ks_dashboard['name']"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</li>
|
||||
<li class="m-2">
|
||||
<button class="dash-btn-red o_apply_group o_add_group ks_duplicate_item" t-on-click="onKsDuplicateItemClick"
|
||||
tabindex="-1" type="button">Duplicate
|
||||
</button>
|
||||
<button class="dash-btn-red o_apply_group o_add_group ks_move_item"
|
||||
tabindex="-1" type="button" t-on-click="onKsMoveItemClick">Move
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button title="Quick Customize" t-if="!isMobile" t-on-click="onEditItemTypeClick"
|
||||
class="ks_dashboard_quick_edit_action_popup d-sm-block d-none img-bg hover-item me-2"
|
||||
type="button" t-att-data-item-id="id" t-att-style="'color:'+ ks_button_color + ';'">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</t>
|
||||
<div class="ks_chart_inner_buttons dropdown">
|
||||
<button title="Info" data-bs-toggle="dropdown"
|
||||
class="ks_item_description dropdown-toggle o-no-caret img-bg hover-item me-2"
|
||||
type="button" t-att-style="'color:'+ ks_button_color + ';'"
|
||||
aria-expanded="true">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00004 14.6667C11.6667 14.6667 14.6667 11.6667 14.6667 8.00004C14.6667 4.33337 11.6667 1.33337 8.00004 1.33337C4.33337 1.33337 1.33337 4.33337 1.33337 8.00004C1.33337 11.6667 4.33337 14.6667 8.00004 14.6667Z" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 5.33337V8.66671" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M7.99646 10.6666H8.00245" stroke="currentColor" stroke-width="1.33333" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div role="menu" class="dropdown-menu ks-dropdown-menu dropdown-menu-right" style="width:20rem">
|
||||
<div class="ks_chart_export_menu">
|
||||
<div class="ks_chart_export_menu_header" style="margin-left:-10px">
|
||||
<span>Info</span>
|
||||
</div>
|
||||
<div class="ks_info" style="margin-left:10px">
|
||||
<span>Company: <t t-esc="ks_company"/></span>
|
||||
</div>
|
||||
<div class="ks_info" style="margin-left:10px">
|
||||
<t t-if="item_data.ks_info">
|
||||
<t t-foreach="ks_item_description_list" t-as="ks_description" t-key="ks_description_index">
|
||||
<span><t t-esc="ks_description"/></span> <br/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="isExportListVisible" class="ks_chart_inner_buttons ks_dashboard_more_action" t-att-data-item-id="id">
|
||||
<button title="Export Chart" data-bs-toggle="dropdown"
|
||||
class="ks_dashboard_item_action dropdown-toggle o-no-caret img-bg hover-item me-2"
|
||||
type="button"
|
||||
aria-expanded="true">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/document-upload.svg" alt="document-upload"
|
||||
class="img-fluid" loading="lazy"/>
|
||||
</button>
|
||||
<div role="menu" class="dropdown-menu ks-dropdown-menu dropdown-menu-right">
|
||||
<!--Dynamic Rendering-->
|
||||
<t t-call="ksMoreChartOptions"/>
|
||||
</div>
|
||||
</div>
|
||||
<div t-if="item_data.ksIsDashboardManager" class="ks_chart_inner_buttons ks_dashboard_more_action">
|
||||
<button title="More" data-bs-toggle="dropdown" type="button" aria-expanded="true"
|
||||
class="ks_dashboard_item_action dropdown-toggle img-bg hover-item me-2" t-att-style="'color:'+ ks_button_color + ';'">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.2916 15.8333C12.2916 17.1 11.2666 18.125 9.99992 18.125C8.73325 18.125 7.70825 17.1 7.70825 15.8333C7.70825 14.5667 8.73325 13.5417 9.99992 13.5417C11.2666 13.5417 12.2916 14.5667 12.2916 15.8333ZM8.95825 15.8333C8.95825 16.4083 9.42492 16.875 9.99992 16.875C10.5749 16.875 11.0416 16.4083 11.0416 15.8333C11.0416 15.2583 10.5749 14.7917 9.99992 14.7917C9.42492 14.7917 8.95825 15.2583 8.95825 15.8333Z" fill="currentColor"/>
|
||||
<path d="M12.2916 4.16671C12.2916 5.43337 11.2666 6.45837 9.99992 6.45837C8.73325 6.45837 7.70825 5.43337 7.70825 4.16671C7.70825 2.90004 8.73325 1.87504 9.99992 1.87504C11.2666 1.87504 12.2916 2.90004 12.2916 4.16671ZM8.95825 4.16671C8.95825 4.74171 9.42492 5.20837 9.99992 5.20837C10.5749 5.20837 11.0416 4.74171 11.0416 4.16671C11.0416 3.59171 10.5749 3.12504 9.99992 3.12504C9.42492 3.12504 8.95825 3.59171 8.95825 4.16671Z" fill="currentColor"/>
|
||||
<path d="M12.2916 9.99996C12.2916 11.2666 11.2666 12.2916 9.99992 12.2916C8.73325 12.2916 7.70825 11.2666 7.70825 9.99996C7.70825 8.73329 8.73325 7.70829 9.99992 7.70829C11.2666 7.70829 12.2916 8.73329 12.2916 9.99996ZM8.95825 9.99996C8.95825 10.575 9.42492 11.0416 9.99992 11.0416C10.5749 11.0416 11.0416 10.575 11.0416 9.99996C11.0416 9.42496 10.5749 8.95829 9.99992 8.95829C9.42492 8.95829 8.95825 9.42496 8.95825 9.99996Z" fill="currentColor"/>
|
||||
</svg>
|
||||
</button>
|
||||
<div role="menu" class="ks_chart_export_menu dropdown-menu ks-dropdown-menu dropdown-menu-right">
|
||||
<div t-if="!isExportListVisible" class="ks_chart_json_export ks_chart_export_menu_item d-flex align-items-center"
|
||||
t-att-data-item-id="id" data-format="chart_xls" t-on-click="ksItemExportJson">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/document-upload.svg" alt="document-upload" class="img-fluid" loading="lazy"/>
|
||||
<span>Export Item</span>
|
||||
</div>
|
||||
<div class="d-flex g-10 align-items-center">
|
||||
<button class="ks_dashboard_item_delete img-bg hover-item me-2 kpi-tile-img" title="Remove Item" type="button" t-on-click="onKsDeleteItemClick">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" class="me-1" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" fill="#241C1D"/>
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.66699 3.31337L5.81366 2.44004C5.92033 1.80671 6.00033 1.33337 7.12699 1.33337H8.87366C10.0003 1.33337 10.087 1.83337 10.187 2.44671L10.3337 3.31337" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.5669 6.09338L12.1336 12.8067C12.0603 13.8534 12.0003 14.6667 10.1403 14.6667H5.86026C4.00026 14.6667 3.94026 13.8534 3.86693 12.8067L3.43359 6.09338" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88672 11H9.10672" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.33301 8.33337H9.66634" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg> Remove
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex g-10 align-items-center" t-if="!isMobile && item_data.ks_dashboard_item_type !== 'ks_to_do'">
|
||||
<button id='ks_ai_item_exp_dash' class="img-bg hover-item me-2 kpi-tile-img"
|
||||
t-on-click="_onButtonClick" title="AI provides the insights of the item">
|
||||
<img src="/ks_dashboard_ninja/static/images/favorite-chart.svg" alt="create" class="img-fluid" loading="lazy"/>
|
||||
Explain With AI
|
||||
</button>
|
||||
</div>
|
||||
<div class="d-flex g-10 align-items-center" t-if="!isMobile">
|
||||
<button class="ks_dashboard_item_chatter_wizard img-bg hover-item me-2 kpi-tile-img" title="Channel" type="button" t-on-click="openChatWizard">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/messages.svg" alt="messages" class="img-fluid" loading="lazy"/>
|
||||
Chat
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ksMoreChartOptions">
|
||||
<div class="ks_chart_export_menu">
|
||||
<div class="ks_chart_xls_csv_export ks_chart_export_menu_item" t-on-click="ksChartExportXlsCsv"
|
||||
t-att-data-chart-id="id" t-att-data-format="item_data.ks_dashboard_item_type === 'ks_list_view' ? 'list_xls' : 'chart_xls'">
|
||||
<i class="fa fa-file-excel-o"/>
|
||||
<span>Export to Excel</span>
|
||||
</div>
|
||||
<div class="ks_chart_xls_csv_export ks_chart_export_menu_item" t-on-click="ksChartExportXlsCsv"
|
||||
t-att-data-chart-id="id" t-att-data-format="item_data.ks_dashboard_item_type === 'ks_list_view' ? 'list_csv' : 'chart_csv'">
|
||||
<i class="fa fa-file-code-o"/>
|
||||
<span>Export to CSV</span>
|
||||
</div>
|
||||
|
||||
<div t-if="item_data.ks_dashboard_item_type != 'ks_list_view'" t-att-data-chart-id="id"
|
||||
class="ks_chart_pdf_export ks_chart_export_menu_item" t-on-click="ksChartExportPdf">
|
||||
<i class="fa fa-file-pdf-o"/>
|
||||
<span>Save as PDF</span>
|
||||
</div>
|
||||
<div t-if="item_data.ks_dashboard_item_type != 'ks_list_view'" t-att-data-chart-id="id"
|
||||
class="ks_chart_export_menu_item ks_chart_image_export" t-on-click="ksChartExportimage">
|
||||
<i class="fa fa-file-image-o"/>
|
||||
<span>Save as Image</span>
|
||||
</div>
|
||||
<div class="ks_chart_json_export ks_chart_export_menu_item" t-on-click="ksItemExportJson"
|
||||
t-att-data-item-id="item_id" data-format="chart_xls">
|
||||
<i class="fa fa-file-code-o"/>
|
||||
<span>Export Item</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,149 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Component, useState, useRef, useChildSubEnv } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs'
|
||||
import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_tile_view/ks_dashboard_tile';
|
||||
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||
import { ks_render_graphs, ksrenderfunnelchart } from "@ks_dashboard_ninja/js/charts_render_global_functions";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
export class CustomDialog extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.dialogService = useService("dialog");
|
||||
this.graphRef = useRef("graph_div");
|
||||
this.ks_question = useRef("ks_question")
|
||||
this.user = user.name;
|
||||
this.name_title = this.user.split(' ').length>1 ? this.user.split(' ')[0].charAt(0)+this.user.split(' ')[1].charAt(0):this.user.split(' ')[0].charAt(0);
|
||||
this.dashboard_container = useRef("ks_gridstack_container");
|
||||
this._rpc = rpc
|
||||
this.notification = useService("notification");
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.state = useState({
|
||||
explain_ai: true,
|
||||
newItem: this.props.item.ks_dashboard_item_type,
|
||||
chart_ks_dashboard_id: this.props.item.ks_dashboard_id,
|
||||
toggleState: true,
|
||||
confirm_notification: false,
|
||||
messages: [ { sender: 'ai', text: 'Hello I am AI Assistant, How may i help you ?' } ],
|
||||
confirm_notification: false,
|
||||
switch_layout: false,
|
||||
});
|
||||
|
||||
useChildSubEnv({
|
||||
ksGetParamsForItemFetch: (item_id) => this.props.getDomainParams(item_id),
|
||||
getContext : this.props.getDashboardContext,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
switch_bar_chart(new_item) {
|
||||
this.ks_item = Object.assign({},this.props.item)
|
||||
this.ks_item['ks_dashboard_item_type'] = new_item
|
||||
$(this.graphRef.el).find('.ks_chart_card_body').remove();
|
||||
if(new_item == 'ks_funnel_chart'){
|
||||
ksrenderfunnelchart.bind(this)($(this.graphRef.el), this.ks_item, 'dashboard_view');
|
||||
}
|
||||
else{
|
||||
ks_render_graphs.bind(this)($(this.graphRef.el), this.ks_item, this.props.dashboard_data?.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
this.state.newItem = new_item;
|
||||
this.state.switch_layout = true;
|
||||
}
|
||||
|
||||
ks_switch_layout() {
|
||||
var self =this
|
||||
let selectedItem = this.state.newItem;
|
||||
let item_data = this.props.item
|
||||
let item_id = this.props.item.id
|
||||
let chart_id = this.state.chart_ks_dashboard_id;
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/write",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'write',
|
||||
args: [item_id, {
|
||||
'ks_dashboard_item_type': selectedItem,
|
||||
...( (selectedItem === 'ks_funnel_chart' && item_data.ks_chart_measure_field.length ) && {
|
||||
'ks_funnel_record_field' : item_data.ks_chart_measure_field[0] })
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(function(result) {
|
||||
self.props.item.ks_dashboard_item_type = self.state.newItem
|
||||
self.props.current_graph.item.ks_dashboard_item_type = selectedItem;
|
||||
self.props.current_graph.ksFetchUpdateItem(item_id, chart_id, {})
|
||||
})
|
||||
.then(() => {
|
||||
self.state.confirm_notification = JSON.parse(JSON.stringify(true));
|
||||
});
|
||||
}
|
||||
ks_key_check(ev){
|
||||
if (ev.keyCode == 13){
|
||||
this.ks_send_request(ev);
|
||||
}
|
||||
}
|
||||
ks_send_request(ev){
|
||||
let self = this;
|
||||
ev.stopPropagation();
|
||||
let user_question= $(this.ks_question.el).val()
|
||||
let user_obj = {sender:"user",text:user_question}
|
||||
this.state.messages = [...this.state.messages,user_obj,{sender:'ai',text:'loading'}]
|
||||
$(this.ks_question.el).val('')
|
||||
rpc('/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_gen_chat_res',{
|
||||
model:'ks_dashboard_ninja.arti_int',
|
||||
method:'ks_gen_chat_res',
|
||||
args:[],
|
||||
kwargs:{ks_question:user_question}
|
||||
}).then((result)=>{
|
||||
if (result['Answer']){
|
||||
let answer = result['Answer'].split('\n').join('')
|
||||
self.state.messages.pop()
|
||||
self.state.messages.push({sender:'ai',text:answer})
|
||||
}else{
|
||||
self.state.messages.pop()
|
||||
self.state.messages.push({sender:'ai',text:'AI unable to Generate Response'})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
closeNotification(){
|
||||
this.state.confirm_notification = false;
|
||||
}
|
||||
|
||||
onChartCanvasClick_funnel(){}
|
||||
|
||||
}
|
||||
CustomDialog.props = {
|
||||
title: { type: String, optional:true},
|
||||
ks_dashboard_manager: { type: Boolean, optional: true },
|
||||
ks_dashboard_items: Object,
|
||||
ks_dashboard_data: Object,
|
||||
ks_dashboard_item_type: { type: String, optional: true },
|
||||
ksdatefilter: { type: String, optional: true },
|
||||
pre_defined_filter: { type:Object, optional:true},
|
||||
custom_filter: { type:Object, optional:true},
|
||||
dashboard_data: Object,
|
||||
item: { type: Object, optional: true },
|
||||
ks_speak: { type: Function, optional: true },
|
||||
ksDateFilterSelection: { type: String, optional: true },
|
||||
close: { type: Function, optional: true },
|
||||
hideButtons: { type: Number, optional: true },
|
||||
update_graph: { type: Function, optional: true },
|
||||
current_graph: { type: Object, optional: true },
|
||||
getDomainParams: { type: Function, optional: true },
|
||||
getDashboardContext: { type: Function, optional: true }
|
||||
}
|
||||
|
||||
|
||||
CustomDialog.components = { Dialog, Ksdashboardgraph, Ksdashboardtile, Ksdashboardkpiview, Ksdashboardtodo };
|
||||
|
||||
CustomDialog.template = "ks_dashboard_ninja.CustomDialog";
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
.ks-common-tab-pills {
|
||||
.nav {
|
||||
border-bottom: 1px solid $color-E5E7EB !important;
|
||||
|
||||
.nav-link {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0.01em;
|
||||
text-align: left;
|
||||
color: $color-paragraph !important;
|
||||
padding: 16px !important;
|
||||
|
||||
&:hover {
|
||||
transition: 0.2s linear;
|
||||
transform: scale(1.1);
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: $color-black;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $color-E7495E !important;
|
||||
background-color: $color-white;
|
||||
border-bottom: 2px solid $color-E7495E;
|
||||
border-radius: 0 !important;
|
||||
transition: 0.2s linear;
|
||||
transform: scale(1.1);
|
||||
cursor: pointer !important;
|
||||
|
||||
svg {
|
||||
stroke: $color-E7495E;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.share-switch {
|
||||
.bg-F5F8FB {
|
||||
background-color: $color-bg-main;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.expalin-content-box {
|
||||
// border: 1px solid $color-E5E7EB;
|
||||
// background-color: $color-bg-main;
|
||||
min-height: 581px;
|
||||
border-radius: 20px;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 22.4px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
|
||||
@include max-992 {
|
||||
font-size: $font-12;
|
||||
}
|
||||
}
|
||||
|
||||
.description-box {
|
||||
max-height: 500px;
|
||||
overflow: auto;
|
||||
@include custom-scrollbar;
|
||||
|
||||
@include max-992 {
|
||||
max-height: calc(100vh - 387px);
|
||||
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 19.2px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.chart-insight-tooltip-container {
|
||||
position: fixed;
|
||||
bottom: 30px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
z-index: 30;
|
||||
|
||||
.tooltip-box {
|
||||
box-shadow: 0px 4px 40px 0px #DBCACA80;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
background-color: $color-white;
|
||||
|
||||
|
||||
.tooltip-content {
|
||||
margin-right: 20px;
|
||||
height: 69;
|
||||
width: 100px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-title {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 33.6px;
|
||||
text-align: left;
|
||||
color: $color-paragraph;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ks-chart-insight {
|
||||
border: 1.63px solid $color-E5E7EB;
|
||||
min-height: 579px;
|
||||
box-shadow: 0px 6.05px 30.23px 0px #EEEEEE80;
|
||||
border-radius: 30px;
|
||||
padding: 8px;
|
||||
|
||||
h4 {
|
||||
font-size: $font-20;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 48.38px;
|
||||
text-align: left;
|
||||
color: $color-05004E;
|
||||
|
||||
@include max-992 {
|
||||
font-size: $font-14;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-img {
|
||||
height: 462px;
|
||||
width: 100%;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="ks_dashboard_ninja.CustomDialog">
|
||||
<Dialog title="'Chart Insights'" footer="false">
|
||||
<div class="container-fluid">
|
||||
<div class="row" style="min-height: 60vh;">
|
||||
<div class="col-6 d-flex flex-column align-items-stretch chat_explain_ai">
|
||||
<t t-if="props.ks_dashboard_item_type === 'ks_tile'">
|
||||
<Ksdashboardtile item="props.item"
|
||||
dashboard_data="props.dashboard_data"
|
||||
ksdatefilter="props.ksdatefilter"
|
||||
pre_defined_filter="props.pre_defined_filter"
|
||||
custom_filter="props.custom_filter"
|
||||
hideButtons="0"
|
||||
on_dialog="true"
|
||||
onItemClick="() => {} "
|
||||
itemsToUpdateList="[]"
|
||||
ks_speak="props.ks_speak"/>
|
||||
</t>
|
||||
<t t-elif="props.ks_dashboard_item_type === 'ks_kpi'">
|
||||
<Ksdashboardkpiview item="props.item"
|
||||
dashboard_data="props.dashboard_data"
|
||||
ksdatefilter="props.ksdatefilter"
|
||||
pre_defined_filter="props.pre_defined_filter"
|
||||
custom_filter="props.custom_filter"
|
||||
hideButtons="0"
|
||||
onItemClick="() => {} "
|
||||
on_dialog="true"
|
||||
itemsToUpdateList="[]"
|
||||
ks_speak="props.ks_speak"/>
|
||||
</t>
|
||||
<t t-elif="props.ks_dashboard_item_type === 'ks_to_do'">
|
||||
<Ksdashboardtodo item="props.item"
|
||||
dashboard_data="props.dashboard_data"
|
||||
hideButtons="0"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="props.item.ks_dashboard_item_type != 'ks_list_view'">
|
||||
<div class="ks-common-tab-pills">
|
||||
<ul class="nav nav-pills mb-3 border-bottom border-2" id="pills-tab" role="tablist">
|
||||
<t t-set="chart_name" t-value="props.ks_dashboard_item_type"/>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button t-attf-class="nav-link text-primary fw-semibold position-relative #{chart_name =='ks_bar_chart'?'show active':''}"
|
||||
id="pills-home-tab" data-bs-toggle="pill" data-bs-target="#pills-one" type="button"
|
||||
role="tab" aria-controls="pills-home" aria-selected="true"
|
||||
t-on-click="()=>this.switch_bar_chart('ks_bar_chart')">
|
||||
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.5 18.3334H17.5" stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M4.66665 6.9834H3.33333C2.875 6.9834 2.5 7.3584 2.5 7.81673V15.0001C2.5 15.4584 2.875 15.8334 3.33333 15.8334H4.66665C5.12498 15.8334 5.49998 15.4584 5.49998 15.0001V7.81673C5.49998 7.3584 5.12498 6.9834 4.66665 6.9834Z"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M10.6666 4.32507H9.33333C8.875 4.32507 8.5 4.70007 8.5 5.15841V15.0001C8.5 15.4584 8.875 15.8334 9.33333 15.8334H10.6666C11.125 15.8334 11.5 15.4584 11.5 15.0001V5.15841C11.5 4.70007 11.125 4.32507 10.6666 4.32507Z"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M16.6666 1.66675H15.3333C14.875 1.66675 14.5 2.04175 14.5 2.50008V15.0001C14.5 15.4584 14.875 15.8334 15.3333 15.8334H16.6666C17.125 15.8334 17.5 15.4584 17.5 15.0001V2.50008C17.5 2.04175 17.125 1.66675 16.6666 1.66675Z"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button t-attf-class="nav-link text-primary fw-semibold position-relative #{chart_name =='ks_area_chart'?'show active':''}"
|
||||
id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="#pills-two"
|
||||
type="button" role="tab" aria-controls="pills-profile" aria-selected="false"
|
||||
t-on-click="()=>this.switch_bar_chart('ks_area_chart')">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M7.50033 18.3333L12.5003 18.3333C16.667 18.3333 18.3337 16.6666 18.3337 12.5L18.3337 7.49996C18.3337 3.33329 16.667 1.66663 12.5003 1.66663L7.50033 1.66663C3.33366 1.66663 1.66699 3.33329 1.66699 7.49996L1.66699 12.5C1.66699 16.6666 3.33366 18.3333 7.50033 18.3333Z"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M6.1084 12.075L8.09173 9.50005C8.37507 9.13338 8.90007 9.06672 9.26673 9.35005L10.7917 10.55C11.1584 10.8334 11.6834 10.7667 11.9667 10.4084L13.8917 7.92505"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button t-attf-class="nav-link text-primary fw-semibold position-relative #{chart_name =='ks_pie_chart'?'show active':''}"
|
||||
id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="#pills-three"
|
||||
type="button" role="tab" aria-controls="pills-profile" aria-selected="false"
|
||||
t-on-click="()=>this.switch_bar_chart('ks_pie_chart')">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M15.2667 10.0002C17.4333 10.0002 18.3333 9.16686 17.5333 6.43352C16.9917 4.59186 15.4083 3.00852 13.5667 2.46686C10.8333 1.66686 10 2.56686 10 4.73352V7.13352C10 9.16686 10.8333 10.0002 12.5 10.0002H15.2667Z"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M16.6672 12.2498C15.8922 16.1081 12.1922 18.9081 7.98384 18.2248C4.82551 17.7164 2.28384 15.1748 1.76718 12.0164C1.09218 7.82476 3.87551 4.12476 7.71718 3.34143"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button t-attf-class="nav-link text-primary fw-semibold position-relative #{chart_name =='ks_radialBar_chart'?'show active':''}"
|
||||
id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="#pills-four"
|
||||
type="button" role="tab" aria-controls="pills-profile" aria-selected="false"
|
||||
t-on-click="()=>this.switch_bar_chart('ks_radialBar_chart')">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.35033 4.97496C2.29199 6.37496 1.66699 8.11663 1.66699 9.99996C1.66699 14.6 5.40033 18.3333 10.0003 18.3333C14.6003 18.3333 18.3337 14.6 18.3337 9.99996C18.3337 5.39996 14.6003 1.66663 10.0003 1.66663"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M4.16699 9.99996C4.16699 13.225 6.77533 15.8333 10.0003 15.8333C13.2253 15.8333 15.8337 13.225 15.8337 9.99996C15.8337 6.77496 13.2253 4.16663 10.0003 4.16663"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M10 13.3333C11.8417 13.3333 13.3333 11.8416 13.3333 9.99996C13.3333 8.15829 11.8417 6.66663 10 6.66663"
|
||||
stroke="" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button t-attf-class="nav-link text-primary fw-semibold position-relative #{chart_name =='ks_funnel_chart'?'show active':''}"
|
||||
id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="#pills-five"
|
||||
type="button" role="tab" aria-controls="pills-profile" aria-selected="false"
|
||||
t-on-click="()=>this.switch_bar_chart('ks_funnel_chart')">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M4.50065 1.75H15.5007C16.4173 1.75 17.1673 2.5 17.1673 3.41667V5.25C17.1673 5.91667 16.7507 6.75 16.334 7.16667L12.7507 10.3333C12.2507 10.75 11.9173 11.5833 11.9173 12.25V15.8333C11.9173 16.3333 11.584 17 11.1673 17.25L10.0007 18C8.91732 18.6667 7.41732 17.9167 7.41732 16.5833V12.1667C7.41732 11.5833 7.08398 10.8333 6.75065 10.4167L3.58398 7.08333C3.16732 6.66667 2.83398 5.91667 2.83398 5.41667V3.5C2.83398 2.5 3.58398 1.75 4.50065 1.75Z"
|
||||
stroke="" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M9.10833 1.75L5 8.33333" stroke="" stroke-width="1.25"
|
||||
stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
<div class="flex-grow-1 ks-chart-insight position-relative" t-ref="graph_div">
|
||||
<Ksdashboardgraph item="props.item"
|
||||
dashboard_data="props.dashboard_data"
|
||||
ksdatefilter="props.ksdatefilter"
|
||||
pre_defined_filter="props.pre_defined_filter"
|
||||
custom_filter="props.custom_filter"
|
||||
hideButtons="0" onItemClick="() => {} " itemsToUpdateList="[]"
|
||||
ks_speak="props.ks_speak"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div id="explain_ai" class="col-6 d-flex1 flex-column" style="min-height: 100%;">
|
||||
<t t-if="state.switch_layout">
|
||||
<t t-if="props.ks_dashboard_item_type != 'ks_to_do' and props.ks_dashboard_item_type != 'ks_kpi' and props.ks_dashboard_item_type != 'ks_tile' and props.item.ks_dashboard_item_type != 'ks_list_view' and props.item.ks_dashboard_item_type != state.newItem">
|
||||
<div class="share-switch d-flex justify-content-end align-items-center p-3">
|
||||
<button class="dash-btn-red d-flex justify-content-center align-items-center me-2"
|
||||
t-on-click="()=>this.ks_switch_layout()" title="Switch chart on Dashboard">
|
||||
<span class="me-2">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10.7673 1.88333L16.1923 4.80833C16.8257 5.14999 16.8257 6.12499 16.1923 6.46666L10.7673 9.39166C10.284 9.64999 9.71732 9.64999 9.23398 9.39166L3.80898 6.46666C3.17565 6.12499 3.17565 5.14999 3.80898 4.80833L9.23398 1.88333C9.71732 1.62499 10.284 1.62499 10.7673 1.88333Z"
|
||||
stroke="#FFF" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M3.00768 8.44161L8.04935 10.9666C8.67435 11.2833 9.07435 11.9249 9.07435 12.6249V17.3916C9.07435 18.0833 8.34935 18.5249 7.73268 18.2166L2.69102 15.6916C2.06602 15.3749 1.66602 14.7333 1.66602 14.0333V9.26661C1.66602 8.57494 2.39102 8.13327 3.00768 8.44161Z"
|
||||
stroke="#FFF" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
d="M16.9924 8.44161L11.9508 10.9666C11.3258 11.2833 10.9258 11.9249 10.9258 12.6249V17.3916C10.9258 18.0833 11.6508 18.5249 12.2674 18.2166L17.3091 15.6916C17.9341 15.3749 18.3341 14.7333 18.3341 14.0333V9.26661C18.3341 8.57494 17.6091 8.13327 16.9924 8.44161Z"
|
||||
stroke="#FFF" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
||||
</span>
|
||||
<span>Switch Layout</span>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<div class="expalin-content-box">
|
||||
<div class="d-flex justify-content-between align-items-center px-3 pt-3">
|
||||
<div class="title"><t t-esc="state.explain_ai? '': 'Chat with AI'"/></div>
|
||||
|
||||
</div>
|
||||
<t t-if="state.explain_ai">
|
||||
<div class="explain-ai-box px-3">
|
||||
<div class="description-box mt-4">
|
||||
<t t-esc="props.item.ks_ai_analysis"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="chat-ai-box px-3">
|
||||
<div class="chat-sec mt-4">
|
||||
<t t-foreach="state.messages" t-as="message" t-key="message_index">
|
||||
<t t-if="message.sender == 'ai'">
|
||||
<div class="left">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="ai-icon me-2">
|
||||
<img src="/ks_dashboard_ninja/static/images/ai-icon.png" alt="ai-assistant" class="img-fluid"
|
||||
loading="lazy"/>
|
||||
</span>
|
||||
<span class="title">AI Assistant</span>
|
||||
</div>
|
||||
<div class="answers">
|
||||
<t t-if="message.text == 'loading'">
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="background:#e7495e;"></span>
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="margin-left:5px;background:#e7495e;"></span>
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="margin-left:5px;background:#e7495e;"></span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-esc="message.text"/>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="right my-4 py-2">
|
||||
<div class="d-flex align-items-center mb-3 justify-content-end">
|
||||
<span class="title"><t t-esc="this.user"/></span>
|
||||
<span
|
||||
class="user-icon ms-2 d-flex justify-content-center align-items-center">
|
||||
<t t-esc="this.name_title"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="questions text-end">
|
||||
<t t-esc="message.text"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="typer-box">
|
||||
<form class="typer d-flex align-items-end">
|
||||
<textarea name="" id="" placeholder="Chat with AI..." t-ref="ks_question" t-on-keyup="(ev)=>this.ks_key_check(ev)"/>
|
||||
<button class="chat-logo" t-on-click="ks_send_request">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5.54977 4.73999L11.9173 2.61749C14.7748 1.66499 16.3273 3.22499 15.3823 6.08249L13.2598 12.45C11.8348 16.7325 9.49477 16.7325 8.06977 12.45L7.43977 10.56L5.54977 9.92999C1.26727 8.50499 1.26727 6.17249 5.54977 4.73999Z"
|
||||
stroke="white" stroke-width="1.5" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M7.58203 10.2375L10.267 7.54504L7.58203 10.2375Z"
|
||||
fill="#241C1D" />
|
||||
<path d="M7.58203 10.2375L10.267 7.54504" stroke="white"
|
||||
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="state.confirm_notification">
|
||||
<div class="container chart-insight-tooltip-container">
|
||||
<div class="d-flex align-items-center mx-auto tooltip-box">
|
||||
<div class="tooltip-content">
|
||||
<img src="/ks_dashboard_ninja/static/images/demo-tooltip-img.png" alt="tootltip" class="img-fluid" loading="lazy"/>
|
||||
</div>
|
||||
<h5 class="tooltip-title mb-0">Your Chart has been Successfully Updated</h5>
|
||||
<div class="ms-auto cursor-pointer" t-on-click="closeNotification">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z"
|
||||
stroke="#241C1D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M9.16992 14.83L14.8299 9.17004" stroke="#241C1D" stroke-width="1.5" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M14.8299 14.83L9.16992 9.17004" stroke="#241C1D" stroke-width="1.5" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</Dialog>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,70 @@
|
||||
/**@odoo-module **/
|
||||
import {Component,useState,useRef,onPatched} from "@odoo/owl";
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
export class KschatwithAI extends Component{
|
||||
setup(){
|
||||
this.user = user.name;
|
||||
this.name_title = this.user.split(' ').length>1 ? this.user.split(' ')[0].charAt(0)+this.user.split(' ')[1].charAt(0):this.user.split(' ')[0].charAt(0);
|
||||
this.state = useState({ messages:[{sender:'ai',text:'Hello I am AI Assistant, How may i help you ?',frame:false}]})
|
||||
this.ks_question = useRef("ks_question")
|
||||
onPatched(()=>{
|
||||
$(".chat-sec")[0].scrollTop = $(".chat-sec")[0].scrollHeight
|
||||
});
|
||||
this.send_request = true
|
||||
}
|
||||
ks_key_check(ev){
|
||||
if (ev.keyCode == 13){
|
||||
if (this.send_request == true){
|
||||
this.ks_send_request(ev)
|
||||
}
|
||||
}
|
||||
}
|
||||
ks_send_request(ev){
|
||||
let self = this;
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
let user_question= $(this.ks_question.el).val()
|
||||
if (user_question.length>1 && this.send_request){
|
||||
let user_obj = {sender:"user",text:user_question,frame:false}
|
||||
this.state.messages = [...this.state.messages,user_obj,{sender:'ai',text:'loading',frame:false}]
|
||||
$(this.ks_question.el).val('')
|
||||
this.send_request = false
|
||||
rpc('/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_gen_chat_res',{
|
||||
model:'ks_dashboard_ninja.arti_int',
|
||||
method:'ks_gen_chat_res',
|
||||
args:[],
|
||||
kwargs:{ks_question:user_question}
|
||||
}).then((result)=>{
|
||||
if (result['Answer']){
|
||||
let answer = result['Answer'].split('\n').join('')
|
||||
if (answer.indexOf('Summary')!= -1){
|
||||
answer = answer.slice(0,answer.indexOf('Summary'))
|
||||
}
|
||||
else{
|
||||
answer = answer
|
||||
}
|
||||
self.state.messages.pop()
|
||||
let frame = JSON.parse(result['Dataframe']).length>5? JSON.parse(result['Dataframe']):false;
|
||||
self.state.messages.push({sender:'ai',text:answer,frame})
|
||||
this.send_request = true
|
||||
}else{
|
||||
self.state.messages.pop()
|
||||
self.state.messages.push({sender:'ai',text:'AI unable to Generate Response'})
|
||||
this.send_request = true
|
||||
}
|
||||
})
|
||||
}else{
|
||||
$(this.ks_question.el).val('')
|
||||
let user_obj = {sender:"user",text:user_question,frame:false}
|
||||
let res_obj = {sender:'ai',text:'Either you have not asked any question or AI Unable to generate response',frame:false}
|
||||
this.state.messages = [...this.state.messages,user_obj,res_obj]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
KschatwithAI.components = { Dialog };
|
||||
KschatwithAI.template = "Kschatwithai"
|
||||
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="Kschatwithai">
|
||||
<div id="chatid" class="chart-sec-modal message_with_ai">
|
||||
<Dialog title="'Chat with AI'" footer="false" size="'md'">
|
||||
<div class="chat-ai-box px-3">
|
||||
<div class="chat-sec mt-4">
|
||||
|
||||
<t t-foreach="state.messages" t-as="message" t-key="message_index">
|
||||
<t t-if="message.sender == 'ai'">
|
||||
<div class="left">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="ai-icon me-2">
|
||||
<img src="/ks_dashboard_ninja/static/images/ai-icon.png" alt="ai-assistant" class="img-fluid"
|
||||
loading="lazy"/>
|
||||
</span>
|
||||
<span class="title">Ksolves Assistant</span>
|
||||
</div>
|
||||
<div class="answers">
|
||||
<t t-if="message.text == 'loading'">
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="background:#e7495e;"></span>
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="margin-left:5px;background:#e7495e;"></span>
|
||||
<span class="spinner-grow spinner-grow-sm" role="status" aria-hidden="true" style="margin-left:5px;background:#e7495e;"></span>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-if="!message.frame">
|
||||
<t t-esc="message.text"/>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="message.frame">
|
||||
<p class="answers">Here is your generated table</p>
|
||||
<div class="chart-table-wrapper">
|
||||
<table class="table table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<t t-foreach="Object.keys(message.frame[0])" t-as="header" t-key="header_index">
|
||||
<th>
|
||||
<t t-esc="header"/>
|
||||
</th>
|
||||
</t>
|
||||
</tr>
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="message.frame" t-as="value" t-key="value_index">
|
||||
<tr>
|
||||
<t t-foreach="Object.keys(value)" t-as="item" t-key="item_index">
|
||||
<td>
|
||||
<t t-esc="value[item]"/>
|
||||
</td>
|
||||
</t>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="right my-4 py-2">
|
||||
<div class="d-flex align-items-center mb-3 justify-content-end">
|
||||
<span class="title"><t t-esc="this.user"/></span>
|
||||
<span
|
||||
class="user-icon ms-2 d-flex justify-content-center align-items-center">
|
||||
<t t-esc="this.name_title"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="questions text-end">
|
||||
<t t-esc="message.text"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
<div class="typer-box">
|
||||
<form class="typer d-flex align-items-end">
|
||||
<textarea name="" id="" placeholder="Chat with AI..." t-ref="ks_question" t-on-keyup="(ev)=>this.ks_key_check(ev)"></textarea>
|
||||
<button class="chat-logo" t-on-click="ks_send_request">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M5.54977 4.73999L11.9173 2.61749C14.7748 1.66499 16.3273 3.22499 15.3823 6.08249L13.2598 12.45C11.8348 16.7325 9.49477 16.7325 8.06977 12.45L7.43977 10.56L5.54977 9.92999C1.26727 8.50499 1.26727 6.17249 5.54977 4.73999Z"
|
||||
stroke="white" stroke-width="1.5" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M7.58203 10.2375L10.267 7.54504L7.58203 10.2375Z"
|
||||
fill="#241C1D" />
|
||||
<path d="M7.58203 10.2375L10.267 7.54504" stroke="white"
|
||||
stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,347 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onWillStart, onWillUpdateProps } from "@odoo/owl";
|
||||
import { useLoadFieldInfo } from "@web/core/model_field_selector/utils";
|
||||
import { getDomainDisplayedOperators } from "@web/core/domain_selector/domain_selector_operator_editor";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { useService, useBus } from "@web/core/utils/hooks";
|
||||
import { treeFromDomain, domainFromTree } from "@web/core/tree_editor/condition_tree";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { getOperatorLabel } from "@web/core/tree_editor/tree_editor_operator_editor";
|
||||
import { getDefaultValue, getValueEditorInfo } from "@web/core/tree_editor/tree_editor_value_editors";
|
||||
import { getExpressionDisplayedOperators } from "@web/core/expression_editor/expression_editor_operator_editor";
|
||||
import { KsDropDown } from "@ks_dashboard_ninja/components/custom_filter/ks_dropdown";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { disambiguate } from "@web/core/tree_editor/utils";
|
||||
import { condition, connector } from "@web/core/tree_editor/condition_tree";
|
||||
import { useGetTreeDescription } from "@web/core/tree_editor/utils";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
|
||||
export class CustomFilter extends Component{
|
||||
static props = {
|
||||
domain: { type: String, optional: true },
|
||||
update: { type: Function, optional: true },
|
||||
remove: { type: Function, optional: true },
|
||||
removeAllFilters: { type: Boolean, optional: true },
|
||||
options: { type: Object, optional: true },
|
||||
filter_info: { type: Object, optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
update: () => {},
|
||||
domain: `[]`,
|
||||
filter_info: {},
|
||||
};
|
||||
|
||||
setup(){
|
||||
this.notification = useService("notification");
|
||||
this.loadFieldInfo = useLoadFieldInfo();
|
||||
this.getDomainTreeDescription = useGetTreeDescription();
|
||||
this.state = useState({
|
||||
filtersRowList: [],
|
||||
toggleState: true
|
||||
});
|
||||
this.customDomainFacets = {}
|
||||
this.groupId = 0
|
||||
|
||||
this.domain = this.props.domain
|
||||
this.filter_info = this.props.filter_info
|
||||
|
||||
onWillStart(() => this.willStart());
|
||||
onWillUpdateProps((nextProps) => this.onPropsUpdated(nextProps))
|
||||
}
|
||||
|
||||
onPropsUpdated(nextProps){
|
||||
if(nextProps.removeAllFilters){
|
||||
this.clearFacets_cookies()
|
||||
this.clearRows();
|
||||
}
|
||||
}
|
||||
|
||||
willStart(){
|
||||
this.setObjFromCookies();
|
||||
const filters_list = Object.values(this.props.filter_info)
|
||||
this.loadFieldDefs_and_Labels(filters_list);
|
||||
const defaultOperator = getDomainDisplayedOperators(filters_list[0])[0]
|
||||
|
||||
this.defaultFilterRowObject = {
|
||||
id: filters_list[0].id,
|
||||
operator: defaultOperator,
|
||||
value: getDefaultValue(filters_list[0], defaultOperator),
|
||||
}
|
||||
this.state.filtersRowList.push(JSON.parse(JSON.stringify(this.defaultFilterRowObject)));
|
||||
}
|
||||
|
||||
setObjFromCookies(){
|
||||
let customDomainFacets_from_cky = getObjectFromCookie('CFilter' + this.props.options.ks_dashboard_id)
|
||||
this.customDomainFacets = customDomainFacets_from_cky?.lastAppliedFilters ?? {}
|
||||
this.groupId = customDomainFacets_from_cky?.lastGroupId ?? 0
|
||||
}
|
||||
|
||||
rowFilter(filter_id){
|
||||
let filter = this.props.filter_info[filter_id]
|
||||
return filter.name + ' ( ' + filter.model_name + ' ) '
|
||||
}
|
||||
|
||||
rowOperator(row_index){
|
||||
return getOperatorLabel(this.state.filtersRowList[row_index].operator)
|
||||
}
|
||||
|
||||
// Remove Data from python , we load field defs here
|
||||
async loadFieldDefs_and_Labels(filters_list) {
|
||||
const promises = [];
|
||||
const filter_labels = [];
|
||||
const fieldDefs = {};
|
||||
for (const filter of filters_list) {
|
||||
filter_labels.push({ filter_name: filter.name + ' ( ' + filter.model_name + ' ) ', filter_id: filter.id})
|
||||
if (typeof filter.field_name === "string") {
|
||||
promises.push(
|
||||
this.loadFieldInfo(filter.model, filter.field_name).then(({ fieldDef }) => {
|
||||
fieldDefs[filter.id] = fieldDef;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
await Promise.all(promises);
|
||||
this.fieldDefs = fieldDefs;
|
||||
this.filterLabels = filter_labels
|
||||
}
|
||||
|
||||
getOperatorInfo(filter_id) {
|
||||
const fieldDef = this.fieldDefs[filter_id];
|
||||
const operators = getDomainDisplayedOperators(fieldDef);
|
||||
const operatorList = operators.map((operator) => ({
|
||||
operator: operator,
|
||||
label: getOperatorLabel(operator),
|
||||
}));
|
||||
return operatorList;
|
||||
}
|
||||
|
||||
getActiveOption(options, active){
|
||||
const foundOption = options.find(option => option[0] === active);
|
||||
return foundOption ? foundOption[1] : "Select";
|
||||
}
|
||||
|
||||
getValueInfo(filter_row) {
|
||||
const fieldDef = this.fieldDefs?.[filter_row.id] || this.filter_info[filter_row.id];
|
||||
let valueInfo = getValueEditorInfo(fieldDef, filter_row.operator);
|
||||
if(valueInfo.component?.name === 'Select' || valueInfo.component?.name === 'List'){
|
||||
const options = fieldDef.selection || [];
|
||||
const params = {activeOption: this.getActiveOption(options, filter_row.value)}
|
||||
let KsSelectComponent = this.getKsSelectComponent(options, params)
|
||||
if(fieldDef.type === "boolean"){
|
||||
if (["is", "is_not"].includes(filter_row.operator)) {
|
||||
const boolOptions = [
|
||||
[true, _t("set")],
|
||||
[false, _t("not set")],
|
||||
];
|
||||
const boolParams = {activeOption: this.getActiveOption(boolOptions, filter_row.value)}
|
||||
return this.getKsSelectComponent(boolOptions, boolParams)
|
||||
}
|
||||
const boolOptions2 = [
|
||||
[true, _t("True")],
|
||||
[false, _t("False")],
|
||||
];
|
||||
const boolParams2 = {activeOption: this.getActiveOption(boolOptions2, filter_row.value)}
|
||||
return this.getKsSelectComponent(boolOptions2, boolParams2)
|
||||
}
|
||||
if(valueInfo.component?.name === 'List'){
|
||||
let editorInfo = getValueEditorInfo(fieldDef, "=", {
|
||||
addBlankOption: true,
|
||||
startEmpty: true,
|
||||
});
|
||||
if(editorInfo.component?.name === 'Select'){
|
||||
editorInfo = KsSelectComponent
|
||||
valueInfo.extractProps = ({ value, update }) => {
|
||||
if (!disambiguate(value)) {
|
||||
const { stringify } = editorInfo;
|
||||
editorInfo.stringify = (val) => stringify(val, false);
|
||||
}
|
||||
return {
|
||||
value,
|
||||
update,
|
||||
editorInfo,
|
||||
};
|
||||
}
|
||||
}
|
||||
return valueInfo;
|
||||
}
|
||||
return KsSelectComponent;
|
||||
}
|
||||
return valueInfo;
|
||||
}
|
||||
|
||||
getKsSelectComponent(options, params){
|
||||
const getOption = (value) => options.find(([v]) => v === value) || null;
|
||||
return {
|
||||
component: KsDropDown,
|
||||
extractProps: ({ value, update }) => ({
|
||||
value,
|
||||
update,
|
||||
options,
|
||||
addBlankOption: params.addBlankOption,
|
||||
activeOption: params.activeOption || "Select"
|
||||
}),
|
||||
isSupported: (value) => Boolean(getOption(value)),
|
||||
defaultValue: () => options[0]?.[0] ?? false,
|
||||
stringify: (value, disambiguate) => {
|
||||
const option = getOption(value);
|
||||
return option ? option[1] : disambiguate ? formatValue(value) : String(value);
|
||||
},
|
||||
message: _t("Value not in selection"),
|
||||
};
|
||||
}
|
||||
|
||||
getDefaultOperator(fieldDef) {
|
||||
return getExpressionDisplayedOperators(fieldDef)[0];
|
||||
}
|
||||
|
||||
onUpdateFilter(filter_id, row_index){
|
||||
const fieldDef = this.fieldDefs[filter_id];
|
||||
const operator = this.getDefaultOperator(fieldDef)
|
||||
this.state.filtersRowList[row_index] = {
|
||||
id: filter_id,
|
||||
operator: operator,
|
||||
value: getDefaultValue(fieldDef, operator),
|
||||
}
|
||||
}
|
||||
|
||||
addFilterRow(ev){
|
||||
const node = JSON.parse(JSON.stringify(this.defaultFilterRowObject));
|
||||
this.state.filtersRowList.push(node);
|
||||
}
|
||||
|
||||
deleteRow(row_index){
|
||||
this.state.filtersRowList.splice(row_index, 1);
|
||||
}
|
||||
|
||||
clearRows(ev){
|
||||
const node = JSON.parse(JSON.stringify(this.defaultFilterRowObject));
|
||||
this.state.filtersRowList = [node];
|
||||
}
|
||||
|
||||
onUpdateValue(row_index, updated_value){
|
||||
let field_type = this.props?.filter_info?.[this.state.filtersRowList[row_index]?.id].type
|
||||
let operator = this.state.filtersRowList[row_index]?.operator
|
||||
if(field_type && ['many2many', 'many2one', 'one2many'].includes(field_type)){
|
||||
if (Array.isArray(updated_value)) {
|
||||
updated_value = updated_value.flatMap(item => {
|
||||
if(item === "%UID") {
|
||||
return user.userId;
|
||||
} else if (item === "%MYCOMPANY") {
|
||||
return ["in", "not in"].includes(operator) ? this.env.services.company.activeCompanyIds : this.env.services.company.activeCompanyIds[0];
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(typeof updated_value === 'string'){
|
||||
if(updated_value === "%UID") {
|
||||
updated_value = user.userId;
|
||||
} else if (updated_value === "%MYCOMPANY") {
|
||||
updated_value = this.env.services.company.activeCompanyIds[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
this.state.filtersRowList[row_index].value = updated_value;
|
||||
}
|
||||
|
||||
onUpdateOperator(operator, row_index){
|
||||
const fieldDef = this.fieldDefs[this.state.filtersRowList[row_index].id];
|
||||
this.state.filtersRowList[row_index].operator = operator;
|
||||
this.state.filtersRowList[row_index].value = getDefaultValue(fieldDef, operator, this.state.filtersRowList[row_index].value);
|
||||
}
|
||||
|
||||
|
||||
clearFacets_cookies(ev){
|
||||
eraseCookie('CFilter' + this.props.options.ks_dashboard_id)
|
||||
this.customDomainFacets = {}
|
||||
}
|
||||
|
||||
async makeLabelsAndDomain(models_domain){
|
||||
await Promise.all(
|
||||
Object.entries(models_domain).map(async ([model, model_domain]) => {
|
||||
model_domain.label = await this.getDomainTreeDescription(model, model_domain.domain);
|
||||
model_domain.domain = new Domain(domainFromTree(model_domain.domain)).toList();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
async applyFilters(ev) {
|
||||
eraseCookie('CFilter' + this.props.options.ks_dashboard_id)
|
||||
const filterRowList = this.state.filtersRowList;
|
||||
const models_domain = {};
|
||||
|
||||
for (const filter_row of filterRowList) {
|
||||
const filter = this.filter_info[filter_row.id];
|
||||
const { model, field_name, model_name } = filter;
|
||||
const {operator, value} = filter_row
|
||||
|
||||
if (!models_domain[model]) {
|
||||
models_domain[model] = {
|
||||
domain: connector('|'),
|
||||
label: 'Custom Filter',
|
||||
model_name
|
||||
};
|
||||
}
|
||||
models_domain[model].domain.children.push(condition(field_name, operator, value));
|
||||
}
|
||||
|
||||
await this.makeLabelsAndDomain(models_domain);
|
||||
let domainsToUpdate = await this.validate_and_ReturnDomainsToUpdate(models_domain);
|
||||
this.clearRows();
|
||||
setObjectInCookie('CFilter' + this.props.options.ks_dashboard_id,
|
||||
{ lastAppliedFilters: this.customDomainFacets, lastGroupId: this.groupId}, 1)
|
||||
this.props.update(domainsToUpdate);
|
||||
}
|
||||
|
||||
async validate_and_ReturnDomainsToUpdate(models_domain){
|
||||
let domainsToUpdate = {}
|
||||
for(const [model, model_domain] of Object.entries(models_domain)){
|
||||
let domain;
|
||||
let isValid;
|
||||
try {
|
||||
const evalContext = { ...user.context };
|
||||
domain = new Domain(model_domain.domain).toList(evalContext);
|
||||
} catch {
|
||||
isValid = false;
|
||||
}
|
||||
if (isValid === undefined) {
|
||||
isValid = await rpc("/web/domain/validate", { model: model, domain, });
|
||||
}
|
||||
if (!isValid) {
|
||||
this.notification.add(_t("Domain is invalid. Please correct it"), {
|
||||
type: "danger" });
|
||||
return;
|
||||
}
|
||||
this.updateFacets(model, model_domain);
|
||||
domainsToUpdate[model] = { [ `custom_filter_${this.groupId++}`] : { label: model_domain.label, domain: model_domain.domain } }
|
||||
|
||||
}
|
||||
return domainsToUpdate;
|
||||
}
|
||||
|
||||
updateFacets(model, model_domain){
|
||||
this.customDomainFacets[model] = this.customDomainFacets[model] || { groups: {}, model_name: model_domain.model_name }
|
||||
this.customDomainFacets[model].groups[`custom_filter_${this.groupId}`] = { label: model_domain.label, domain: model_domain.domain }
|
||||
}
|
||||
|
||||
onRemoveFacet(model, group){
|
||||
eraseCookie('CFilter' + this.props.options.ks_dashboard_id)
|
||||
delete this.customDomainFacets[model].groups[group];
|
||||
|
||||
if(!Object.values(this.customDomainFacets[model].groups).length) delete this.customDomainFacets[model];
|
||||
setObjectInCookie('CFilter' + this.props.options.ks_dashboard_id,
|
||||
{ lastAppliedFilters: this.customDomainFacets, lastGroupId: this.groupId}, 1)
|
||||
this.props.remove([model], [group]);
|
||||
this.state.toggleState = !this.state.toggleState
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CustomFilter.template = "ks_dashboard_ninja.custom_filter"
|
||||
|
||||
CustomFilter.components = { Dropdown, DropdownItem }
|
||||
@@ -0,0 +1,160 @@
|
||||
.custom-dash-collapse{
|
||||
.o_input{
|
||||
button{
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
.dropdown-toggle.d-flex.encapsulated-link{
|
||||
overflow: auto;
|
||||
max-height: 75px;
|
||||
}
|
||||
.dash-default-btn{
|
||||
svg{
|
||||
fill: transparent !important;
|
||||
}
|
||||
}
|
||||
.table-dlt-btn{
|
||||
&:hover{
|
||||
border-color: #E7495E !important;
|
||||
svg{
|
||||
stroke: #E7495E !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 150px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks-nav-link{
|
||||
button{
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.dash-dd-2{
|
||||
.selcted-opt.opted{
|
||||
background-color: #F5F8FB;
|
||||
padding-right: 22px;
|
||||
}
|
||||
.dropdown-toggle{
|
||||
&:after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.encapsulated-cross {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-custom {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
max-height: calc(100vh - 483px);
|
||||
|
||||
@include custom-scrollbar;
|
||||
|
||||
.table-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 11px; // Adjust the spacing between rows if necessary
|
||||
|
||||
.table-cell {
|
||||
// padding: 0px 11px 11px 0;
|
||||
flex-shrink: 0; // Prevents the cell from shrinking smaller than its content
|
||||
width: auto; // Allows the cell to take space based on its content
|
||||
|
||||
|
||||
& .o_multi_record_selector .o_record_autocomplete_with_caret {
|
||||
min-width: auto !important;
|
||||
&::after {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
.table-dlt-btn {
|
||||
border: 0.81px solid $color-D1D5DB;
|
||||
padding: 10px 14px;
|
||||
border-radius: 6px;
|
||||
display: block;
|
||||
background-color: transparent;
|
||||
|
||||
svg {
|
||||
stroke: $color-black;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
&.active,
|
||||
&:focus {
|
||||
svg {
|
||||
stroke: $color-danger;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-dd {
|
||||
.dropdown-menu {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
border: 0.81px solid $color-D1D5DB;
|
||||
padding: 12px 11px;
|
||||
border-radius: 6px;
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18.52px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
display: block;
|
||||
|
||||
&::after {
|
||||
margin-left: 8.2em;
|
||||
|
||||
@include max-992 {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1600px) {
|
||||
.custom-dash-collapse{
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 80px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1600px) {
|
||||
.custom-dash-collapse{
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 60px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="ks_dashboard_ninja.custom_filter">
|
||||
<t t-call="ks_dn.facets_container">
|
||||
<t t-set="filter_data" t-value="customDomainFacets"/>
|
||||
<t t-set="remove" t-value="onRemoveFacet.bind(this)"/>
|
||||
</t>
|
||||
<div class="d-flex align-items-center mb-3 mt-1">
|
||||
<h4 class="mb-2">Custom Filters</h4>
|
||||
<button class="clear-all-btn ms-auto" t-on-click="clearRows">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/close-circle.svg" alt="cross-icon"
|
||||
class="img-fluid me-1" loading="lazy"/>
|
||||
Clear All
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<div class="table-custom mb-2">
|
||||
<t t-foreach="state.filtersRowList" t-as="filter_row" t-key="filter_row_index">
|
||||
<div class="table-row gap-3">
|
||||
<t t-call="ks_dn.customFilter.filter.select">
|
||||
<t t-set="row" t-value="filter_row"/>
|
||||
<t t-set="row_index" t-value="filter_row_index"/>
|
||||
</t>
|
||||
<t t-call="ks_dn.customFilter.operator.select">
|
||||
<t t-set="row" t-value="filter_row"/>
|
||||
<t t-set="row_index" t-value="filter_row_index"/>
|
||||
</t>
|
||||
|
||||
<t t-call="ks_dn.customFilter.value.select">
|
||||
<t t-set="row" t-value="filter_row"/>
|
||||
<t t-set="row_index" t-value="filter_row_index"/>
|
||||
</t>
|
||||
|
||||
<div t-att-class=" filter_row_index === 0 ? 'table-cell d-none' : 'table-cell'" t-on-click="() => this.deleteRow(filter_row_index)">
|
||||
<button class="table-dlt-btn">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665"
|
||||
stroke="" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M5.6665 3.31325L5.81317 2.43992C5.91984 1.80659 5.99984 1.33325 7.1265 1.33325H8.87317C9.99984 1.33325 10.0865 1.83325 10.1865 2.44659L10.3332 3.31325"
|
||||
stroke="" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M12.5664 6.09351L12.1331 12.8068C12.0598 13.8535 11.9998 14.6668 10.1398 14.6668H5.85977C3.99977 14.6668 3.93977 13.8535 3.86644 12.8068L3.43311 6.09351"
|
||||
stroke="" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M6.88672 11H9.10672" stroke="" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M6.3335 8.33325H9.66683" stroke="" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<div class="btn-box d-flex justify-content-end align-items-center">
|
||||
<button class="dash-default-btn bg-white" t-on-click="addFilterRow">
|
||||
<t t-call="ks_dashboard_ninja.add_circle_svg"/> Add a condition
|
||||
</button>
|
||||
<button class="dash-btn-red ms-2" t-on-click="applyFilters">
|
||||
Apply Filter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dn.customFilter.filter.select">
|
||||
<div class="table-cell">Where</div>
|
||||
<Dropdown menuClass="'table-cell ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem
|
||||
t-foreach="filterLabels"
|
||||
t-as="filterLabel"
|
||||
t-key="filterLabel.filter_id"
|
||||
class="{ '': true }"
|
||||
onSelected="() => this.onUpdateFilter(filterLabel.filter_id, row_index)"
|
||||
t-esc="filterLabel.filter_name"/>
|
||||
</t>
|
||||
<button class="text-decoration-none bg-transparent " role="button" aria-expanded="false">
|
||||
<t t-out="rowFilter(row.id)"/>
|
||||
</button>
|
||||
</Dropdown>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dn.customFilter.operator.select">
|
||||
<Dropdown menuClass="'table-cell ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem
|
||||
t-foreach="getOperatorInfo(row.id)"
|
||||
t-as="operator"
|
||||
t-key="operator_index"
|
||||
class="{ '': true }"
|
||||
t-esc="operator.label"
|
||||
onSelected="() => this.onUpdateOperator(operator.operator, row_index)"
|
||||
/>
|
||||
</t>
|
||||
<button class="text-decoration-none bg-transparent " href="#" role="button" aria-expanded="false">
|
||||
<t t-out="rowOperator(row_index)"/>
|
||||
</button>
|
||||
</Dropdown>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dn.customFilter.value.select">
|
||||
<t t-call="web.TreeEditor.Editor">
|
||||
<t t-set="_classes" t-value="'overflow-hidden table-cell form-control form-input-box'"/>
|
||||
<t t-set="info" t-value="getValueInfo(filter_row)" />
|
||||
<t t-set="value" t-value="filter_row.value" />
|
||||
<t t-set="update" t-value="(value) => this.onUpdateValue(row_index, value)"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dn.no-filter-view">
|
||||
<div class="no-data-avilable">
|
||||
<div class="d-flex align-items-center justify-content-center flex-column">
|
||||
<div class="no-data-img">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/no-data.png" alt="no-data-available" loading="lazy" class="img-fluid"/>
|
||||
</div>
|
||||
<div class="title mb-1">
|
||||
No Filter Available
|
||||
</div>
|
||||
<p>
|
||||
No custom filter, Create some from dashboard settings
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,41 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, xml, useEffect } from "@odoo/owl";
|
||||
import { Select } from "@web/core/tree_editor/tree_editor_components";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
|
||||
|
||||
export class KsDropDown extends Select{
|
||||
setup(){
|
||||
super.setup();
|
||||
}
|
||||
|
||||
deserialize(value){
|
||||
return JSON.parse(value);
|
||||
}
|
||||
}
|
||||
|
||||
KsDropDown.template = xml`<Dropdown menuClass="'o_input pe-3 text-truncate ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem
|
||||
t-foreach="props.options"
|
||||
t-as="option"
|
||||
t-key="serialize(option[0])"
|
||||
class="{ '': true }"
|
||||
t-esc="option[1]"
|
||||
onSelected="() => this.props.update(this.deserialize(serialize(option[0])))"
|
||||
/>
|
||||
</t>
|
||||
<button class="text-decoration-none" href="#" role="button" aria-expanded="false">
|
||||
<t t-out="props.activeOption"/>
|
||||
</button>
|
||||
</Dropdown>`
|
||||
|
||||
KsDropDown.components = { Dropdown, DropdownItem }
|
||||
|
||||
KsDropDown.props = [ ...Select.props, "activeOption"]
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/**@odoo-module **/
|
||||
|
||||
import { Component, useState, useRef } from "@odoo/owl"
|
||||
import { DateTimeInput } from "@web/core/datetime/datetime_input";
|
||||
import { parseDateTime, parseDate, formatDate, formatDateTime } from "@web/core/l10n/dates";
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
|
||||
const { DateTime } = luxon;
|
||||
|
||||
|
||||
export class KsDateFilter extends Component{
|
||||
setup(){
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.notification = this.env.services.notification
|
||||
this.isMobile = isMobileOS();
|
||||
this.ks_date_filter_selections = {
|
||||
'l_none': _t('All Time'),
|
||||
'l_day': _t('Today'),
|
||||
't_week': _t('This Week'),
|
||||
'td_week': _t('Week To Date'),
|
||||
't_month': _t('This Month'),
|
||||
'td_month': _t('Month to Date'),
|
||||
't_quarter': _t('This Quarter'),
|
||||
'td_quarter': _t('Quarter to Date'),
|
||||
't_year': _t('This Year'),
|
||||
'td_year': _t('Year to Date'),
|
||||
'n_day': _t('Next Day'),
|
||||
'n_week': _t('Next Week'),
|
||||
'n_month': _t('Next Month'),
|
||||
'n_quarter': _t('Next Quarter'),
|
||||
'n_year': _t('Next Year'),
|
||||
'ls_day': _t('Last Day'),
|
||||
'ls_week': _t('Last Week'),
|
||||
'ls_month': _t('Last Month'),
|
||||
'ls_quarter': _t('Last Quarter'),
|
||||
'ls_year': _t('Last Year'),
|
||||
'l_week': _t('Last 7 days'),
|
||||
'l_month': _t('Last 30 days'),
|
||||
'l_quarter': _t('Last 90 days'),
|
||||
'l_year': _t('Last 365 days'),
|
||||
'ls_past_until_now': _t('Past Till Now'),
|
||||
'ls_pastwithout_now': _t('Past Excluding Today'),
|
||||
'n_future_starting_now': _t('Future Starting Now'),
|
||||
'n_futurestarting_tomorrow': _t('Future Starting Tomorrow'),
|
||||
'l_custom': _t('Custom Filter'),
|
||||
};
|
||||
this.ksDateFilterSelection = false
|
||||
this.ksDateFilterStartDateObj = this.ks_dashboard_data.ks_dashboard_start_date ? parseDateTime(this.ks_dashboard_data.ks_dashboard_start_date) : DateTime.now();
|
||||
this.ksDateFilterEndDateObj = this.get_initial_date(this.ks_dashboard_data.ks_dashboard_end_date)
|
||||
|
||||
this.rootRef = useRef("rootRef")
|
||||
|
||||
this.items = Object.keys(this.ks_dashboard_data.ks_dashboard_items_ids)
|
||||
this.state = useState({
|
||||
ks_current_filter : this.ksDateFilterSelection,
|
||||
is_show_date_fields : false
|
||||
})
|
||||
this.state.ks_current_filter = this.ks_dashboard_data.ks_date_filter_selection
|
||||
|
||||
this.custom_date_filter_buttons = [ { name: "Apply", callback: this.onApplyClick.bind(this), classes: 'dash-default-btn bg-white me-2', shouldVisible: true },
|
||||
{ name: "Clear", callback: this._onKsClearDateValues.bind(this), classes: 'dash-btn-red', shouldVisible: true } ]
|
||||
}
|
||||
|
||||
get_initial_date(date){
|
||||
if(date) return parseDateTime(date);
|
||||
return this.ks_dashboard_data.ks_default_end_time ? DateTime.now().endOf('day') : DateTime.now();
|
||||
}
|
||||
|
||||
_ksOnDateFilterMenuSelect(selected_filter_id) {
|
||||
this.env.services.ui.block();
|
||||
|
||||
eraseCookie('FilterDateData' + this.ks_dashboard_data.ks_dashboard_id);
|
||||
this.state.ks_current_filter = selected_filter_id
|
||||
if (this.state.ks_current_filter !== 'l_custom'){
|
||||
this._onKsApplyDateFilter(this.state.ks_current_filter, false, false)
|
||||
}
|
||||
else{
|
||||
this.ksDateFilterStartDateObj = this.ks_dashboard_data.ks_dashboard_start_date ? parseDateTime(this.ks_dashboard_data.ks_dashboard_start_date) : DateTime.now()
|
||||
this.ksDateFilterEndDateObj = this.get_initial_date(this.ks_dashboard_data.ks_dashboard_end_date)
|
||||
this.state.is_show_date_fields = true
|
||||
}
|
||||
this.props.update_mode(this.state.ks_current_filter !== 'l_custom' ? "manager" : "custom_date")
|
||||
this.env.services.ui.unblock();
|
||||
|
||||
}
|
||||
|
||||
_onKsApplyDateFilter(selected_filter_id, start_date, end_date) {
|
||||
let self = this;
|
||||
if(!['l_none', 'l_custom'].includes(selected_filter_id))
|
||||
setObjectInCookie('FilterDateData' + this.ks_dashboard_data.ks_dashboard_id,
|
||||
{'filter_selection': this.state.ks_current_filter, date_range: { start_date, end_date }}, 1);
|
||||
self.ksDateFilterSelection = this.state.ks_current_filter;
|
||||
if (this.state.ks_current_filter !== "l_custom") {
|
||||
this.env.ks_update_date_filter_state(selected_filter_id, false, false);
|
||||
this.props.update_mode(this.ks_dashboard_data.ks_dashboard_manager ? "manager" : "user");
|
||||
} else {
|
||||
if (start_date && end_date) {
|
||||
if ( start_date <= end_date ) {
|
||||
start_date = start_date.toString()
|
||||
end_date = end_date.toString()
|
||||
if (start_date === "Invalid date" || end_date === "Invalid date"){
|
||||
this.notification.add(_t("Invalid Date"), { type: "warning"});
|
||||
}else{
|
||||
setObjectInCookie('FilterDateData' + this.ks_dashboard_data.ks_dashboard_id,
|
||||
{'filter_selection': this.state.ks_current_filter, date_range: { start_date, end_date }}, 1);
|
||||
this.state.is_show_date_fields = false
|
||||
this.env.ks_update_date_filter_state(selected_filter_id, start_date, end_date)
|
||||
this.props.update_mode(this.ks_dashboard_data.ks_dashboard_manager ? "manager" : "user");
|
||||
}
|
||||
} else {
|
||||
this.notification.add(_t("Start date should be less than end date."), { type: "warning"});
|
||||
}
|
||||
} else {
|
||||
let notification_text = !start_date && !end_date ? "Please enter start date and end date." : `Please enter ${ !start_date ? "start" : "end" } date`;
|
||||
this.notification.add(_t(notification_text), { type: "warning"});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change_start_date(args){
|
||||
this.ksDateFilterStartDateObj = args
|
||||
}
|
||||
|
||||
change_end_date(args){
|
||||
this.ksDateFilterEndDateObj = args
|
||||
}
|
||||
|
||||
onApplyClick(){
|
||||
this._onKsApplyDateFilter('l_custom', this.ksDateFilterStartDateObj, this.ksDateFilterEndDateObj)
|
||||
}
|
||||
|
||||
_onKsClearDateValues() {
|
||||
eraseCookie('FilterDateData' + this.ks_dashboard_data.ks_dashboard_id);
|
||||
this.state.ks_current_filter = 'l_none'
|
||||
this.state.is_show_date_fields = false
|
||||
this.env.ks_update_date_filter_state('l_none', false, false)
|
||||
this.props.update_mode(this.ks_dashboard_data.ks_dashboard_manager ? "manager" : "user");
|
||||
|
||||
|
||||
}
|
||||
|
||||
showDateFilterFields(){
|
||||
this.state.is_show_date_fields = true
|
||||
this.props.update_mode('custom_date');
|
||||
}
|
||||
|
||||
} ;
|
||||
KsDateFilter.props = {
|
||||
dashboard_data : { type : Object, optional : true },
|
||||
update_mode : { type : Function, optional : true }
|
||||
}
|
||||
KsDateFilter.components = { Dropdown, DateTimeInput, DropdownItem }
|
||||
KsDateFilter.template = "ks_dashboard_ninja.Ks_date_filter"
|
||||
@@ -0,0 +1,39 @@
|
||||
.ks_custom_date_filter .dropdown-menu{
|
||||
@include custom-scrollbar;
|
||||
}
|
||||
|
||||
.custom-date-range-selector {
|
||||
&.magic-star-dd {
|
||||
.img-bg {
|
||||
background-color: $color-white !important;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: #6789C6 !important;
|
||||
stroke: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks_date_input_fields {
|
||||
input {
|
||||
border: 0.81px solid #D1D5DB !important;
|
||||
border-radius: 6px;
|
||||
padding: 12px 10px !important;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 18.52px;
|
||||
text-align: left;
|
||||
color: #241C1D;
|
||||
background-color: $color-white;
|
||||
|
||||
|
||||
&#ks_btn_middle_child,
|
||||
&#ks_btn_last_child {
|
||||
border-radius: 6px !important;
|
||||
padding: 12px 10px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="ks_dashboard_ninja.Ks_date_filter" owl="1">
|
||||
<div t-att-class="this.items.length > 0 ?'ks_dashboard_link ks_am_content_element dash-dd-2 ks_custom_date_filter gap-2': 'ks_hide'"
|
||||
t-ref="rootRef">
|
||||
<t t-call="ks_dashboard_ninja.ks_date_filter_dropdown"/>
|
||||
<div class="custom-date-range-selector cursor-pointer magic-star-dd"
|
||||
t-if="state.ks_current_filter === 'l_custom' && !state.is_show_date_fields && !isMobile" t-on-click="showDateFilterFields">
|
||||
<span class="img-bg">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.1662 2.37325V1.33325C11.1662 1.05992 10.9395 0.833252 10.6662 0.833252C10.3928 0.833252 10.1662 1.05992 10.1662 1.33325V2.33325H5.83284V1.33325C5.83284 1.05992 5.60617 0.833252 5.33284 0.833252C5.0595 0.833252 4.83284 1.05992 4.83284 1.33325V2.37325C3.03284 2.53992 2.1595 3.61325 2.02617 5.20659C2.01284 5.39992 2.17284 5.55992 2.3595 5.55992H13.6395C13.8328 5.55992 13.9928 5.39325 13.9728 5.20659C13.8395 3.61325 12.9662 2.53992 11.1662 2.37325Z" fill="#6789C6"/>
|
||||
<path d="M13.3333 6.56006H2.66667C2.3 6.56006 2 6.86006 2 7.22673V11.3334C2 13.3334 3 14.6667 5.33333 14.6667H10.6667C13 14.6667 14 13.3334 14 11.3334V7.22673C14 6.86006 13.7 6.56006 13.3333 6.56006ZM6.14 12.1401C6.10667 12.1667 6.07333 12.2001 6.04 12.2201C6 12.2467 5.96 12.2667 5.92 12.2801C5.88 12.3001 5.84 12.3134 5.8 12.3201C5.75333 12.3267 5.71333 12.3334 5.66667 12.3334C5.58 12.3334 5.49333 12.3134 5.41333 12.2801C5.32667 12.2467 5.26 12.2001 5.19333 12.1401C5.07333 12.0134 5 11.8401 5 11.6667C5 11.4934 5.07333 11.3201 5.19333 11.1934C5.26 11.1334 5.32667 11.0867 5.41333 11.0534C5.53333 11.0001 5.66667 10.9867 5.8 11.0134C5.84 11.0201 5.88 11.0334 5.92 11.0534C5.96 11.0667 6 11.0867 6.04 11.1134C6.07333 11.1401 6.10667 11.1667 6.14 11.1934C6.26 11.3201 6.33333 11.4934 6.33333 11.6667C6.33333 11.8401 6.26 12.0134 6.14 12.1401ZM6.14 9.80673C6.01333 9.92673 5.84 10.0001 5.66667 10.0001C5.49333 10.0001 5.32 9.92673 5.19333 9.80673C5.07333 9.68006 5 9.50673 5 9.33339C5 9.16006 5.07333 8.98673 5.19333 8.86006C5.38 8.67339 5.67333 8.61339 5.92 8.72006C6.00667 8.75339 6.08 8.80006 6.14 8.86006C6.26 8.98673 6.33333 9.16006 6.33333 9.33339C6.33333 9.50673 6.26 9.68006 6.14 9.80673ZM8.47333 12.1401C8.34667 12.2601 8.17333 12.3334 8 12.3334C7.82667 12.3334 7.65333 12.2601 7.52667 12.1401C7.40667 12.0134 7.33333 11.8401 7.33333 11.6667C7.33333 11.4934 7.40667 11.3201 7.52667 11.1934C7.77333 10.9467 8.22667 10.9467 8.47333 11.1934C8.59333 11.3201 8.66667 11.4934 8.66667 11.6667C8.66667 11.8401 8.59333 12.0134 8.47333 12.1401ZM8.47333 9.80673C8.44 9.83339 8.40667 9.86006 8.37333 9.88673C8.33333 9.91339 8.29333 9.93339 8.25333 9.94673C8.21333 9.96673 8.17333 9.98006 8.13333 9.98672C8.08667 9.99339 8.04667 10.0001 8 10.0001C7.82667 10.0001 7.65333 9.92673 7.52667 9.80673C7.40667 9.68006 7.33333 9.50673 7.33333 9.33339C7.33333 9.16006 7.40667 8.98673 7.52667 8.86006C7.58667 8.80006 7.66 8.75339 7.74667 8.72006C7.99333 8.61339 8.28667 8.67339 8.47333 8.86006C8.59333 8.98673 8.66667 9.16006 8.66667 9.33339C8.66667 9.50673 8.59333 9.68006 8.47333 9.80673ZM10.8067 12.1401C10.68 12.2601 10.5067 12.3334 10.3333 12.3334C10.16 12.3334 9.98667 12.2601 9.86 12.1401C9.74 12.0134 9.66667 11.8401 9.66667 11.6667C9.66667 11.4934 9.74 11.3201 9.86 11.1934C10.1067 10.9467 10.56 10.9467 10.8067 11.1934C10.9267 11.3201 11 11.4934 11 11.6667C11 11.8401 10.9267 12.0134 10.8067 12.1401ZM10.8067 9.80673C10.7733 9.83339 10.74 9.86006 10.7067 9.88673C10.6667 9.91339 10.6267 9.93339 10.5867 9.94673C10.5467 9.96673 10.5067 9.98006 10.4667 9.98672C10.42 9.99339 10.3733 10.0001 10.3333 10.0001C10.16 10.0001 9.98667 9.92673 9.86 9.80673C9.74 9.68006 9.66667 9.50673 9.66667 9.33339C9.66667 9.16006 9.74 8.98673 9.86 8.86006C9.92667 8.80006 9.99333 8.75339 10.08 8.72006C10.2 8.66673 10.3333 8.65339 10.4667 8.68006C10.5067 8.68673 10.5467 8.70006 10.5867 8.72006C10.6267 8.73339 10.6667 8.75339 10.7067 8.78006C10.74 8.80673 10.7733 8.83339 10.8067 8.86006C10.9267 8.98673 11 9.16006 11 9.33339C11 9.50673 10.9267 9.68006 10.8067 9.80673Z" fill="#6789C6"/>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<t t-if="state.ks_current_filter == 'l_custom' && state.is_show_date_fields">
|
||||
<div class="ks_date_input_fields d-flex gap-2">
|
||||
<div class="form-input-box form-control start-date">
|
||||
<DateTimeInput value="ksDateFilterStartDateObj" type="'datetime'" rounding="1"
|
||||
id="'ks_btn_middle_child'" placeholder="'Start Date...'" onChange.bind="change_start_date"/>
|
||||
</div>
|
||||
<div class="form-input-box form-control start-date">
|
||||
<DateTimeInput value="ksDateFilterEndDateObj" type="'datetime'" rounding="1"
|
||||
id="'ks_btn_last_child'" placeholder="'End Date...'" onChange.bind="change_end_date"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="ks_date_apply_clear_print gap-2">
|
||||
<!--Apply and Clear buttons will only be shown when Date filter : Custom-->
|
||||
<button type='button' class='dash-default-btn bg-white ' t-on-click="onApplyClick" data-tooltip="Apply">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" class="me-lg-2 me-0" height="20" viewBox="0 0 20 20" fill="none" stroke="#FFFFFF">
|
||||
<path d="M18.0249 12.2917C18.0249 13.0334 17.8249 13.7334 17.4583 14.3334C16.7749 15.4751 15.5166 16.25 14.0666 16.25C13.2833 16.25 12.5499 16.0167 11.9333 15.6084C11.4166 15.2917 10.9916 14.8501 10.6833 14.3334C10.3166 13.7334 10.1083 13.0334 10.1083 12.2917C10.1083 10.1084 11.8833 8.33337 14.0666 8.33337C14.3666 8.33337 14.6583 8.3667 14.9333 8.43337C16.7083 8.82504 18.0249 10.4084 18.0249 12.2917Z" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.5253 12.2917L13.5003 13.2667L15.6086 11.3167" stroke="#241C1D" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M17.2413 3.34995V5.19995C17.2413 5.87495 16.8163 6.71663 16.3996 7.14163L14.9329 8.43329C14.6579 8.36662 14.3663 8.33329 14.0663 8.33329C11.8829 8.33329 10.1079 10.1083 10.1079 12.2916C10.1079 13.0333 10.3163 13.7333 10.6829 14.3333C10.9913 14.85 11.4163 15.2916 11.9329 15.6083V15.8916C11.9329 16.4 11.5996 17.075 11.1746 17.325L9.9996 18.0833C8.90794 18.7583 7.39127 18 7.39127 16.65V12.1916C7.39127 11.6 7.0496 10.8416 6.71627 10.425L3.51625 7.05829C3.09958 6.63329 2.75793 5.87497 2.75793 5.37497V3.43329C2.75793 2.42496 3.51628 1.66663 4.44128 1.66663H15.5579C16.4829 1.66663 17.2413 2.42495 17.2413 3.34995Z" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
<button type='button' class='dash-default-btn bg-white clear-dashboard-date-filter' t-on-click="_onKsClearDateValues" data-tooltip="Clear">
|
||||
<svg width="20" height="20" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.00016 14.6666C11.6668 14.6666 14.6668 11.6666 14.6668 7.99992C14.6668 4.33325 11.6668 1.33325 8.00016 1.33325C4.3335 1.33325 1.3335 4.33325 1.3335 7.99992C1.3335 11.6666 4.3335 14.6666 8.00016 14.6666Z" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.11328 9.88661L9.88661 6.11328" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.88661 9.88661L6.11328 6.11328" stroke="#241C1D" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="ks_dashboard_ninja.ks_date_filter_dropdown">
|
||||
<Dropdown menuClass="'ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem t-foreach="ks_date_filter_selections" t-as="date_selection" t-key="date_selection_index"
|
||||
class="{ 'global-active': state.ks_current_filter === date_selection , 'd-none': date_selection === 'l_custom' && isMobile}"
|
||||
onSelected="() => this._ksOnDateFilterMenuSelect(date_selection)">
|
||||
<t t-esc="ks_date_filter_selections[date_selection]"/>
|
||||
</DropdownItem>
|
||||
</t>
|
||||
<span class="ellipsis-content d-block max-width-medium-6vw" t-esc="ks_date_filter_selections[state.ks_current_filter]"/>
|
||||
</Dropdown>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,147 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onWillStart } from "@odoo/owl";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { PreDefinedFilter } from "@ks_dashboard_ninja/components/predefined_filter/predefined_filter";
|
||||
import { FavFilterWizard } from "@ks_dashboard_ninja/components/favourite_filter/favourite_filter";
|
||||
import { FavouriteFilter } from "@ks_dashboard_ninja/components/favourite_filter/favourite_filter";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { CustomFilter } from '@ks_dashboard_ninja/components/custom_filter/custom_filter';
|
||||
import { ModelDrivenFilterApplicator } from '@ks_dashboard_ninja/components/model_driven_filter_applicator/model_driven_filter_applicator';
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
|
||||
|
||||
/*
|
||||
* TODO : Applying filters , updating facets , removing facets,
|
||||
and applying domain have some functionalities common , can be reviewed
|
||||
there is a possibility to make common methods and reduce some lines of code
|
||||
*/
|
||||
|
||||
export class DNFilter extends Component{
|
||||
static props = {
|
||||
dashboard_data: { type: Object, optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
|
||||
};
|
||||
static components = { PreDefinedFilter, Dropdown, CustomFilter, FavouriteFilter, ModelDrivenFilterApplicator }
|
||||
|
||||
setup(){
|
||||
this.dashboard_domain_data = {}
|
||||
this.isShowPredefinedFilter = Object.keys(this.props.dashboard_data.ks_dashboard_pre_domain_filter).length
|
||||
this.isShowCustomFilter = Object.keys(this.props.dashboard_data.ks_dashboard_custom_domain_filter).length
|
||||
|
||||
this.state = useState({
|
||||
dashboard_favourite_filter: this.props.dashboard_data.ks_dashboard_favourite_filter,
|
||||
removeAllFilters: false,
|
||||
filters_count: 0,
|
||||
})
|
||||
onWillStart( this.willStart );
|
||||
}
|
||||
|
||||
willStart(){
|
||||
this.setObjFromCookies();
|
||||
this.state.filters_count = this.filters_count
|
||||
}
|
||||
|
||||
get options(){
|
||||
return {
|
||||
ks_dashboard_id : this.props.dashboard_data.ks_dashboard_id,
|
||||
}
|
||||
}
|
||||
|
||||
get filters_count(){
|
||||
let count = 0;
|
||||
Object.values(this.dashboard_domain_data).forEach( (model_domain_data) => {
|
||||
Object.keys(model_domain_data.sub_domains).forEach( (group_key_name) => {
|
||||
group_key_name.startsWith('FF') ? count : ++count;
|
||||
})
|
||||
})
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
get hasActiveFilter(){
|
||||
return Object.keys(this.dashboard_domain_data).length ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
setObjFromCookies(){
|
||||
let dashboard_domain_data_from_cky = getObjectFromCookie('Filter' + this.props.dashboard_data.ks_dashboard_id)
|
||||
this.dashboard_domain_data = dashboard_domain_data_from_cky ?? {}
|
||||
}
|
||||
|
||||
update_sub_domains(modelDomainsToUpdate){
|
||||
this.state.removeAllFilters = false
|
||||
Object.keys(modelDomainsToUpdate).forEach( (model) => {
|
||||
this.dashboard_domain_data[model] ??= { sub_domains: {}}
|
||||
Object.keys(modelDomainsToUpdate[model]).forEach( (group) => {
|
||||
this.dashboard_domain_data[model].sub_domains[group] ??= {}
|
||||
this.dashboard_domain_data[model].sub_domains[group] = modelDomainsToUpdate[model][group].domain
|
||||
})
|
||||
})
|
||||
this.update(Object.keys(modelDomainsToUpdate))
|
||||
}
|
||||
|
||||
applyFavouriteFilter(modelDomainsToUpdate){
|
||||
eraseCookie('Filter' + this.props.dashboard_data.ks_dashboard_id)
|
||||
delete this.dashboard_domain_data
|
||||
this.state.removeAllFilters = true
|
||||
this.dashboard_domain_data = modelDomainsToUpdate
|
||||
this.state.filters_count = this.filters_count
|
||||
setObjectInCookie('Filter' + this.props.dashboard_data.ks_dashboard_id, this.dashboard_domain_data, 1)
|
||||
this.env.replace_dashboard_filters(modelDomainsToUpdate)
|
||||
}
|
||||
|
||||
remove_sub_domains(models, groups){
|
||||
models.forEach( (model) => {
|
||||
groups.forEach( ( group) => {
|
||||
delete this.dashboard_domain_data[model].sub_domains[group]
|
||||
})
|
||||
})
|
||||
this.update(models)
|
||||
// this.pruneEmptyFilterGroups(models)
|
||||
}
|
||||
|
||||
|
||||
|
||||
update(models){
|
||||
eraseCookie('Filter' + this.props.dashboard_data.ks_dashboard_id)
|
||||
let domainsToUpdate = {};
|
||||
for( let model of models){
|
||||
let domain = Domain.and([ ...Object.values(this.dashboard_domain_data[model].sub_domains) ]).toList();
|
||||
this.dashboard_domain_data[model].domain = domain
|
||||
domainsToUpdate[model] = { domain, sub_domains: this.dashboard_domain_data[model].sub_domains }
|
||||
}
|
||||
setObjectInCookie('Filter' + this.props.dashboard_data.ks_dashboard_id, this.dashboard_domain_data, 1)
|
||||
this.state.filters_count = this.filters_count
|
||||
this.env.update_dashboard_filters(domainsToUpdate)
|
||||
}
|
||||
|
||||
onSaveAsFavouriteClick(){
|
||||
this.env.services.dialog.add(FavFilterWizard,{
|
||||
save_favourite_filter: this.save_favourite_filter.bind(this),
|
||||
dashboard_favourite_filter: this.state.dashboard_favourite_filter,
|
||||
dashboard_data: this.props.dashboard_data,
|
||||
dashboard_domain_data: this.dashboard_domain_data
|
||||
});
|
||||
}
|
||||
|
||||
save_favourite_filter(ks_filter_name, ks_filter_obj){
|
||||
this.state.dashboard_favourite_filter[ks_filter_name] = ks_filter_obj
|
||||
}
|
||||
|
||||
delete_favourite_filter(ks_filter_name){
|
||||
delete this.state.dashboard_favourite_filter[ks_filter_name]
|
||||
}
|
||||
|
||||
hideFilterTab() {
|
||||
Collapse.getInstance('#collapseExample').hide()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DNFilter.template = "ks_dashboard_ninja.dn_filter"
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
.ks_body_class .filters-amount {
|
||||
background-color: $color-E7495E;
|
||||
font-size: 8px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
text-align: left;
|
||||
color: $color-white;
|
||||
height: 17px;
|
||||
width: 17px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ks_body_class .filter {
|
||||
svg {
|
||||
stroke: $color-paragraph;
|
||||
fill: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .filter.active {
|
||||
svg {
|
||||
fill: $color-6789C6;
|
||||
stroke: $color-white;
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .favorite-btn {
|
||||
border: 0.81px solid $color-E5E7EB;
|
||||
border-radius: 5px;
|
||||
font-size: $font-12;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 16.8px;
|
||||
text-align: left;
|
||||
color: $color-1E1E1E;
|
||||
padding: 10px 8px;
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
.ks_body_class .o_searchview_facet_label {
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-dash-collapse {
|
||||
left: -250px;
|
||||
}
|
||||
|
||||
.custom-filter-tab, .predefined-filter-tab {
|
||||
overflow: auto;
|
||||
max-height: 50vh;
|
||||
|
||||
@include custom-scrollbar;
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="ks_dashboard_ninja.dn_filter" owl="1">
|
||||
<div class="d-flex justify-content-center align-items-center gap-2 filters_section_root">
|
||||
<div class="dropdown dash-dd-2 filter filters_section d-lg-block d-none"
|
||||
t-att-class="state.filters_count ? 'active' : ''">
|
||||
<a class="text-decoration-none d-flex dropdown-toggle align-items-center" data-bs-toggle="collapse"
|
||||
data-bs-target="#collapseExample" aria-expanded="false" aria-controls="collapseExample">
|
||||
<span class="d-flex align-items-center">
|
||||
<svg width="20" class="me-lg-2 me-0" height="20" viewBox="0 0 20 20" fill=""
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M18.0249 12.2917C18.0249 13.0334 17.8249 13.7334 17.4583 14.3334C16.7749 15.4751 15.5166 16.25 14.0666 16.25C13.2833 16.25 12.5499 16.0167 11.9333 15.6084C11.4166 15.2917 10.9916 14.8501 10.6833 14.3334C10.3166 13.7334 10.1083 13.0334 10.1083 12.2917C10.1083 10.1084 11.8833 8.33337 14.0666 8.33337C14.3666 8.33337 14.6583 8.3667 14.9333 8.43337C16.7083 8.82504 18.0249 10.4084 18.0249 12.2917Z"
|
||||
stroke="" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M12.5253 12.2917L13.5003 13.2667L15.6086 11.3167" stroke=""
|
||||
stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path
|
||||
d="M17.2413 3.34995V5.19995C17.2413 5.87495 16.8163 6.71663 16.3996 7.14163L14.9329 8.43329C14.6579 8.36662 14.3663 8.33329 14.0663 8.33329C11.8829 8.33329 10.1079 10.1083 10.1079 12.2916C10.1079 13.0333 10.3163 13.7333 10.6829 14.3333C10.9913 14.85 11.4163 15.2916 11.9329 15.6083V15.8916C11.9329 16.4 11.5996 17.075 11.1746 17.325L9.9996 18.0833C8.90794 18.7583 7.39127 18 7.39127 16.65V12.1916C7.39127 11.6 7.0496 10.8416 6.71627 10.425L3.51625 7.05829C3.09958 6.63329 2.75793 5.87497 2.75793 5.37497V3.43329C2.75793 2.42496 3.51628 1.66663 4.44128 1.66663H15.5579C16.4829 1.66663 17.2413 2.42495 17.2413 3.34995Z"
|
||||
stroke="" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
<span class="d-lg-block d-none ellipsis-content max-width-medium-4vw">Filters</span>
|
||||
<div class="ms-1 d-flex justify-content-center filters-amount" t-if="state.filters_count" t-esc="state.filters_count"/>
|
||||
</a>
|
||||
|
||||
<div class="collapse custom-dash-collapse" id="collapseExample">
|
||||
<div class="card card-body">
|
||||
<ul class="nav nav-pills mb-3 border-bottom border-2" id="pills-tab" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link text-primary fw-semibold position-relative show active" id="pills-home-tab"
|
||||
data-bs-toggle="pill" data-bs-target="#pills-home"
|
||||
type="button" role="tab" aria-controls="pills-home" aria-selected="true">Predefined Filter
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link text-primary fw-semibold position-relative" id="pills-profile-tab"
|
||||
data-bs-toggle="pill" data-bs-target="#pills-profile" type="button" role="tab"
|
||||
title="Create domain and apply filter" aria-controls="pills-profile"
|
||||
aria-selected="false">Custom Filter
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link text-primary fw-semibold position-relative" id="pills-charts-filter-tab"
|
||||
data-bs-toggle="pill" data-bs-target="#pills-charts-filter" type="button" role="tab"
|
||||
title="Create domain and apply filter" aria-controls="pills-charts-filter"
|
||||
aria-selected="false"> Charts Filter
|
||||
</button>
|
||||
</li>
|
||||
<div class="position-relative ms-auto encapsulated-bottom">
|
||||
<button class="favorite-btn me-3 d-flex align-items-center justify-content-center" t-on-click="onSaveAsFavouriteClick">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/ranking.png" alt="ranking"
|
||||
class="img-fluid me-1" loading="lazy"/>
|
||||
Save as Favourite
|
||||
</button>
|
||||
</div>
|
||||
<div t-on-click="hideFilterTab" class="position-relative d-flex align-items-center me-2 encapsulated-bottom">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/close-circle.svg" alt="cross-icon" style="height: 20px; width: 20px;"
|
||||
class="img-fluid me-2" loading="lazy"/>
|
||||
</div>
|
||||
</ul>
|
||||
|
||||
|
||||
<div class="tab-content" id="pills-tabContent">
|
||||
<!-- Home tab pane (default visible tab) -->
|
||||
<div class="tab-pane fade show active predefined-filter-tab" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab">
|
||||
<PreDefinedFilter filters_data="props.dashboard_data.ks_dashboard_pre_domain_filter" domain="'[]'" options="options"
|
||||
update.bind="update_sub_domains" remove.bind="remove_sub_domains" removeAllFilters="state.removeAllFilters"/>
|
||||
</div>
|
||||
|
||||
<!-- Profile tab pane -->
|
||||
<div class="tab-pane fade custom-filter-tab" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab">
|
||||
<t t-if="isShowCustomFilter">
|
||||
<CustomFilter filter_info="props.dashboard_data.ks_dashboard_custom_domain_filter" options="options"
|
||||
update.bind="update_sub_domains" domain="'[]'" remove.bind="remove_sub_domains" removeAllFilters="state.removeAllFilters"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_dn.no-filter-view"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="tab-pane fade charts-filter-tab" id="pills-charts-filter" role="tabpanel" aria-labelledby="pills-charts-filter-tab">
|
||||
<ModelDrivenFilterApplicator options="options" update.bind="update_sub_domains"
|
||||
remove.bind="remove_sub_domains" removeAllFilters="state.removeAllFilters"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<FavouriteFilter t-if="Object.keys(state.dashboard_favourite_filter).length"
|
||||
favourite_filters_data="props.dashboard_data.ks_dashboard_favourite_filter" options="options"
|
||||
onDelete.bind="delete_favourite_filter" update.bind="applyFavouriteFilter" remove.bind="remove_sub_domains"/>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,145 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onWillStart } from "@odoo/owl";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { session } from "@web/session";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
|
||||
export class FavFilterWizard extends Component{
|
||||
static template = "ks_dashboard_ninja.FavFilterWizard"
|
||||
static components = { Dialog }
|
||||
|
||||
setup(){
|
||||
this.notification = useService("notification")
|
||||
// this.favoriteFilterId = 0
|
||||
}
|
||||
save_favourite_filter(ev){
|
||||
let self = this;
|
||||
let ks_filter_name = $('#favourite_filter_name').val();
|
||||
let ks_is_fav_filter_shared = $('#favFilterShareBool').prop('checked')
|
||||
if (!ks_filter_name.length){
|
||||
this.notification.add(_t("A name for your favorite filter is required."), {
|
||||
type: "warning",
|
||||
});
|
||||
|
||||
}else{
|
||||
var ks_saved_fav_filters = Object.keys(self.props.dashboard_favourite_filter)
|
||||
const favourite = ks_saved_fav_filters.find(item => item == ks_filter_name)
|
||||
if (favourite?.length){
|
||||
this.notification.add(_t("A filter with same name already exists."), {
|
||||
type: "warning",
|
||||
});
|
||||
}
|
||||
else{
|
||||
let domains_to_save = JSON.stringify(self.props.dashboard_domain_data)
|
||||
let newFavFilter = {name: ks_filter_name,
|
||||
ks_dashboard_board_id: self.props.dashboard_data.ks_dashboard_id,
|
||||
ks_filter: domains_to_save,
|
||||
ks_access_id: ks_is_fav_filter_shared ? false : user.userId}
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.favourite_filters/create", {
|
||||
model: 'ks_dashboard_ninja.favourite_filters',
|
||||
method: 'create',
|
||||
args: [newFavFilter],
|
||||
kwargs: {}
|
||||
}).then(function(result){
|
||||
newFavFilter.id = result
|
||||
newFavFilter.ks_filter = self.props.dashboard_domain_data
|
||||
self.props.save_favourite_filter(ks_filter_name, newFavFilter)
|
||||
self.props.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class FavouriteFilter extends Component{
|
||||
static props = {
|
||||
favourite_filters_data: { type: Object, optional: true },
|
||||
onDelete: { type: Function, optional: true },
|
||||
update: { type: Function, optional: true },
|
||||
remove: { type: Function, optional: true },
|
||||
options: { type: Object, optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
|
||||
};
|
||||
static template = "ks_dashboard_ninja.favourite_filter"
|
||||
static components = { Dropdown, DropdownItem }
|
||||
|
||||
setup(){
|
||||
// this.dashboard_domain_data = {}
|
||||
this.state = useState({ current_active: ''})
|
||||
onWillStart( () => { this.setObjFromCookies() })
|
||||
|
||||
}
|
||||
|
||||
setObjFromCookies(){
|
||||
let current_active_from_cky = getObjectFromCookie('FFilter' + this.props.options.ks_dashboard_id)
|
||||
this.state.current_active = current_active_from_cky ?? ''
|
||||
}
|
||||
|
||||
onFilterSelect(filterName){
|
||||
filterName !== this.state.current_active ? this.applyFavFilter(filterName) : this.removeFavFilter(filterName)
|
||||
}
|
||||
|
||||
applyFavFilter(filterName){
|
||||
this.state.current_active = filterName
|
||||
eraseCookie('FFilter' + this.props.options.ks_dashboard_id)
|
||||
let domainsToUpdate = {}
|
||||
let filterToBeApplied = this.props.favourite_filters_data[filterName].ks_filter
|
||||
Object.keys(filterToBeApplied).forEach( (model) => {
|
||||
let domain = filterToBeApplied[model].domain
|
||||
domainsToUpdate[model] = { domain: domain , sub_domains: { [`FF_${filterName}`]: domain } }
|
||||
})
|
||||
setObjectInCookie('FFilter' + this.props.options.ks_dashboard_id, this.state.current_active, 1)
|
||||
this.props.update(domainsToUpdate)
|
||||
}
|
||||
|
||||
removeFavFilter(filterName){
|
||||
eraseCookie('FFilter' + this.props.options.ks_dashboard_id)
|
||||
this.state.current_active = ''
|
||||
this.props.remove(Object.keys(this.props.favourite_filters_data[filterName].ks_filter) , [`FF_${filterName}`])
|
||||
}
|
||||
|
||||
onDeleteBtnClick(filterName){
|
||||
// var ks_filter_domain = this.props.favourite_filters_data[filterName].filter;
|
||||
let ks_access_id = this.props.favourite_filters_data[filterName].ks_access_id;
|
||||
// var ks_remove_filter_models = Object.keys(ks_filter_domain)
|
||||
// const ks_items_to_update_remove = self.ks_dashboard_data.ks_dashboard_items_ids.filter((item) =>
|
||||
// ks_remove_filter_models.includes(self.ks_dashboard_data.ks_item_model_relation[item][0])|| ks_remove_filter_models.includes(self.ks_dashboard_data.ks_item_model_relation[item][1])
|
||||
// );
|
||||
this.env.services.dialog.add(ConfirmationDialog, {
|
||||
body: _t(`This filter is will be removed${ks_access_id ? '' : 'for everybody'} if you continue.`),
|
||||
confirmLabel: _t("Delete Filter"),
|
||||
title: _t("Delete Filter"),
|
||||
confirm: () => {
|
||||
this.delete_fav_filter(filterName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
delete_fav_filter(filterName){
|
||||
let self = this;
|
||||
// this.isFavFilter = false;
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.favourite_filters/unlink", {
|
||||
model: 'ks_dashboard_ninja.favourite_filters',
|
||||
method: 'unlink',
|
||||
args: [Number(this.props.favourite_filters_data[filterName].id)],
|
||||
kwargs: {}
|
||||
}).then(function(result) {
|
||||
self.removeFavFilter(filterName)
|
||||
self.props.onDelete(filterName)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.FavFilterWizard">
|
||||
<Dialog title="'Create Favourite Filter'" size="'md'" contentClass="'favFilterDialog'">
|
||||
<div>
|
||||
<label for="favourite_filter_name" class="mb-2 input-label">Filter Name</label>
|
||||
<input type="text" id="favourite_filter_name" class="form-control form common-input mb-3" placeholder="Enter Filter Name (eg. Order States, SaleOrder)" maxlength="35"/>
|
||||
<input type="checkbox" id="favFilterShareBool" class="form-check-input common-checkbox "/>
|
||||
<label for="favFilterShareBool" class="ms-2 ps-1 label-checkbox">Show with all users</label>
|
||||
</div>
|
||||
<t t-set-slot="footer">
|
||||
<button class="dash-btn-red o-default-button" t-on-click="save_favourite_filter">Save</button>
|
||||
<button class="dash-default-btn" t-on-click="props.close">Close</button>
|
||||
</t>
|
||||
</Dialog>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_dashboard_ninja.favourite_filter" owl="1">
|
||||
<Dropdown menuClass="'ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<DropdownItem t-foreach="Object.values(props.favourite_filters_data)" t-as="favourite_filter" t-key="favourite_filter_index"
|
||||
class="{ 'd-flex justify-content-between ': true, ' global-active': state.current_active === favourite_filter.name}"
|
||||
onSelected="() => this.onFilterSelect(favourite_filter.name)">
|
||||
<span><t t-esc="favourite_filter.name"/></span>
|
||||
<button class="dadsh-dlt-btn" t-on-click.stop="() => this.onDeleteBtnClick(favourite_filter.name)">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.5 2.98999C8.835 2.82499 7.16 2.73999 5.49 2.73999C4.5 2.73999 3.51 2.78999 2.52 2.88999L1.5 2.98999"
|
||||
stroke="#EC2D30" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4.25 2.485L4.36 1.83C4.44 1.355 4.5 1 5.345 1H6.655C7.5 1 7.565 1.375 7.64 1.835L7.75 2.485"
|
||||
stroke="#EC2D30" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M9.4252 4.57007L9.1002 9.60507C9.0452 10.3901 9.0002 11.0001 7.6052 11.0001H4.3952C3.0002 11.0001 2.9552 10.3901 2.9002 9.60507L2.5752 4.57007"
|
||||
stroke="#EC2D30" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M5.16504 8.25H6.83004" stroke="#EC2D30" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M4.75 6.25H7.25" stroke="#EC2D30" stroke-width="0.75" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
</DropdownItem>
|
||||
</t>
|
||||
<div class="">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.0836 6.75843L12.1836 8.95843C12.3336 9.25843 12.7336 9.55843 13.067 9.60843L15.0586 9.94177C16.3336 10.1584 16.6336 11.0751 15.717 11.9918L14.167 13.5501C13.9086 13.8084 13.7586 14.3168 13.842 14.6834L14.2836 16.6084C14.6336 18.1251 13.8253 18.7168 12.4836 17.9251L10.617 16.8168C10.2753 16.6168 9.7253 16.6168 9.38364 16.8168L7.50864 17.9168C6.16697 18.7084 5.35864 18.1168 5.70864 16.6001L6.1503 14.6751C6.23364 14.3168 6.08364 13.8084 5.8253 13.5418L4.28364 12.0001C3.36697 11.0834 3.66697 10.1584 4.94197 9.9501L6.93364 9.61677C7.26697 9.55843 7.66697 9.26677 7.81697 8.96677L8.91697 6.76677C9.50864 5.56677 10.492 5.56677 11.0836 6.75843Z" fill="#6789C6" />
|
||||
<path d="M5 8.12508C4.65833 8.12508 4.375 7.84175 4.375 7.50008V1.66675C4.375 1.32508 4.65833 1.04175 5 1.04175C5.34167 1.04175 5.625 1.32508 5.625 1.66675V7.50008C5.625 7.84175 5.34167 8.12508 5 8.12508Z" fill="#6789C6" />
|
||||
<path d="M15 8.12508C14.6583 8.12508 14.375 7.84175 14.375 7.50008V1.66675C14.375 1.32508 14.6583 1.04175 15 1.04175C15.3417 1.04175 15.625 1.32508 15.625 1.66675V7.50008C15.625 7.84175 15.3417 8.12508 15 8.12508Z" fill="#6789C6" />
|
||||
<path d="M10 3.95841C9.65833 3.95841 9.375 3.67508 9.375 3.33341V1.66675C9.375 1.32508 9.65833 1.04175 10 1.04175C10.3417 1.04175 10.625 1.32508 10.625 1.66675V3.33341C10.625 3.67508 10.3417 3.95841 10 3.95841Z" fill="#6789C6" />
|
||||
</svg>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,3 @@
|
||||
// .ks_date_filter_selected{
|
||||
//
|
||||
// }
|
||||
@@ -0,0 +1,858 @@
|
||||
/** @odoo-module **/
|
||||
import { Component, onWillStart, useState ,useEffect,onMounted, onPatched, onWillUpdateProps,useRef, onWillUnmount, markup, onError } from "@odoo/owl";
|
||||
import { onAudioEnded, convert_data_to_utc } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { KsItemButton } from '@ks_dashboard_ninja/components/chart_buttons/chart_buttons';
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { useBus, useService } from "@web/core/utils/hooks";
|
||||
import { formatFloat } from "@web/core/utils/numbers";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import {formatDate,formatDateTime} from "@web/core/l10n/dates";
|
||||
import { parseDateTime, parseDate } from "@web/core/l10n/dates";
|
||||
import { renderToElement, renderToString } from "@web/core/utils/render";
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { ks_render_graphs, ksrenderfunnelchart, ksrendermapview } from "@ks_dashboard_ninja/js/charts_render_global_functions";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { domainFromTree } from "@web/core/tree_editor/condition_tree";
|
||||
import { condition, connector } from "@web/core/tree_editor/condition_tree";
|
||||
|
||||
export class Ksdashboardgraph extends Component{
|
||||
setup(){
|
||||
this.markup = markup;
|
||||
this.chart_container = {};
|
||||
this.dialogService = useService("dialog");
|
||||
this.actionService = useService("action");
|
||||
this._rpc = rpc
|
||||
this.state = useState({item_data:"",list_view_data:"", update_chart: 0})
|
||||
onMounted(() => this._update_view());
|
||||
onPatched(() => this.update_list_view());
|
||||
this.item = this.props.item
|
||||
this.item.ksIsDashboardManager = this.props.dashboard_data.ks_dashboard_manager
|
||||
this.item.ks_dashboard_list = this.props.dashboard_data.ks_dashboard_list
|
||||
this.ks_dashboard_id = this.props.item.ks_dashboard_id
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
if (this.item.ks_dashboard_item_type == 'ks_list_view'){
|
||||
this.prepare_list()
|
||||
}else{
|
||||
this.prepare_item(this.item);
|
||||
}
|
||||
this.ks_gridstack_container = useRef("ks_gridstack_container");
|
||||
this.aiAudioRef = useRef("aiAudioRef");
|
||||
this.ks_list_view = useRef("ks_list_view");
|
||||
|
||||
var update_interval = this.props.dashboard_data.ks_set_interval
|
||||
this.ks_ai_analysis = this.ks_dashboard_data.ks_ai_explain_dash
|
||||
if (this.item.ks_ai_analysis && this.item.ks_ai_analysis){
|
||||
var ks_analysis = this.item.ks_ai_analysis.split('ks_gap')
|
||||
this.ks_ai_analysis_1 = ks_analysis[0]
|
||||
this.ks_ai_analysis_2 = ks_analysis[1]
|
||||
}
|
||||
|
||||
|
||||
onWillUpdateProps((nextprops)=>{
|
||||
if (nextprops.itemsToUpdateList.length){
|
||||
if (nextprops.itemsToUpdateList?.includes(this.item.id)){
|
||||
this.ksFetchUpdateItem(this.item.id, this.ks_dashboard_id, nextprops.dashboard_data.context)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
onWillUnmount( () => {
|
||||
this.aiAudioRef.el?.removeEventListener('ended', onAudioEnded)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
get isMobile() {
|
||||
return isMobileOS();
|
||||
}
|
||||
|
||||
ksFetchUpdateItem(item_id, dash_id, context, domain = this.env.ksGetParamsForItemFetch(item_id)) {
|
||||
this.root?.dispose();
|
||||
this.env.services.ui.block();
|
||||
var self = this;
|
||||
context = self.env.getContext();
|
||||
rpc("/web/dataset/call_kw",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_item',
|
||||
args: [
|
||||
[parseInt(item_id)], dash_id,domain
|
||||
],
|
||||
kwargs: { context },
|
||||
})
|
||||
.then((new_item_data) => {
|
||||
if(new_item_data[item_id].ks_list_view_data){
|
||||
new_item_data[item_id].ks_list_view_data = convert_data_to_utc(new_item_data[item_id].ks_list_view_data)
|
||||
}
|
||||
this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id];
|
||||
this.item = this.ks_dashboard_data.ks_item_data[item_id] ;
|
||||
// done this to render updated items on play button
|
||||
this.__owl__.parent.component.ks_dashboard_data.ks_item_data[this.item.id] = new_item_data[item_id]
|
||||
if (this.item.ks_dashboard_item_type =="ks_funnel_chart"){
|
||||
$(this.ks_gridstack_container.el).find(".card-body").remove()
|
||||
ksrenderfunnelchart.bind(this)($(this.ks_gridstack_container.el),this.item, 'dashboard_view');
|
||||
}else if(this.item.ks_dashboard_item_type =="ks_list_view"){
|
||||
this.prepare_list()
|
||||
if (this.intial_count < this.item.ks_pagination_limit ) {
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}else{
|
||||
$(this.ks_list_view.el).find('.ks_load_next').removeClass('ks_event_offer_list');
|
||||
}
|
||||
|
||||
}else if(this.item.ks_dashboard_item_type == ("ks_map_view")){
|
||||
$(this.ks_gridstack_container.el).find(".card-body").remove()
|
||||
ksrendermapview.bind(this)($(this.ks_gridstack_container.el),this.item, 'dashboard_view')
|
||||
}else{
|
||||
$(this.ks_gridstack_container.el).find(".card-body").remove()
|
||||
ks_render_graphs.bind(this)($(this.ks_gridstack_container.el),this.item, this.props.dashboard_data.zooming_enabled, 'dashboard_view')
|
||||
}
|
||||
this.env.services.ui.unblock();
|
||||
//
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
_update_view(){
|
||||
let self = this
|
||||
if(this.item.ks_dashboard_item_type == 'ks_list_view'){
|
||||
if (this.item.ks_pagination_limit < this.intial_count) {
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.intial_count < this.item.ks_pagination_limit ) {
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.item.ks_record_data_limit === this.item.ks_pagination_limit){
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.intial_count == 0){
|
||||
$(this.ks_list_view.el).find('.ks_pager').addClass('d-none');
|
||||
}
|
||||
if (this.item.ks_pagination_limit==0){
|
||||
$(this.ks_list_view.el).find('.ks_pager_name').addClass('d-none');
|
||||
}
|
||||
if (this.item.ks_data_calculation_type === 'query' || this.item.ks_list_view_type === "ungrouped"){
|
||||
$('.ks_list_canvas_click').removeClass('ks_list_canvas_click');
|
||||
}
|
||||
}else{
|
||||
if (this.item.ks_data_calculation_type === 'query'){
|
||||
$(this.ks_gridstack_container.el).find(".ks_dashboard_item_chart_info").addClass('d-none');
|
||||
}
|
||||
$(this.ks_gridstack_container.el).addClass('ks_dashboarditem_id');
|
||||
$(this.ks_gridstack_container.el).find(".ks_dashboard_item_button_container").addClass("ks_funnel_item_container")
|
||||
if (this.item.ks_dashboard_item_type =="ks_funnel_chart"){
|
||||
ksrenderfunnelchart.bind(this)($(this.ks_gridstack_container.el),this.item, 'dashboard_view')
|
||||
}else if(this.item.ks_dashboard_item_type == ("ks_map_view")){
|
||||
ksrendermapview.bind(this)($(this.ks_gridstack_container.el),this.item, 'dashboard_view')
|
||||
}else{
|
||||
ks_render_graphs.bind(this)($(this.ks_gridstack_container.el),this.item, this.props.dashboard_data.zooming_enabled, 'dashboard_view')
|
||||
}
|
||||
}
|
||||
this.aiAudioRef.el?.addEventListener('ended', onAudioEnded)
|
||||
|
||||
}
|
||||
update_list_view(){
|
||||
if(this.item.ks_dashboard_item_type == 'ks_list_view'){
|
||||
if (this.item.ks_pagination_limit < this.intial_count) {
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.intial_count < this.item.ks_pagination_limit ) {
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.item.ks_record_data_limit === this.item.ks_pagination_limit){
|
||||
$(this.ks_list_view.el).find('.ks_load_next').addClass('ks_event_offer_list');
|
||||
}
|
||||
if (this.intial_count == 0){
|
||||
$(this.ks_list_view.el).find('.ks_pager').addClass('d-none');
|
||||
}
|
||||
if (this.intial_count != 0){
|
||||
$(this.ks_list_view.el).find('.ks_pager').removeClass('d-none');
|
||||
}
|
||||
if (this.item.ks_pagination_limit==0){
|
||||
$(this.ks_list_view.el).find('.ks_pager_name').addClass('d-none');
|
||||
}
|
||||
if (this.item.ks_data_calculation_type === 'query' || this.item.ks_list_view_type === "ungrouped"){
|
||||
$('.ks_list_canvas_click').removeClass('ks_list_canvas_click');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prepare_list() {
|
||||
var self = this;
|
||||
if (this.item.ks_info){
|
||||
var ks_description = this.item.ks_info.replace?.(/\\n/g, '\n').split?.('\n');
|
||||
var ks_description = ks_description.filter(element => element !== '')
|
||||
}else {
|
||||
var ks_description = false;
|
||||
}
|
||||
if (typeof(this.item.ks_list_view_data) == 'string'){
|
||||
var list_view_data = JSON.parse(this.item.ks_list_view_data)
|
||||
}else{
|
||||
var list_view_data = this.item.ks_list_view_data
|
||||
}
|
||||
var data_rows = list_view_data.data_rows
|
||||
var length = data_rows ? data_rows.length: false;
|
||||
var item_id = this.item.id
|
||||
this.ks_info = ks_description?.join?.(' ') ?? false;
|
||||
this.ks_chart_title = this.item.name
|
||||
this.ks_breadcrumb = this.item.ks_action_name
|
||||
this.item_id = item_id
|
||||
this.ksIsDashboardManager= self.ks_dashboard_data.ks_dashboard_manager,
|
||||
this.ksIsUser = true,
|
||||
this.ks_dashboard_list = self.ks_dashboard_data.ks_dashboard_list,
|
||||
this.count = '1-' + length
|
||||
this.offset = 1
|
||||
this.intial_count = length
|
||||
this.ks_company= this.item.ks_company
|
||||
this.calculation_type = this.ks_dashboard_data.ks_item_data[this.item_id].ks_data_calculation_type
|
||||
this.self = this
|
||||
|
||||
if (this.item.ks_list_view_type === "ungrouped" && list_view_data) {
|
||||
if (list_view_data.date_index) {
|
||||
var index_data = list_view_data.date_index;
|
||||
for (var i = 0; i < index_data.length; i++) {
|
||||
for (var j = 0; j < list_view_data.data_rows.length; j++) {
|
||||
var index = index_data[i]
|
||||
var date = list_view_data.data_rows[j]["data"][index]
|
||||
if (date) {
|
||||
if( list_view_data.fields_type[index] === 'date'){
|
||||
let parsedDate = parseDate(date,{format: localization.dateFormat});
|
||||
list_view_data.data_rows[j]["data"][index] = formatDate(parsedDate, { format: localization.dateFormat })
|
||||
} else{
|
||||
let parsedDate = parseDateTime(date,{format: localization.dateTimeFormat});
|
||||
list_view_data.data_rows[j]["data"][index] = formatDateTime(parsedDate, { format: localization.dateTimeFormat })
|
||||
}
|
||||
}else{
|
||||
// list_view_data.data_rows[j]["data"][index] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (list_view_data) {
|
||||
for (var i = 0; i < list_view_data.data_rows.length; i++) {
|
||||
for (var j = 0; j < list_view_data.data_rows[0]["data"].length; j++) {
|
||||
if (typeof(list_view_data.data_rows[i].data[j]) === "number" || list_view_data.data_rows[i].data[j]) {
|
||||
if (typeof(list_view_data.data_rows[i].data[j]) === "number") {
|
||||
list_view_data.data_rows[i].data[j] = formatFloat(list_view_data.data_rows[i].data[j], Float64Array, {digits:[0, self.item.ks_precision_digits]})
|
||||
}
|
||||
} else {
|
||||
// list_view_data.data_rows[i].data[j] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.state.list_view_data = list_view_data
|
||||
this.list_type = this.item.ks_list_view_type
|
||||
this.ks_pager = true
|
||||
this.tmpl_list_type = self.ks_dashboard_data.ks_item_data[this.item_id].ks_list_view_type
|
||||
this.isDrill = this.ks_dashboard_data.ks_item_data[this.item_id]['isDrill']
|
||||
this.ks_show_records = this.item.ks_show_records
|
||||
// this.item.$el = $ks_gridstack_container;
|
||||
}
|
||||
|
||||
prepare_item(item) {
|
||||
var self = this;
|
||||
var isDrill = item.isDrill ? item.isDrill : false;
|
||||
this.chart
|
||||
var chart_id = item.id;
|
||||
this.ksColorOptions = ["default","dark","moonrise","material"]
|
||||
var funnel_title = item.name;
|
||||
if (item.ks_info){
|
||||
var ks_description = item.ks_info.replace?.(/\\n/g, '\n').split?.('\n');
|
||||
var ks_description = ks_description.filter(element => element !== '')
|
||||
}else {
|
||||
var ks_description = false;
|
||||
}
|
||||
|
||||
this.ks_chart_title= funnel_title,
|
||||
this.ksIsDashboardManager= self.ks_dashboard_data.ks_dashboard_manager,
|
||||
this.ksIsUser = true,
|
||||
this.ks_dashboard_list = self.ks_dashboard_data.ks_dashboard_list,
|
||||
this.chart_id = chart_id,
|
||||
this.ks_info = ks_description?.join?.(' ') ?? false,
|
||||
this.ksChartColorOptions = this.ksColorOptions,
|
||||
this.ks_company = item.ks_company,
|
||||
this.ks_dashboard_item_type = item.ks_dashboard_item_type,
|
||||
this.ks_breadcrumb = item.ks_action_name
|
||||
}
|
||||
|
||||
|
||||
onChartCanvasClick(evt, column_index = false, row_data = false, column_field_type = false) {
|
||||
var self = this;
|
||||
this.ksUpdateDashboard = {};
|
||||
if(this.env.inDialog) return ;
|
||||
var item_id = $(evt.target).parent().data().itemId;
|
||||
var chart_title = '#'+this.item.name
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
if (self.ks_dashboard_data.ks_item_data[item_id].max_sequnce) {
|
||||
|
||||
var sequence = item_data.sequnce ? item_data.sequnce : 0
|
||||
|
||||
var domain = $(evt.target).parent().data().domain;
|
||||
|
||||
if ($(evt.target).parent().data().last_seq !== sequence) {
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/ks_fetch_drill_down_data",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'ks_fetch_drill_down_data',
|
||||
args: [item_id, domain, sequence],
|
||||
kwargs : {},
|
||||
}).then((result) => {
|
||||
if (result.ks_list_view_data) {
|
||||
var chart_id_name = '#item'+'_' +'-1'
|
||||
var id_name = '#'+result.ks_action_name + '_' + (result.sequence-1)
|
||||
if (self.ks_dashboard_data.ks_item_data[item_id].domains) {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_list_view_data).previous_domain;
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'] = {}
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_list_view_data).previous_domain;
|
||||
}
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['isDrill'] = true;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_data'] = result.ks_list_view_data;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_type'] = result.ks_list_view_type;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = 'ks_list_view';
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none');
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_chart_heading").addClass("d-none")
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_list_view_heading").addClass("d-none")
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty();
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none');
|
||||
// $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_title).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(id_name).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block ');
|
||||
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
var list_view_data = JSON.parse(item_data['ks_list_view_data'])
|
||||
|
||||
var $container = renderToElement('ks_dashboard_ninja.ks_new_list_view_table',{
|
||||
list_view_data,item_id:self.item_id,self, markup, state : { list_view_data }
|
||||
})
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").append($container);
|
||||
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_chart_data'] = result.ks_chart_data;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = result.ks_chart_type;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['isDrill'] = true;
|
||||
var chart_id_name = '#item'+'_' +'-1'
|
||||
var id_name = '#'+result.ks_action_name + '_' + (result.sequence-1)
|
||||
if (self.ks_dashboard_data.ks_item_data[item_id].domains) {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_chart_data).previous_domain;
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'] = {}
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_chart_data).previous_domain;
|
||||
}
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none');
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_list_view_heading").addClass("d-none")
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).removeClass('d-none');
|
||||
// $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_title).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(id_name).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block ');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty();
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
if(item_data.ks_dashboard_item_type == 'ks_funnel_chart'){
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove();
|
||||
ksrenderfunnelchart.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data, 'dashboard_view');
|
||||
}else{
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove();
|
||||
ks_render_graphs.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data, self.props.dashboard_data.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else{
|
||||
/**
|
||||
* This is the logic for adding dashboard filter from chart clicks
|
||||
*/
|
||||
if(!isMobileOS()){
|
||||
if(['many2one', 'selection'].includes(column_field_type)){
|
||||
let field_name = self.item.ks_list_view_data.fields_technical_name[column_index]
|
||||
let model_name = self.item.ks_list_view_data.model
|
||||
let model_display_name = self.item.ks_model_display_name
|
||||
if(field_name && model_name && model_display_name)
|
||||
this.env.bus.trigger("APPLY: Dashboard Filter" , { model_display_name, model_name, field_name,
|
||||
operator : '=', value : row_data[0] ?? row_data })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
evt.stopPropagation();
|
||||
}
|
||||
|
||||
|
||||
|
||||
async onChartCanvasClick_funnel(evt, item_id, item){
|
||||
var self = this;
|
||||
if(this.env.inDialog || self.env.mode === 'edit') return ;
|
||||
this.ksUpdateDashboard = {};
|
||||
var domain = [];
|
||||
var partner_id;
|
||||
var final_active;
|
||||
// var myChart = self.chart_container[item_id];
|
||||
var index;
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id];
|
||||
var groupBy = JSON.parse(item_data["ks_chart_data"])['groupby'];
|
||||
var labels = JSON.parse(item_data["ks_chart_data"])['labels'];
|
||||
var domains = JSON.parse(item_data["ks_chart_data"])['domains'];
|
||||
var sequnce = item_data.sequnce ? item_data.sequnce : 0;
|
||||
// $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_breadcrumb").removeClass("d-none")
|
||||
var chart_title = '#'+item.name
|
||||
// if (item.ks_dashboard_item_type == "ks_bullet_chart" || item.ks_dashboard_item_type === "ks_funnel_chart" || item.ks_dashboard_item_type === "ks_flower_view" || item.ks_dashboard_item_type === "ks_radialBar_chart"){
|
||||
if (evt.target.dataItem){
|
||||
var activePoint = evt.target.dataItem.dataContext;
|
||||
}
|
||||
|
||||
if (activePoint) {
|
||||
if (activePoint.category){
|
||||
for (let i=0 ; i<labels.length ; i++){
|
||||
if (labels[i] == activePoint.category){
|
||||
index = i
|
||||
}
|
||||
}
|
||||
domain = domains[index]
|
||||
}
|
||||
else if (activePoint.stage){
|
||||
for (let i=0 ; i<labels.length ; i++){
|
||||
if (labels[i] == activePoint.stage){
|
||||
index = i
|
||||
}
|
||||
}
|
||||
domain = domains[index]
|
||||
}
|
||||
|
||||
if (typeof domain === 'object' && domain !== null && !Array.isArray(domain)) {
|
||||
domain = domain[evt.target.dataItem.component._settings.name]
|
||||
}
|
||||
|
||||
if (item_data.max_sequnce != 0 && sequnce < item_data.max_sequnce) {
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/ks_fetch_drill_down_data",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'ks_fetch_drill_down_data',
|
||||
args: [item_id, domain, sequnce],
|
||||
kwargs : {},
|
||||
}).then((result) => {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['isDrill'] = true;
|
||||
if (result.ks_chart_data) {
|
||||
|
||||
var chart_id_name = '#item'+'_' +'-1'
|
||||
var id_name = '#'+result.ks_action_name + '_' + (result.sequence-1)
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = result.ks_chart_type;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_chart_data'] = result.ks_chart_data;
|
||||
if (self.ks_dashboard_data.ks_item_data[item_id].domains) {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_chart_data).previous_domain;
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'] = {}
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_chart_data).previous_domain;
|
||||
}
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_chart_heading").addClass("d-none")
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(id_name).removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block ');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none');
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty();
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
if(item_data.ks_dashboard_item_type == 'ks_funnel_chart'){
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove();
|
||||
ksrenderfunnelchart.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"),item_data, 'dashboard_view');
|
||||
}else{
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove();
|
||||
ks_render_graphs.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data, self.props.dashboard_data.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
} else {
|
||||
if ('domains' in self.ks_dashboard_data.ks_item_data[item_id]) {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_list_view_data).previous_domain;
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'] = {}
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['domains'][result.sequence] = JSON.parse(result.ks_list_view_data).previous_domain;
|
||||
}
|
||||
var chart_id_name = '#item'+'_' +'-1'
|
||||
var id_name = '#'+result.ks_action_name + '_' + (result.sequence-1)
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['isDrill'] = true;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_data'] = result.ks_list_view_data;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_type'] = result.ks_list_view_type;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = 'ks_list_view';
|
||||
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_chart_heading").addClass("d-none")
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).removeClass('d-none');
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none');
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(id_name).removeClass('d-none');
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty();
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").removeClass('d-sm-block ');
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").addClass('table-responsive');
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
self.item = item_data
|
||||
self.prepare_list();
|
||||
var list_view_data = JSON.parse(item_data['ks_list_view_data'])
|
||||
var $container = renderToElement('ks_dashboard_ninja.ks_new_list_view_table',{
|
||||
list_view_data, self, item_id:self.item_id, markup, state: { list_view_data }
|
||||
})
|
||||
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").append($container);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (item_data.action) {
|
||||
var action = Object.assign({}, item_data.action);
|
||||
if (action.view_mode.includes('tree')) action.view_mode = action.view_mode.replace('tree', 'list');
|
||||
for (var i = 0; i < action.views.length; i++) action.views[i][1].includes('tree') ? action.views[i][1] = action.views[i][1].replace('tree', 'list') : action.views[i][1];
|
||||
action['domain'] = domain || [];
|
||||
action['search_view_id'] = [action.search_view_id, 'search']
|
||||
} else {
|
||||
var action = {
|
||||
name: _t(item_data.name),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: item_data.ks_model_name,
|
||||
domain: domain || [],
|
||||
context: {
|
||||
'group_by': groupBy ? groupBy:false ,
|
||||
},
|
||||
views: [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
],
|
||||
view_mode: 'list',
|
||||
target: 'current',
|
||||
}
|
||||
}
|
||||
if (item_data.ks_show_records && action) {
|
||||
|
||||
self.actionService.doAction(action, {
|
||||
on_reverse_breadcrumb: self.on_reverse_breadcrumb,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ksOnDrillUp(e) {
|
||||
var self = this;
|
||||
var item_id = e.currentTarget.dataset.itemId;
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id];
|
||||
var domain;
|
||||
var chart_name = '#'+item_data.name
|
||||
var sequence = parseInt(e.currentTarget.dataset.sequence)
|
||||
var chart_id_name = '#item'+'_' +'-1'
|
||||
if(item_data) {
|
||||
|
||||
if ('domains' in item_data) {
|
||||
domain = item_data['domains'][sequence+1] ? item_data['domains'][sequence+1] : []
|
||||
var sequnce = sequence;
|
||||
if (sequnce >= 0) {
|
||||
self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/ks_fetch_drill_down_data",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'ks_fetch_drill_down_data',
|
||||
args: [item_id, domain, sequnce],
|
||||
kwargs:{}
|
||||
}).then((result) => {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_chart_data'] = result.ks_chart_data;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['sequnce'] = result.sequence;
|
||||
var id_name = '#'+result.ks_action_name + '_' + sequence;
|
||||
var ks_breadcrumb_elements = $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(id_name).nextAll();
|
||||
if (result.ks_chart_type) {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = result.ks_chart_type;
|
||||
self.item.ks_dashboard_item_type = result.ks_chart_type
|
||||
}
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").empty();
|
||||
if (result.ks_chart_data) {
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id];
|
||||
ks_breadcrumb_elements.each(function(index,item){
|
||||
$(item).addClass("d-none")
|
||||
})
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none')
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".card-body").remove()
|
||||
if (result.ks_chart_type == "ks_funnel_chart"){
|
||||
ksrenderfunnelchart.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"),item_data, 'dashboard_view');
|
||||
}else{
|
||||
ks_render_graphs.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]"), item_data, self.props.dashboard_data.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
} else {
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_data'] = result.ks_list_view_data;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_list_view_type'] = result.ks_list_view_type;
|
||||
self.ks_dashboard_data.ks_item_data[item_id]['ks_dashboard_item_type'] = 'ks_list_view';
|
||||
self.item.ks_dashboard_item_type = 'ks_list_view';
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id]
|
||||
ks_breadcrumb_elements.each(function(index,item){
|
||||
$(item).addClass("d-none")
|
||||
})
|
||||
self.prepare_list(item_data);
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_pager").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").addClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").addClass('d-none')
|
||||
var list_view_data = JSON.parse(item_data['ks_list_view_data'])
|
||||
|
||||
var $container = renderToElement('ks_dashboard_ninja.ks_new_list_view_table',{
|
||||
list_view_data,item_id:self.item_id,self, markup, state: { list_view_data }
|
||||
})
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".card-body").append($container);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
} else {
|
||||
var ks_breadcrumb_elements = $($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).nextAll();
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(chart_id_name).addClass('d-none');
|
||||
ks_breadcrumb_elements.each(function(index,item){
|
||||
$(item).addClass("d-none")
|
||||
})
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_chart_heading").removeClass("d-none")
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").find(".ks_list_view_heading").removeClass("d-none")
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").addClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_chart_info").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_color_option").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_quick_edit_action_popup").addClass('d-sm-block ');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_more_action").removeClass('d-none');
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_action_export").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_plus").removeClass('d-none')
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_search_minus").removeClass('d-none')
|
||||
self.ksFetchChartItem(item_id)
|
||||
var updateValue = self.ks_dashboard_data.ks_set_interval;
|
||||
}
|
||||
|
||||
} else {
|
||||
if(!domain){
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_id + "]").children()[0]).find(".ks_dashboard_item_drill_up").addClass('d-none');
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
ksFetchChartItem(id) {
|
||||
var self = this;
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[id];
|
||||
|
||||
return self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_fetch_item",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_item',
|
||||
args: [
|
||||
[item_data.id], self.ks_dashboard_data.ks_dashboard_id, {}
|
||||
],
|
||||
kwargs:{},
|
||||
}).then((new_item_data) => {
|
||||
this.ks_dashboard_data.ks_item_data[id] = new_item_data[id];
|
||||
this.ks_dashboard_data.ks_item_data[id]['ks_dashboard_item_type'] = new_item_data[id].ks_dashboard_item_type
|
||||
this.item.ks_dashboard_item_type = new_item_data[id].ks_dashboard_item_type
|
||||
$($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + id + "]").children()[0]).find(".card-body").empty();
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[id]
|
||||
if (item_data.ks_list_view_data) {
|
||||
self.actionService.doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "reload",
|
||||
});
|
||||
}else if(item_data.ks_dashboard_item_type == 'ks_funnel_chart'){
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove();
|
||||
var name = item_data.name ?item_data.name : item_data.ks_model_display_name;
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').prop('title',name)
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]").find('.ks_chart_heading').text(name)
|
||||
ksrenderfunnelchart.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]"),item_data, 'dashboard_view');
|
||||
}else{
|
||||
$(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove();
|
||||
ks_render_graphs.bind(this)($(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + id + "]"), item_data, self.props.dashboard_data.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
ksRenderChartColorOptions(e) {
|
||||
var self = this;
|
||||
if (!$(e.currentTarget).parent().hasClass('global-active')) {
|
||||
// FIXME : Correct this later.
|
||||
var $parent = $(e.currentTarget).parent().parent();
|
||||
$parent.find('.global-active').removeClass('global-active')
|
||||
$(e.currentTarget).parent().addClass('global-active')
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[$parent.data().itemId];
|
||||
var chart_data = JSON.parse(item_data.ks_chart_data);
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/write",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'write',
|
||||
args: [$parent.data().itemId, {
|
||||
"ks_chart_item_color": e.currentTarget.dataset.chartColor
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(() => {
|
||||
self.ks_dashboard_data.ks_item_data[$parent.data().itemId]['ks_chart_item_color'] = e.target.dataset.chartColor;
|
||||
$(".grid-stack-item[gs-id=" + item_data.id + "]").find(".card-body").remove();
|
||||
if (item_data.ks_dashboard_item_type == 'ks_funnel_chart'){
|
||||
ksrenderfunnelchart.bind(this)($(self.ks_gridstack_container.el), item_data, 'dashboard_view');
|
||||
}else{
|
||||
ks_render_graphs.bind(this)($(self.ks_gridstack_container.el),item_data, self.props.dashboard_data.zooming_enabled, 'dashboard_view');
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
ksLoadMoreRecords(e) {
|
||||
var self = this;
|
||||
var ks_intial_count = e.target.parentElement.dataset.prevOffset;
|
||||
var ks_offset = e.target.parentElement.dataset.next_offset;
|
||||
var itemId = e.currentTarget.dataset.itemId;
|
||||
var offset = self.ks_dashboard_data.ks_item_data[itemId].ks_pagination_limit;
|
||||
var context = self.ks_dashboard_data['context']
|
||||
var params;
|
||||
params = self.env.ksGetParamsForItemFetch(parseInt(itemId));
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_get_list_view_data_offset",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_get_list_view_data_offset',
|
||||
args: [parseInt(itemId), {
|
||||
ks_intial_count: ks_intial_count,
|
||||
offset: ks_offset,
|
||||
}, parseInt(self.ks_dashboard_data.ks_dashboard_id), params],
|
||||
kwargs:{context: self.env.getContext()}
|
||||
}).then(function(result) {
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[itemId];
|
||||
if(result.ks_list_view_data){
|
||||
result.ks_list_view_data = convert_data_to_utc(result.ks_list_view_data)
|
||||
}
|
||||
var item_view = $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]");
|
||||
self.item.ks_list_view_data = result.ks_list_view_data;
|
||||
self.prepare_list();
|
||||
$(e.target).parents('.ks_pager').find('.ks_value').text(result.offset + "-" + result.next_offset);
|
||||
e.target.parentElement.dataset.next_offset = result.next_offset;
|
||||
e.target.parentElement.dataset.prevOffset = result.offset;
|
||||
$(e.target.parentElement).find('.ks_load_previous').removeClass('ks_event_offer_list');
|
||||
if (result.next_offset < parseInt(result.offset) + (offset - 1) || result.next_offset == item_data.ks_record_count || result.next_offset === result.limit){
|
||||
$(e.target).addClass('ks_event_offer_list');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ksLoadPreviousRecords(e) {
|
||||
var self = this;
|
||||
var itemId = e.currentTarget.dataset.itemId;
|
||||
var offset = self.ks_dashboard_data.ks_item_data[itemId].ks_pagination_limit;
|
||||
var ks_offset = parseInt(e.target.parentElement.dataset.prevOffset) - (offset + 1) ;
|
||||
var ks_intial_count = e.target.parentElement.dataset.next_offset;
|
||||
var context = self.ks_dashboard_data['context']
|
||||
var params;
|
||||
params = self.env.ksGetParamsForItemFetch(parseInt(itemId));
|
||||
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_get_list_view_data_offset",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_get_list_view_data_offset',
|
||||
args: [parseInt(itemId), {
|
||||
ks_intial_count: ks_intial_count,
|
||||
offset: ks_offset,
|
||||
}, parseInt(self.ks_dashboard_data.ks_dashboard_id), params],
|
||||
kwargs:{context: self.env.getContext()}
|
||||
}).then(function(result) {
|
||||
if(result.ks_list_view_data){
|
||||
result.ks_list_view_data = convert_data_to_utc(result.ks_list_view_data)
|
||||
}
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[itemId];
|
||||
var item_view = $(".ks_dashboard_main_content").find(".grid-stack-item[gs-id=" + item_data.id + "]");
|
||||
self.item.ks_list_view_data = result.ks_list_view_data;
|
||||
self.prepare_list();
|
||||
$(e.target).parents('.ks_pager').find('.ks_value').text(result.offset + "-" + result.next_offset);
|
||||
e.target.parentElement.dataset.next_offset = result.next_offset;
|
||||
e.target.parentElement.dataset.prevOffset = result.offset;
|
||||
$(e.target.parentElement).find('.ks_load_next').removeClass('ks_event_offer_list');
|
||||
if (result.offset === 1) {
|
||||
$(e.target).addClass('ks_event_offer_list');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ksOnListItemInfoClick(e) {
|
||||
var self = this;
|
||||
var item_id = e.currentTarget.dataset.itemId;
|
||||
var item_data = self.ks_dashboard_data.ks_item_data[item_id];
|
||||
var action = {
|
||||
name: _t(item_data.name),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: e.currentTarget.dataset.model,
|
||||
domain: item_data.ks_domain || [],
|
||||
views: [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
],
|
||||
target: 'current',
|
||||
}
|
||||
if (e.currentTarget.dataset.listViewType === "ungrouped") {
|
||||
action['view_mode'] = 'form';
|
||||
action['views'] = [
|
||||
[false, 'form']
|
||||
];
|
||||
action['res_id'] = parseInt(e.currentTarget.dataset.recordId);
|
||||
} else {
|
||||
if (e.currentTarget.dataset.listType === "date_type") {
|
||||
var domain = JSON.parse(e.currentTarget.parentElement.parentElement.dataset.domain);
|
||||
action['view_mode'] = 'list';
|
||||
action['context'] = {
|
||||
'group_by': e.currentTarget.dataset.groupby,
|
||||
};
|
||||
action['domain'] = domain;
|
||||
} else if (e.currentTarget.dataset.listType === "relational_type") {
|
||||
var domain = JSON.parse(e.currentTarget.parentElement.parentElement.dataset.domain);
|
||||
action['view_mode'] = 'list';
|
||||
action['context'] = {
|
||||
'group_by': e.currentTarget.dataset.groupby,
|
||||
};
|
||||
action['domain'] = domain;
|
||||
action['context']['search_default_' + e.currentTarget.dataset.groupby] = parseInt(e.currentTarget.dataset.recordId);
|
||||
} else if (e.currentTarget.dataset.listType === "other") {
|
||||
var domain = JSON.parse(e.currentTarget.parentElement.parentElement.dataset.domain);
|
||||
action['view_mode'] = 'list';
|
||||
action['context'] = {
|
||||
'group_by': e.currentTarget.dataset.groupby,
|
||||
};
|
||||
action['context']['search_default_' + e.currentTarget.dataset.groupby] = parseInt(e.currentTarget.dataset.recordId);
|
||||
action['domain'] = domain;
|
||||
}
|
||||
}
|
||||
self.actionService.doAction(action)
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Ksdashboardgraph.props = {
|
||||
item: { type: Object, optional: true},
|
||||
dashboard_data: { type: Object, optional: true},
|
||||
ksdatefilter : { type: String ,optional: true},
|
||||
pre_defined_filter :{ type:Object, optional: true},
|
||||
custom_filter :{ type:Object, optional: true},
|
||||
itemsToUpdateList : { type: Array, optional: true },
|
||||
ks_speak:{ type: Function , optional: true},
|
||||
hideButtons: { type: Number, optional: true },
|
||||
generate_dialog: { type: Boolean, optional: true },
|
||||
explain_ai_whole: { type: Boolean, optional: true },
|
||||
onItemClick: { type: Function },
|
||||
};
|
||||
|
||||
Ksdashboardgraph.template = "Ks_chart_list_container";
|
||||
Ksdashboardgraph.components = { KsItemButton };
|
||||
@@ -0,0 +1,108 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="Ks_chart_list_container">
|
||||
<t t-if="item.ks_dashboard_item_type == 'ks_list_view'">
|
||||
<t t-call="ks_dashboard_ninja.Ksdashboardlistview"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="Ks_gridstack_container"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="Ks_gridstack_container">
|
||||
|
||||
|
||||
|
||||
<div class="grid-stack-item ks_tile_carousel ks_chart_container ks_dashboarditem_id" t-att-id="chart_id" t-ref="ks_gridstack_container">
|
||||
<div class="grid-stack-item-content ks_dashboarditem_chart_container ks_border_radius ks_dashboard_item_hover dashboard-container d-flex flex-fill flex-column border-0"
|
||||
t-att-title="ks_info" t-att-id="chart_id">
|
||||
|
||||
<t t-if="!env.isExplainDashboardWithAi">
|
||||
<div class="dashboard-header position-relative py-3 mb-1 px-3 d-flex justify-content-between align-items-center">
|
||||
<div class="d-flex align-items-center w-50">
|
||||
<h4 class="ks_chart_heading text-capitalize text-start" t-att-title="ks_chart_title">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</h4>
|
||||
<!-- <div >-->
|
||||
<t t-if="ks_breadcrumb.length >= 1">
|
||||
<nav class="ks_breadcrumb">
|
||||
<ul>
|
||||
<li class="d-none" t-att-id="'item'+'_'+'-1'">
|
||||
<span t-att-data-sequence = '-1' t-att-data-item-id="chart_id" t-on-click="ksOnDrillUp">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</span>
|
||||
</li>
|
||||
<t t-foreach="ks_breadcrumb" t-as="chart_breadcrumb" t-key="chart_breadcrumb_index">
|
||||
<li class="d-none" t-att-id="chart_breadcrumb['name'] + '_' + chart_breadcrumb_index">
|
||||
<span t-att-data-sequence="chart_breadcrumb_index" t-att-data-item-id="chart_id" t-on-click="ksOnDrillUp">
|
||||
<t t-esc="chart_breadcrumb['name']"/>
|
||||
</span>
|
||||
</li>
|
||||
</t>
|
||||
<!-- <t t-if="state.explain_ai">-->
|
||||
</ul>
|
||||
</nav>
|
||||
</t>
|
||||
</div>
|
||||
<!-- </div>-->
|
||||
<img src="/ks_dashboard_ninja/static/images/selected.svg" class="ks_img_display d-none" width="30"/>
|
||||
<div class="select-btn d-none">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.0001 18.3332C14.5834 18.3332 18.3334 14.5832 18.3334 9.99984C18.3334 5.4165 14.5834 1.6665 10.0001 1.6665C5.41675 1.6665 1.66675 5.4165 1.66675 9.99984C1.66675 14.5832 5.41675 18.3332 10.0001 18.3332Z"
|
||||
stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M6.45825 9.99993L8.81659 12.3583L13.5416 7.6416" stroke="" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<KsItemButton item_data="this.item" itemRootRef="this.ks_gridstack_container"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec">
|
||||
<h4 class="ks_chart_heading text-capitalize text-start" t-att-title="ks_chart_title">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</h4>
|
||||
<div class="card-body ks_chart_card_body charts-sec"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<!-- <div class="ks_ai_explanation">-->
|
||||
<p><t t-esc="ks_ai_analysis_1"/></p>
|
||||
<p><t t-esc="ks_ai_analysis_2"/></p>
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="mt-1 card-body ks_chart_card_body"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,457 @@
|
||||
/** @odoo-module **/
|
||||
import { Component,useState ,onWillUpdateProps,useEffect,onMounted,useRef, onWillUnmount} from "@odoo/owl";
|
||||
import {globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { formatFloat } from "@web/core/utils/numbers";
|
||||
import { formatInteger } from "@web/views/fields/formatters";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { onAudioEnded } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { KsItemButton } from '@ks_dashboard_ninja/components/chart_buttons/chart_buttons';
|
||||
|
||||
export class Ksdashboardkpiview extends Component{
|
||||
file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
|
||||
setup(){
|
||||
var self = this;
|
||||
this._rpc = rpc
|
||||
this.actionService = useService("action");
|
||||
this.ks_kpi = useRef('ks_kpi')
|
||||
this.aiAudioRef = useRef("aiAudioRef");
|
||||
|
||||
this.ksAllowItemClick = false;
|
||||
this.state = useState({item_info_kpi1:{},item_info_kpi2:{},item_info_kpi3:{}})
|
||||
onMounted(() => this._update_view());
|
||||
this.item = this.props.item
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.item.ksIsDashboardManager = this.props.dashboard_data.ks_dashboard_manager
|
||||
this.item.ks_dashboard_list = this.props.dashboard_data.ks_dashboard_list
|
||||
this.classname = ' encapsulated-kpi-tile ks_dashboard_kpi ks_dashboard_kpi_dashboard ks_dashboard_custom_srollbar ks_dashboarditem_id ks_dashboard_item_hover ks_db_item_preview_color_picker grid-stack-item-content'
|
||||
this.ks_ai_analysis = this.props.dashboard_data.ks_ai_explain_dash
|
||||
if (this.ks_ai_analysis){
|
||||
this.reviewclass = 'ks_ai_explain_tile'
|
||||
}else{
|
||||
this.reviewclass = ''
|
||||
}
|
||||
if (this.item.ks_ai_analysis && this.item.ks_ai_analysis){
|
||||
var ks_analysis = this.item.ks_ai_analysis.split('ks_gap')
|
||||
this.ks_ai_analysis_1 = ks_analysis[0]
|
||||
this.ks_ai_analysis_2 = ks_analysis[1]
|
||||
}
|
||||
this.prepareKpiData();
|
||||
var update_interval = this.props.dashboard_data.ks_set_interval
|
||||
onWillUpdateProps( async (nextprops) => {
|
||||
if (nextprops?.itemsToUpdateList?.length){
|
||||
if (nextprops.itemsToUpdateList?.includes(this.item.id)){
|
||||
await this.ksFetchUpdateItem(this.item.id)
|
||||
}
|
||||
}
|
||||
})
|
||||
onWillUnmount( () => {
|
||||
this.aiAudioRef.el?.removeEventListener('ended', onAudioEnded)
|
||||
})
|
||||
}
|
||||
ksFetchUpdateItem(item_id) {
|
||||
var self = this;
|
||||
return rpc("/web/dataset/call_kw",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_item',
|
||||
args: [
|
||||
[parseInt(item_id)], self.ks_dashboard_data.ks_dashboard_id, self.env.ksGetParamsForItemFetch(self.item.id)
|
||||
],
|
||||
kwargs: { context: self.env.getContext() },
|
||||
}).then(function(new_item_data) {
|
||||
this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id];
|
||||
this.item = this.ks_dashboard_data.ks_item_data[item_id] ;
|
||||
this.__owl__.parent.component.ks_dashboard_data.ks_item_data[this.item.id] = new_item_data[item_id]
|
||||
this.prepareKpiData()
|
||||
this._update_view();
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
get isMobile() {
|
||||
return isMobileOS();
|
||||
}
|
||||
|
||||
_update_view(){
|
||||
if(!this.kpi_data[1]){
|
||||
if (this.field.ks_target_view === "Progress Bar" && this.field.ks_goal_enable) {
|
||||
if(this.ks_kpi.el?.querySelector('#ks_progressbar')){
|
||||
this.ks_kpi.el.querySelector('#ks_progressbar').value = this.target_deviation ? parseInt(this.target_deviation) : 0
|
||||
}
|
||||
}
|
||||
if (this.field.ks_goal_enable) {
|
||||
const targetDeviationElement = this.ks_kpi.el?.querySelector(".target_deviation");
|
||||
if(targetDeviationElement)
|
||||
targetDeviationElement.style.color = this.state.item_info_kpi1.target_arrow === 'up' ? 'green' : 'red';
|
||||
}
|
||||
var ks_valid_date_selection = ['l_day', 't_week', 't_month', 't_quarter', 't_year'];
|
||||
if (this.field.ks_previous_period && String(this.state.item_info_kpi1.previous_period_data) && ks_valid_date_selection.indexOf(this.ks_date_filter_selection) >= 0) {
|
||||
const preDeviationElement = this.ks_kpi.el?.querySelector(".pre_deviation");
|
||||
if(preDeviationElement)
|
||||
preDeviationElement.style.color = this.state.item_info_kpi1.pre_arrow === 'up' ? 'green' : 'red';
|
||||
}
|
||||
const ksTargetPreviousElement = this.ks_kpi.el?.querySelector('.ks_target_previous');
|
||||
if (ksTargetPreviousElement?.children?.length !== 2)
|
||||
ksTargetPreviousElement?.classList.add('justify-content-center');
|
||||
}else{
|
||||
if (this.field.ks_data_comparison === 'Sum') {
|
||||
if(this.ks_kpi.el?.querySelector('.target_deviation')) {
|
||||
const targetDeviationElement = this.ks_kpi.el.querySelector('.target_deviation');
|
||||
if(targetDeviationElement)
|
||||
targetDeviationElement.style.color = this.state.item_info_kpi2.ks_color;
|
||||
}
|
||||
if (this.field.ks_goal_enable && this.field.ks_target_view === "Progress Bar") {
|
||||
const progressBarElement = this.ks_kpi.el.querySelector('#ks_progressbar');
|
||||
const targetDeviation = (this.ks_target_deviation === Infinity || this.ks_target_deviation === -Infinity) ? 0 : this.ks_target_deviation;
|
||||
if (!isNaN(targetDeviation) && targetDeviation >= 0 && targetDeviation <= 100) {
|
||||
progressBarElement.value = parseInt(targetDeviation);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.field.ks_data_comparison === 'Percentage') {
|
||||
const targetDeviationElement = this.ks_kpi.el?.querySelector('.target_deviation');
|
||||
if(targetDeviationElement){
|
||||
targetDeviationElement.style.color = this.state.item_info_kpi2.ks_color;
|
||||
}
|
||||
|
||||
if (this.field.ks_goal_enable && this.field.ks_target_view === "Progress Bar") {
|
||||
const progressBarElement = this.ks_kpi.el.querySelector('#ks_progressbar');
|
||||
if (this.state.item_info_kpi2.count) {
|
||||
const countValue = (this.count === Infinity || this.count === -Infinity) ? 0 : this.count;
|
||||
progressBarElement.value = parseInt(countValue);
|
||||
} else {
|
||||
progressBarElement.value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
const dashboardItem = this.ks_kpi.el.querySelector('.ks_dashboarditem_id');
|
||||
dashboardItem.style.backgroundColor = this.ks_rgba_background_color;
|
||||
dashboardItem.style.color = this.ks_rgba_font_color;
|
||||
this.aiAudioRef.el?.addEventListener('ended', onAudioEnded)
|
||||
}
|
||||
|
||||
ksSum(count_1, count_2, item_info, field, target_1, kpi_data) {
|
||||
var self = this;
|
||||
var count = count_1 + count_2;
|
||||
if (field.ks_multiplier_active){
|
||||
item_info['count'] = globalfunction._onKsGlobalFormatter(count* field.ks_multiplier, field.ks_data_format, field.ks_precision_digits);
|
||||
item_info['count_tooltip'] = formatFloat(count * field.ks_multiplier,{digits:[0,field.ks_precision_digits]});
|
||||
}else{
|
||||
|
||||
item_info['count'] = globalfunction._onKsGlobalFormatter(count, field.ks_data_format, field.ks_precision_digits);
|
||||
item_info['count_tooltip'] = formatFloat(parseFloat(count), Float64Array, {digits:[0,field.ks_precision_digits]});
|
||||
}
|
||||
if (field.ks_multiplier_active){
|
||||
count = count * field.ks_multiplier;
|
||||
}
|
||||
var ks_selection = field.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = field.ks_currency_id[0];
|
||||
var ks_data = globalfunction.ks_monetary(item_info['count'], ks_currency_id);
|
||||
item_info['count'] = ks_data;
|
||||
} else if (ks_selection === 'custom') {
|
||||
var ks_field = field.ks_chart_unit;
|
||||
item_info['count']= ks_field+" "+item_info['count']
|
||||
}
|
||||
|
||||
item_info['target_enable'] = field.ks_goal_enable;
|
||||
item_info['ks_color'] = (target_1 - count) > 0 ? "red" : "green";
|
||||
item_info.pre_arrow = (target_1 - count) > 0 ? "down" : "up";
|
||||
item_info['ks_comparison'] = true;
|
||||
this.target_deviation = (target_1 - count) > 0 ? Math.round(((target_1 - count) / target_1) * 100) : Math.round((Math.abs((target_1 - count)) / target_1) * 100);
|
||||
this.ks_target_deviation = Math.round((count / target_1) * 100);
|
||||
if (this.target_deviation !== Infinity) item_info.target_deviation = formatInteger(this.target_deviation) + "%";
|
||||
else {
|
||||
item_info.target_deviation = this.target_deviation;
|
||||
item_info.pre_arrow = false;
|
||||
}
|
||||
var target_progress_deviation = target_1 == 0 ? 0 : Math.round((count / target_1) * 100);
|
||||
item_info.target_progress_deviation = formatInteger(target_progress_deviation) + "%";
|
||||
return item_info
|
||||
}
|
||||
|
||||
ksPercentage(count_1, count_2, field, item_info, target_1, kpi_data) {
|
||||
if (field.ks_multiplier_active){
|
||||
count_1 = count_1 * field.ks_multiplier;
|
||||
count_2 = count_2 * field.ks_multiplier;
|
||||
}
|
||||
if (field.ks_data_format=="exact"){
|
||||
var count = (count_1 / count_2) * 100;
|
||||
}
|
||||
else{
|
||||
var count = parseInt((count_1 / count_2) * 100);
|
||||
}
|
||||
if (field.ks_multiplier_active){
|
||||
count = count * field.ks_multiplier;
|
||||
}
|
||||
if (field.ks_data_format=='exact'){
|
||||
item_info['count'] = count ? formatFloat(count, {digits: [0, 2]}) + "%" : "0%";
|
||||
}
|
||||
else{
|
||||
item_info['count'] = count ? formatInteger(count) + "%" : "0%";
|
||||
|
||||
}
|
||||
item_info['count_tooltip'] = count ? count + "%" : "0%";
|
||||
item_info.target_progress_deviation = item_info['count']
|
||||
target_1 = target_1 > 100 ? 100 : target_1;
|
||||
item_info.target = target_1 + "%";
|
||||
item_info.pre_arrow = (target_1 - count) > 0 ? "down" : "up";
|
||||
item_info['ks_color'] = (target_1 - count) > 0 ? "red" : "green";
|
||||
item_info['target_enable'] = field.ks_goal_enable;
|
||||
item_info['ks_comparison'] = false;
|
||||
item_info.target_deviation = item_info.target > 100 ? 100 : item_info.target;
|
||||
this.count = Math.round(count) ? Math.round(count) :0
|
||||
return item_info
|
||||
}
|
||||
|
||||
prepareKpiData() {
|
||||
// if(!kpi_data) return
|
||||
var self = this;
|
||||
var field = this.item;
|
||||
this.ks_date_filter_selection = field.ks_date_filter_selection;
|
||||
if (field.ks_date_filter_selection === "l_none") this.ks_date_filter_selection = self.ks_dashboard_data.ks_date_filter_selection;
|
||||
var ks_valid_date_selection = ['l_day', 't_week', 't_month', 't_quarter', 't_year'];
|
||||
var kpi_data = JSON.parse(field.ks_kpi_data);
|
||||
var count_1 = kpi_data[0] ? kpi_data[0].record_data: undefined;
|
||||
var count_2 = kpi_data[1] ? kpi_data[1].record_data : undefined;
|
||||
var target_1 = kpi_data[0] ? kpi_data[0].target : undefined;
|
||||
var target_view = field.ks_target_view,
|
||||
pre_view = field.ks_prev_view;
|
||||
this.ks_rgba_background_color = self._ks_get_rgba_format(field.ks_background_color);
|
||||
var ks_rgba_button_color = self._ks_get_rgba_format(field.ks_button_color);
|
||||
this.ks_rgba_font_color = self._ks_get_rgba_format(field.ks_font_color);
|
||||
if (field.ks_goal_enable) {
|
||||
var diffrence = 0.0
|
||||
if(field.ks_multiplier_active){
|
||||
diffrence = (count_1 * field.ks_multiplier) - target_1
|
||||
}else{
|
||||
diffrence = count_1 - target_1
|
||||
}
|
||||
var acheive = diffrence >= 0 ? true : false;
|
||||
diffrence = Math.abs(diffrence);
|
||||
var deviation = Math.round((diffrence / target_1) * 100)
|
||||
if (deviation !== Infinity) deviation = deviation ? formatInteger(deviation) + '%' : 0 + '%';
|
||||
}
|
||||
if (field.ks_previous_period && ks_valid_date_selection.indexOf(this.ks_date_filter_selection) >= 0) {
|
||||
var previous_period_data = kpi_data[0].previous_period;
|
||||
var pre_diffrence = (count_1 - previous_period_data);
|
||||
if (field.ks_multiplier_active){
|
||||
var previous_period_data = kpi_data[0].previous_period * field.ks_multiplier;
|
||||
var pre_diffrence = (count_1 * field.ks_multiplier - previous_period_data);
|
||||
}
|
||||
var pre_acheive = pre_diffrence > 0 ? true : false;
|
||||
pre_diffrence = Math.abs(pre_diffrence);
|
||||
var pre_deviation = previous_period_data ? formatInteger(parseInt((pre_diffrence / previous_period_data) * 100)) + '%' : "100%"
|
||||
}
|
||||
if (this.item.ks_info){
|
||||
var ks_description = this.item.ks_info.replace?.(/\\n/g, '\n').split?.('\n');
|
||||
var ks_description = ks_description.filter(element => element !== '')?.join?.(' ') ?? false
|
||||
}else {
|
||||
var ks_description = false;
|
||||
}
|
||||
this.item['ksIsDashboardManager'] = self.ks_dashboard_data.ks_dashboard_manager;
|
||||
this.item['ksIsUser'] = true;
|
||||
// if (this.item.ks_tv_play){
|
||||
// this.item['ksIsUser'] = false;
|
||||
// }
|
||||
var ks_icon_url;
|
||||
if (field.ks_icon_select == "Custom") {
|
||||
if (field.ks_icon[0]) {
|
||||
ks_icon_url = 'data:image/' + (self.file_type_magic_word[field.ks_icon[0]] || 'png') + ';base64,' + field.ks_icon;
|
||||
} else {
|
||||
ks_icon_url = false;
|
||||
}
|
||||
}
|
||||
var target_progress_deviation = String(Math.round((count_1 / target_1) * 100));
|
||||
if(field.ks_multiplier_active){
|
||||
var target_progress_deviation = String(Math.round(((count_1 * field.ks_multiplier) / target_1) * 100));
|
||||
}
|
||||
var ks_rgba_icon_color = self._ks_get_rgba_format(field.ks_default_icon_color)
|
||||
var item_info = {
|
||||
item: this.item,
|
||||
id: field.id,
|
||||
count_1: globalfunction.ksNumFormatter(kpi_data[0]['record_data'], 1),
|
||||
count_1_tooltip: kpi_data[0]['record_data'],
|
||||
count_2: kpi_data[1] ? String(kpi_data[1]['record_data']) : false,
|
||||
name: field.name ? field.name : field.ks_model_id.data.display_name,
|
||||
target_progress_deviation:target_progress_deviation,
|
||||
icon_select: field.ks_icon_select,
|
||||
default_icon: field.ks_default_icon,
|
||||
icon_color: ks_rgba_icon_color,
|
||||
target_deviation: deviation,
|
||||
target_arrow: acheive ? 'up' : 'down',
|
||||
ks_enable_goal: field.ks_goal_enable,
|
||||
ks_previous_period: ks_valid_date_selection.indexOf(this.ks_date_filter_selection) >= 0 ? field.ks_previous_period : false,
|
||||
target: globalfunction.ksNumFormatter(target_1, 1),
|
||||
previous_period_data: previous_period_data,
|
||||
pre_deviation: pre_deviation,
|
||||
pre_arrow: pre_acheive ? 'up' : 'down',
|
||||
target_view: field.ks_target_view,
|
||||
pre_view: field.ks_prev_view,
|
||||
ks_dashboard_list: self.ks_dashboard_data.ks_dashboard_list,
|
||||
ks_icon_url: ks_icon_url,
|
||||
ks_rgba_button_color:ks_rgba_button_color,
|
||||
ks_info: ks_description,
|
||||
}
|
||||
this.previous_period_data = previous_period_data
|
||||
|
||||
this.target_deviation = parseInt(item_info.target_progress_deviation) ? parseInt(item_info.target_progress_deviation) : "0"
|
||||
// if (item_info.target_deviation === Infinity) item_info.target_arrow = false;
|
||||
item_info.target_progress_deviation = parseInt(item_info.target_progress_deviation) ? formatInteger(parseInt(item_info.target_progress_deviation)) : "0"
|
||||
if (field.ks_multiplier_active){
|
||||
item_info['count_1'] = globalfunction._onKsGlobalFormatter(kpi_data[0]['record_data'] * field.ks_multiplier, field.ks_data_format, field.ks_precision_digits);
|
||||
item_info['count_1_tooltip'] = kpi_data[0]['record_data'] * field.ks_multiplier
|
||||
}else{
|
||||
item_info['count_1'] = globalfunction._onKsGlobalFormatter(kpi_data[0]['record_data'], field.ks_data_format, field.ks_precision_digits);
|
||||
}
|
||||
if (kpi_data[0].target){
|
||||
item_info['target'] = globalfunction._onKsGlobalFormatter(kpi_data[0].target, field.ks_data_format, field.ks_precision_digits);
|
||||
}
|
||||
if (field.ks_unit){
|
||||
if (field.ks_multiplier_active){
|
||||
var ks_record_count = kpi_data[0]['record_data'] * field.ks_multiplier
|
||||
}else{
|
||||
var ks_record_count = kpi_data[0]['record_data']
|
||||
}
|
||||
var ks_selection = field.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = field.ks_currency_id;
|
||||
var ks_data = globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits);
|
||||
ks_data = globalfunction.ks_monetary(ks_data, ks_currency_id);
|
||||
item_info['count_1'] = ks_data;
|
||||
} else if (ks_selection === 'custom') {
|
||||
var ks_field = field.ks_chart_unit;
|
||||
item_info['count_1']= ks_field+" "+globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits);
|
||||
}else {
|
||||
item_info['count_1']= globalfunction._onKsGlobalFormatter(ks_record_count, field.ks_data_format, field.ks_precision_digits);
|
||||
}
|
||||
}
|
||||
this.kpi_data = kpi_data
|
||||
this.field = field
|
||||
this.state.item_info_kpi1 = this.state.item_info_kpi3 = item_info
|
||||
if (kpi_data[1]) {
|
||||
switch (this.field.ks_data_comparison) {
|
||||
case "None":
|
||||
if (field.ks_multiplier_active){
|
||||
var count_tooltip = String(count_1 * field.ks_multiplier) + "/" + String(count_2 * field.ks_multiplier);
|
||||
var count = String(globalfunction.ksNumFormatter(count_1 * field.ks_multiplier, 1)) + "/" + String(globalfunction.ksNumFormatter(count_2 * field.ks_multiplier, 1));
|
||||
var data1 = globalfunction._onKsGlobalFormatter(count_1 * field.ks_multiplier, field.ks_data_format, field.ks_precision_digits);
|
||||
var data2 = globalfunction._onKsGlobalFormatter(count_2 * field.ks_multiplier, field.ks_data_format, field.ks_precision_digits);
|
||||
if (field.ks_unit){
|
||||
var ks_selection = field.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = field.ks_currency_id;
|
||||
data1 = globalfunction.ks_monetary(data1, ks_currency_id);
|
||||
data2 = globalfunction.ks_monetary(data2, ks_currency_id)
|
||||
item_info['count'] = data1+"/"+data2;
|
||||
} else if (ks_selection === 'custom') {
|
||||
var ks_field = field.ks_chart_unit;
|
||||
data1= ks_field+" "+data1
|
||||
data2= ks_field+" "+data2
|
||||
item_info['count']= data1+"/"+data2
|
||||
}
|
||||
}else {
|
||||
item_info['count']=String(globalfunction._onKsGlobalFormatter(count_1*field.ks_multiplier, field.ks_data_format, field.ks_precision_digits)) + "/" + String(globalfunction._onKsGlobalFormatter(count_2*field.ks_multiplier, field.ks_data_format, field.ks_precision_digits));
|
||||
}
|
||||
}else{
|
||||
var count_tooltip = String(count_1) + "/" + String(count_2);
|
||||
var count = String(globalfunction.ksNumFormatter(count_1, 1)) + "/" + String(globalfunction.ksNumFormatter(count_2, 1));
|
||||
var data1 = globalfunction._onKsGlobalFormatter(count_1 , field.ks_data_format, field.ks_precision_digits);
|
||||
var data2 = globalfunction._onKsGlobalFormatter(count_2 , field.ks_data_format, field.ks_precision_digits);
|
||||
if (field.ks_unit){
|
||||
var ks_selection = field.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = field.ks_currency_id;
|
||||
data1 = globalfunction.ks_monetary(data1, ks_currency_id);
|
||||
data2 = globalfunction.ks_monetary(data2, ks_currency_id)
|
||||
item_info['count'] = data1+"/"+data2;
|
||||
} else{
|
||||
var ks_field = field.ks_chart_unit;
|
||||
data1= ks_field+" "+data1
|
||||
data2= ks_field+" "+data2
|
||||
item_info['count']= data1+"/"+data2
|
||||
}
|
||||
}else {
|
||||
item_info['count']=String(globalfunction._onKsGlobalFormatter(count_1, field.ks_data_format, field.ks_precision_digits)) + "/" + String(globalfunction._onKsGlobalFormatter(count_2, field.ks_data_format, field.ks_precision_digits));
|
||||
}
|
||||
}
|
||||
item_info['count_tooltip'] = count_tooltip;
|
||||
item_info['target_enable'] = false;
|
||||
this.state.item_info_kpi2 = item_info
|
||||
break;
|
||||
case "Sum":
|
||||
this.state.item_info_kpi2 = this.ksSum(count_1, count_2, item_info, field, target_1, kpi_data);
|
||||
break;
|
||||
case "Percentage":
|
||||
this.state.item_info_kpi2 = this.ksPercentage(count_1, count_2, field, item_info, target_1, kpi_data);
|
||||
break;
|
||||
case "Ratio":
|
||||
var gcd = self.ks_get_gcd(Math.round(count_1), Math.round(count_2));
|
||||
if (this.item.ks_data_format == 'exact'){
|
||||
if (count_1 && count_2) {
|
||||
item_info['count_tooltip'] = count_1 / gcd + ":" + count_2 / gcd;
|
||||
item_info['count'] = formatFloat(count_1 / gcd, Float64Array,{digits: [0, field.ks_precision_digits]}) + ":" + formatFloat(count_2 / gcd, Float64Array, {digits: [0, field.ks_precision_digits]});
|
||||
} else {
|
||||
item_info['count_tooltip'] = count_1 + ":" + count_2;
|
||||
item_info['count'] = count_1 + ":" + count_2
|
||||
}
|
||||
}else{
|
||||
if (count_1 && count_2) {
|
||||
item_info['count_tooltip'] = count_1 / gcd + ":" + count_2 / gcd;
|
||||
item_info['count'] = globalfunction.ksNumFormatter(count_1 / gcd, 1) + ":" + globalfunction.ksNumFormatter(count_2 / gcd, 1);
|
||||
}else {
|
||||
item_info['count_tooltip'] = (count_1) + ":" + count_2;
|
||||
item_info['count'] = globalfunction.ksNumFormatter(count_1, 1) + ":" + globalfunction.ksNumFormatter(count_2, 1);
|
||||
}
|
||||
}
|
||||
item_info['target_enable'] = false;
|
||||
this.state.item_info_kpi2 = item_info
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_ks_get_rgba_format(val){
|
||||
var rgba = val.split(',')[0].match(/[A-Za-z0-9]{2}/g);
|
||||
rgba = rgba.map(function(v) {
|
||||
return parseInt(v, 16)
|
||||
}).join(",");
|
||||
return "rgba(" + rgba + "," + val.split(',')[1] + ")";
|
||||
}
|
||||
|
||||
get previewclass(){
|
||||
var ks_valid_date_selection = ['l_day', 't_week', 't_month', 't_quarter', 't_year'];
|
||||
if (this.field.ks_previous_period && String(this.state.item_info_kpi1.previous_period_data) && ks_valid_date_selection.indexOf(this.ks_date_filter_selection) >= 0 &&
|
||||
(this.field.ks_goal_enable && this.field.ks_target_view === "Progress Bar")){
|
||||
return 'ks_previous_period'
|
||||
}else{ return ''}
|
||||
}
|
||||
|
||||
ks_get_gcd(a, b) {
|
||||
return (b == 0) ? a : this.ks_get_gcd(b, a % b);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Ksdashboardkpiview.props = {
|
||||
item: { type: Object, optional:true},
|
||||
dashboard_data: { type: Object, optional:true},
|
||||
ksdatefilter :{type :String, optional:true},
|
||||
pre_defined_filter:{type: Object, optional:true},
|
||||
custom_filter :{type:Object, optional:true},
|
||||
itemsToUpdateList : { type: Array, optional: true },
|
||||
ks_speak:{type:Function , optional:true},
|
||||
hideButtons: { type: Number, optional: true },
|
||||
on_dialog: { type: Boolean, optional: true },
|
||||
generate_dialog: { type: Boolean, optional: true },
|
||||
onItemClick: { type: Function },
|
||||
};
|
||||
|
||||
Ksdashboardkpiview.template = "Ksdashboardkpiview";
|
||||
Ksdashboardkpiview.components = { KsItemButton };
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="Ksdashboardkpiview">
|
||||
<t t-if="props.item.ks_model_id_2 == false and (props.item.ks_target_view == 'Number' || !props.item.ks_goal_enable)">
|
||||
<t t-call="ks_kpi_template"/>
|
||||
</t>
|
||||
<t t-elif="props.item.ks_model_id_2 == false and (props.item.ks_target_view == 'Progress Bar' and props.item.ks_goal_enable)">
|
||||
<t t-call="ks_kpi_template_3"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_template_2"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_kpi_template">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel '+ previewclass + reviewclass" t-att-id="state.item_info_kpi1.item.id" t-ref="ks_kpi">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_kpi_temp_1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_1"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel '+ previewclass + reviewclass" t-att-id="state.item_info_kpi1.item.id" t-ref="ks_kpi">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_kpi_temp_1"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_1"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_kpi_template_3">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel template-3-checking ' + reviewclass" t-att-id="state.item_info_kpi3.item.id" t-ref="ks_kpi">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_kpi_temp_3"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_3"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel template-3-checking ' + reviewclass" t-att-id="state.item_info_kpi3.item.id" t-ref="ks_kpi">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_kpi_temp_3"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_3"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
|
||||
|
||||
<t t-name="ks_kpi_template_2">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel'+ reviewclass" t-att-id="state.item_info_kpi2.item.id" t-ref="ks_kpi">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_kpi_temp_2"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_2"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-class="'ks_item_click grid-stack-item ks_tile_carousel '+ reviewclass" t-att-id="state.item_info_kpi2.item.id" t-ref="ks_kpi">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_kpi_temp_2"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_kpi_temp_2"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_kpi_temp_1">
|
||||
<div t-att-class="ks_ai_analysis? classname + ' ks_ai_chart_body ks_ai_dashboard_item ks_explain_ai_view': classname"
|
||||
t-att-title="state.item_info_kpi1.item.ks_info" t-att-id="state.item_info_kpi1.item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<div class="ks_dashboard_icon_l5 ks_dashboard_icon_color_picker dashboard-item-icon img-bg">
|
||||
<t t-if="state.item_info_kpi1.icon_select=='Custom'">
|
||||
<t t-if="state.item_info_kpi1.ks_icon_url">
|
||||
<img t-att-src="state.item_info_kpi1.ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="state.item_info_kpi1.icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ state.item_info_kpi1.icon_color + ';'"
|
||||
t-att-class="'fa fa-' + state.item_info_kpi1.default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="ks_dashboard_item_main_body_l5 ks_kpi_main_body">
|
||||
<div class="ks_dashboard_kpi_count_preview" t-att-title="state.item_info_kpi1.count_1_tooltip">
|
||||
<t t-esc="state.item_info_kpi1.count_1"/>
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="state.item_info_kpi1.ks_previous_period">
|
||||
<div class="var-prev" style="text-align: center;">
|
||||
<div style="color: rgba(0, 0, 0, 0.61);">
|
||||
<span>vs Prev</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="pre_deviation " style="font-size:medium;">
|
||||
<t t-esc="state.item_info_kpi1.pre_deviation"/>
|
||||
<i t-att-class="'fa fa-arrow-'+ pre_arrow"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_kpi_name_preview dashboard-item-name mb-3" t-att-title="state.item_info_kpi1.name">
|
||||
<t t-esc="state.item_info_kpi1.name"/>
|
||||
</div>
|
||||
|
||||
<div class="d-flex ks_target_previous dashboard-item-compare">
|
||||
<t t-if="state.item_info_kpi1.ks_enable_goal">
|
||||
<div class="w-100 d-flex justify-content-between align-items-center px-2">
|
||||
<div style="color: rgba(0, 0, 0, 0.61); text-align:center;">
|
||||
<span>vs Target</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="target_deviation" style="font-size : medium;">
|
||||
<t t-esc="state.item_info_kpi1.target_deviation"/>
|
||||
<t t-if="state.item_info_kpi1.target_arrow">
|
||||
<i t-att-class="'fa fa-arrow-'+ state.item_info_kpi1.target_arrow"/>
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<!-- for ai dashboard-->
|
||||
<img src="/ks_dashboard_ninja/static/images/selected.svg" class="ks_img_display d-none" width="30"/>
|
||||
<div class="select-btn d-none">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10.0001 18.3332C14.5834 18.3332 18.3334 14.5832 18.3334 9.99984C18.3334 5.4165 14.5834 1.6665 10.0001 1.6665C5.41675 1.6665 1.66675 5.4165 1.66675 9.99984C1.66675 14.5832 5.41675 18.3332 10.0001 18.3332Z"
|
||||
stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M6.45825 9.99993L8.81659 12.3583L13.5416 7.6416" stroke="" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<!---->
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="this.ks_kpi"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="ks_kpi_temp_2">
|
||||
<div t-att-id="state.item_info_kpi2.id"
|
||||
t-att-class="ks_ai_analysis? classname + ' ks_ai_chart_body ks_ai_dashboard_item ks_explain_ai_view': classname"
|
||||
t-att-title="state.item_info_kpi2.item.ks_info" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<div class="ks_dashboard_icon_l5 ks_dashboard_icon_color_picker dashboard-item-icon img-bg">
|
||||
<t t-if="state.item_info_kpi2.icon_select=='Custom'">
|
||||
<t t-if="state.item_info_kpi2.ks_icon_url">
|
||||
<img t-att-src="state.item_info_kpi2.ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="state.item_info_kpi2.icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ state.item_info_kpi2.icon_color + ';'"
|
||||
t-att-class="'fa fa-' + state.item_info_kpi2.default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_main_body_l5 ks_kpi_main_body">
|
||||
<div class="ks_dashboard_kpi_count_preview dashboard-item-data" t-att-title="state.item_info_kpi2.count_tooltip">
|
||||
<span>
|
||||
<t t-esc="state.item_info_kpi2.count"/>
|
||||
<t t-if="state.item_info_kpi2.target_view =='Progress Bar' and state.item_info_kpi2.target_enable">/
|
||||
<t t-esc="state.item_info_kpi2.target"/>
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_kpi_name_preview dashboard-item-name mb-3">
|
||||
<t t-esc="state.item_info_kpi2.name"/>
|
||||
</div>
|
||||
|
||||
<t t-if="state.item_info_kpi2.ks_enable_goal and state.item_info_kpi2.target_enable">
|
||||
<div>
|
||||
<t t-if="state.item_info_kpi2.target_deviation and state.item_info_kpi2.target_view =='Number'">
|
||||
<div class="dashboard-item-compare">
|
||||
<div>
|
||||
<span class="ks_kpi_target_grey">vs Target</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="target_deviation">
|
||||
<t t-esc="state.item_info_kpi2.target_deviation"/>
|
||||
<t t-if="state.item_info_kpi2.pre_arrow">
|
||||
<i t-att-class="'fa fa-arrow-'+ state.item_info_kpi2.pre_arrow"/>
|
||||
</t>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="state.item_info_kpi2.target_progress_deviation and state.item_info_kpi2.target_view =='Progress Bar'">
|
||||
<div class="text-center ks_progress dashboard-item-compare">
|
||||
<div class="w-100 text-start">
|
||||
<progress id="ks_progressbar" value="0" max="100"/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<t t-esc="state.item_info_kpi2.target_progress_deviation"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="this.ks_kpi" />
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="ks_kpi_temp_3">
|
||||
<div t-att-id="state.item_info_kpi3.id"
|
||||
t-att-class="ks_ai_analysis? classname + ' ks_ai_chart_body ks_ai_dashboard_item ks_explain_ai_view': classname"
|
||||
t-att-title="state.item_info_kpi3.item.ks_info" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<div class="ks_dashboard_icon_l5 ks_dashboard_icon_color_picker dashboard-item-icon img-bg">
|
||||
<t t-if="state.item_info_kpi3.icon_select=='Custom'">
|
||||
<t t-if="state.item_info_kpi3.ks_icon_url">
|
||||
<img t-att-src="state.item_info_kpi3.ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="state.item_info_kpi3.icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ state.item_info_kpi3.icon_color + ';'"
|
||||
t-att-class="'fa fa-' + state.item_info_kpi3.default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="flex-container">
|
||||
<div class="ks_dashboard_item_main_body_l5 ks_kpi_main_body dashboard-item-data">
|
||||
<div class="ks_dashboard_kpi_count_preview" t-att-title="count_1_tooltip">
|
||||
<span class="ks_count">
|
||||
<t t-esc="state.item_info_kpi3.count_1"/>
|
||||
</span>
|
||||
/
|
||||
<span>
|
||||
<t t-esc="state.item_info_kpi3.target"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<t t-if="item.ks_previous_period && previous_period_data">
|
||||
<div class="text-center var-prev">
|
||||
<div>
|
||||
<span>vs Prev</span>
|
||||
</div>
|
||||
<div class="d-flex flex-column">
|
||||
<t t-esc="state.item_info_kpi3.previous_period_data"/>
|
||||
<span class="pre_deviation">
|
||||
<t t-esc="state.item_info_kpi3.pre_deviation"/>
|
||||
<i t-att-class="'fa fa-arrow-'+ state.item_info_kpi3.pre_arrow"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_kpi_name_preview dashboard-item-name mb-3">
|
||||
<t t-esc="state.item_info_kpi3.name"/>
|
||||
</div>
|
||||
<div class="text-center ks_progress dashboard-item-compare">
|
||||
<div class="w-100 text-start">
|
||||
<progress id="ks_progressbar" value="0" max="100"/>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<t t-esc="state.item_info_kpi3.target_progress_deviation"/>%
|
||||
</div>
|
||||
</div>
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="this.ks_kpi"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,212 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="ks_dashboard_ninja.Ksdashboardlistview">
|
||||
|
||||
<div class="grid-stack-item ks_tile_carousel ks_dashboarditem_id" t-att-id="item_id" t-ref="ks_list_view">
|
||||
<div class="grid-stack-item-content ks_list_view_container ks_dashboarditem_chart_container ks_dashboard_item_hover card border-0"
|
||||
t-att-title="ks_info" t-att-id="item_id">
|
||||
|
||||
<t t-if="!env.isExplainDashboardWithAi">
|
||||
<div class="p-3 py-3 d-flex flex-row align-items-center justify-content-between">
|
||||
<div class="d-flex align-items-center w-50">
|
||||
<h6 class="m-0 font-weight-bold h3 mr-3 ks_list_view_heading text-capitalize text-start " t-att-title="ks_chart_title">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</h6>
|
||||
<t t-if="ks_breadcrumb.length >= 1">
|
||||
<nav class="ks_breadcrumb">
|
||||
<ul>
|
||||
<li class="d-none" t-att-id="'item'+'_'+'-1'">
|
||||
<span t-att-data-sequence = '-1' t-att-data-item-id="item_id" t-on-click="ksOnDrillUp">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</span>
|
||||
</li>
|
||||
<t t-foreach="ks_breadcrumb" t-as="chart_breadcrumb" t-key="chart_breadcrumb_index">
|
||||
<li class="d-none" t-att-id="chart_breadcrumb['name'] + '_' + chart_breadcrumb_index">
|
||||
<span t-att-data-sequence="chart_breadcrumb_index" t-att-data-item-id="item_id" t-on-click="ksOnDrillUp">
|
||||
<t t-esc="chart_breadcrumb['name']"/>
|
||||
</span>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</nav>
|
||||
</t>
|
||||
</div>
|
||||
<!-- for ai dashboard-->
|
||||
<img src="/ks_dashboard_ninja/static/images/selected.svg" class="ks_img_display d-none" width="30"/>
|
||||
<div class="select-btn d-none">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M10.0001 18.3332C14.5834 18.3332 18.3334 14.5832 18.3334 9.99984C18.3334 5.4165 14.5834 1.6665 10.0001 1.6665C5.41675 1.6665 1.66675 5.4165 1.66675 9.99984C1.66675 14.5832 5.41675 18.3332 10.0001 18.3332Z"
|
||||
stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M6.45825 9.99993L8.81659 12.3583L13.5416 7.6416" stroke="" stroke-width="1.5"
|
||||
stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<!-- -->
|
||||
<KsItemButton item_data="this.item" itemRootRef="ks_list_view"/>
|
||||
<t t-if="ksIsDashboardManager and props.hideButtons">
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec">
|
||||
<h6 class="m-0 font-weight-bold h3 mr-3 ks_list_view_heading text-capitalize text-start text-black" t-att-title="ks_chart_title">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</h6>
|
||||
<div name="ks_list_div" class="card-body table-responsive ks_list_card_body ks_list_item_table ks_list_explain">
|
||||
<t t-call="ks_dashboard_ninja.ks_list_view_table"/>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<div class="ks_pager_name">
|
||||
<t t-if="ks_pager" t-call="ks_pager_template"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<!-- <div class="ks_ai_explanation">-->
|
||||
<p><t t-esc="ks_ai_analysis_1"/></p>
|
||||
<p><t t-esc="ks_ai_analysis_2"/></p>
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div name="ks_list_div" class="card-body table-responsive ks_list_item_table">
|
||||
<t t-call="ks_dashboard_ninja.ks_list_view_table"/>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<div class="ks_pager_name">
|
||||
<t t-if="ks_pager" t-call="ks_pager_template"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_list_view_tmpl">
|
||||
<t t-foreach="state.list_view_data['data_rows']" t-as="table_row" t-key="table_row_index">
|
||||
<tr class="ks_tr" t-att-data-record-id="table_row['id']" t-att-data-domain="table_row['domain']"
|
||||
t-att-data-item-Id="item_id"
|
||||
t-att-data-sequence="table_row['sequence']" t-att-data-last_seq="table_row['last_seq']">
|
||||
<t t-set="ks_rec_count" t-value="0"/>
|
||||
<t t-foreach="table_row['data']" t-as="row_data" t-key="row_data_index">
|
||||
<t t-if="table_row['ks_column_type']?.[ks_rec_count]=='html'">
|
||||
<td class="ks_list_canvas_click">
|
||||
<t t-out="markup(row_data)"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<!-- TODO: No need of multiple if else , can be deduced to logic without if else , nedd to change the flow for this -->
|
||||
<t t-elif="['many2one', 'selection'].includes(state.list_view_data['fields_type']?.[ks_rec_count])">
|
||||
<td class="ks_list_canvas_click cursor-pointer"
|
||||
t-on-click="(ev) => this.onChartCanvasClick(ev, row_data_index, row_data, state.list_view_data['fields_type']?.[ks_rec_count] )">
|
||||
<t t-out="row_data ? row_data[1] : ''"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<t t-elif="table_row['ks_column_type']?.[ks_rec_count] == 'boolean'">
|
||||
<td class="ks_list_canvas_click" t-on-click="onChartCanvasClick">
|
||||
<t t-out="row_data"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td class="ks_list_canvas_click" t-on-click="onChartCanvasClick">
|
||||
<t t-esc="row_data !== false ? row_data : ''"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
</t>
|
||||
<td class="ks_info">
|
||||
<t t-if="ks_show_records">
|
||||
<div id="ks_item_info" t-att-data-model="state.list_view_data['model']"
|
||||
t-att-data-list-type="state.list_view_data['list_view_type']"
|
||||
t-att-data-groupby="state.list_view_data['groupby']"
|
||||
t-att-data-record-id="table_row['id']" t-att-data-item-id="item_id"
|
||||
t-att-data-list-view-type="tmpl_list_type"
|
||||
t-att-data-domain="table_row['domain']"
|
||||
t-on-click="ksOnListItemInfoClick">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="#241C1D" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_list_view_table">
|
||||
<t t-if="state.list_view_data && state.list_view_data.label && state.list_view_data.label.length">
|
||||
<table id="ksListViewTable" class="table table-hover ks_list_view_layout_1"
|
||||
t-att-data-model="state.list_view_data['model']">
|
||||
<thead>
|
||||
<t t-call="ks_list_view_header"/>
|
||||
</thead>
|
||||
<tbody class="ks_table_body">
|
||||
<t t-call="ks_dashboard_ninja.ks_list_view_tmpl"/>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
No Data Present
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="ks_list_view_header">
|
||||
<tr>
|
||||
<t t-foreach="state.list_view_data['label']" t-as="table_header" t-key="table_header_index">
|
||||
<th>
|
||||
<t t-esc="table_header"/>
|
||||
</th>
|
||||
</t>
|
||||
<th/>
|
||||
</tr>
|
||||
</t>
|
||||
<div t-name="ks_pager_template" class="ks_pager">
|
||||
<span class="ks_counter">
|
||||
<span class="ks_value">
|
||||
<t t-esc="count"/>
|
||||
</span>
|
||||
</span>
|
||||
<span class="btn-group" aria-atomic="true" t-att-data-next_offset="intial_count"
|
||||
t-att-data-prev-offset="offset">
|
||||
<button type="button"
|
||||
class="fa fa-chevron-left btn ks_load_previous ks_event_offer_list"
|
||||
t-att-data-item-id="item_id" title="Previous" t-on-click="ksLoadPreviousRecords"/>
|
||||
<button type="button" class="fa fa-chevron-right btn ks_load_next"
|
||||
t-att-data-item-id="item_id" title="Next" t-on-click="ksLoadMoreRecords"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_new_list_view_tmpl">
|
||||
<t t-foreach="list_view_data['data_rows']" t-as="table_row" t-key="table_row_index">
|
||||
<tr class="ks_tr" t-att-data-record-id="table_row['id']" t-att-data-domain="table_row['domain']"
|
||||
t-att-data-item-Id="item_id"
|
||||
t-att-data-sequence="table_row['sequence']" t-att-data-last_seq="table_row['last_seq']">
|
||||
<t t-set="ks_rec_count" t-value="0"/>
|
||||
<t t-foreach="table_row['data']" t-as="row_data" t-key="row_data_index">
|
||||
<t t-if="table_row['ks_column_type'][ks_rec_count]=='html'">
|
||||
<td class="ks_list_canvas_click">
|
||||
<t t-out="markup(row_data)"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<!-- TODO: No need of multiple if else , can be deduced to logic without if else , nedd to change the flow for this -->
|
||||
<t t-elif="['many2one', 'selection'].includes(state.list_view_data['fields_type']?.[ks_rec_count])">
|
||||
<td class="ks_list_canvas_click cursor-pointer"
|
||||
t-on-click="(ev) => self.onChartCanvasClick(ev, row_data_index, row_data, state.list_view_data['fields_type'][ks_rec_count] )">
|
||||
<!-- <t t-out="row_data"/>-->
|
||||
<t t-raw="row_data ? row_data[1] : ''"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<t t-elif="table_row['ks_column_type'][ks_rec_count] == 'boolean'">
|
||||
<td class="ks_list_canvas_click" t-on-click="onChartCanvasClick">
|
||||
<t t-out="row_data"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<td class="ks_list_canvas_click" t-on-click="(ev)=>self.onChartCanvasClick(ev)">
|
||||
<t t-esc="row_data !== false ? row_data : ''"/>
|
||||
</td>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
</t>
|
||||
<td class="ks_info">
|
||||
<t t-if="ks_show_records ">
|
||||
<div id="ks_item_info" t-att-data-model="list_view_data['model']"
|
||||
t-att-data-list-type="list_view_data['list_view_type']"
|
||||
t-att-data-groupby="list_view_data['groupby']"
|
||||
t-att-data-record-id="table_row['id']" t-att-data-item-id="item_id"
|
||||
t-att-data-list-view-type="tmpl_list_type"
|
||||
t-att-data-domain="table_row['domain']"
|
||||
t-on-click="ksOnListItemInfoClick">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="#241C1D" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="#241C1D" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.ks_new_list_view_table">
|
||||
<t t-if="list_view_data">
|
||||
<table id="ksListViewTable" class="table table-hover ks_list_view_layout_1"
|
||||
t-att-data-model="list_view_data['model']">
|
||||
<thead>
|
||||
<t t-call="ks_new_list_view_header"/>
|
||||
</thead>
|
||||
<tbody class="ks_table_body">
|
||||
<t t-call="ks_dashboard_ninja.ks_new_list_view_tmpl"/>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
No Data Present
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
<t t-name="ks_new_list_view_header">
|
||||
<tr>
|
||||
<t t-foreach="list_view_data['label']" t-as="table_header" t-key="table_header_index">
|
||||
<th>
|
||||
<t t-esc="table_header"/>
|
||||
</th>
|
||||
</t>
|
||||
<th/>
|
||||
</tr>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,556 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Component, onRendered, onWillStart, useState, onPatched, useChildSubEnv, useSubEnv,
|
||||
onMounted, onWillRender, useRef, useEffect, onWillUnmount } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { useService, useBus } from "@web/core/utils/hooks";
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { session } from "@web/session";
|
||||
import { download } from "@web/core/network/download";
|
||||
import { useChildRef } from "@web/core/utils/hooks";
|
||||
import { BlockUI } from "@web/core/ui/block_ui";
|
||||
import { WebClient } from "@web/webclient/webclient";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { loadBundle } from '@web/core/assets';
|
||||
import { FormViewDialog} from '@web/views/view_dialogs/form_view_dialog';
|
||||
import { renderToElement } from "@web/core/utils/render";
|
||||
import { convert_data_to_utc, eraseAllCookies } from '@ks_dashboard_ninja/js/ks_global_functions'
|
||||
import { KschatwithAI } from '@ks_dashboard_ninja/components/chatwithAI/ks_chat';
|
||||
import { DateTimePicker } from "@web/core/datetime/datetime_picker";
|
||||
import { DateTimeInput } from "@web/core/datetime/datetime_input";
|
||||
const { DateTime } = luxon;
|
||||
import {formatDate,formatDateTime} from "@web/core/l10n/dates";
|
||||
import {parseDateTime,parseDate,} from "@web/core/l10n/dates";
|
||||
import { KsHeader } from '@ks_dashboard_ninja/components/Header/Header'
|
||||
import { KsItems } from "@ks_dashboard_ninja/components/ks_items/ks_items";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
import { debounce } from "@bus/workers/websocket_worker_utils";
|
||||
|
||||
|
||||
export class KsDashboardNinja extends Component {
|
||||
|
||||
setup() {
|
||||
let self = this;
|
||||
this.actionService = useService("action");
|
||||
this.uiService = useService("ui");
|
||||
this.dialogService = useService("dialog");
|
||||
this.notification = useService("notification");
|
||||
this._rpc = rpc
|
||||
this.dialogService = useService("dialog");
|
||||
this.user = user
|
||||
this.headerRootRef = useChildRef();
|
||||
this.gridStackRootRef = useChildRef();
|
||||
// debugger;
|
||||
this.header = this.headerRootRef
|
||||
this.footer = useRef("ks_dashboard_footer");
|
||||
this.main_body = useRef("ks_main_body");
|
||||
this.reload_menu_option = {
|
||||
reload:this.props.action.context.ks_reload_menu,
|
||||
menu_id: this.props.action.context.ks_menu_id
|
||||
};
|
||||
this.ks_mode = 'active';
|
||||
this.action_manager = parent;
|
||||
this.name = "ks_dashboard";
|
||||
this.ksIsDashboardManager = false;
|
||||
this.dashboard_domain_data = {}
|
||||
this.recent_searches = useState({ value : []})
|
||||
this.file_type_magic_word = {
|
||||
'/': 'jpg',
|
||||
'R': 'gif',
|
||||
'i': 'png',
|
||||
'P': 'svg+xml',
|
||||
};
|
||||
this.ksAllowItemClick = true;
|
||||
|
||||
//Dn Filters Iitialization
|
||||
|
||||
this.date_format = localization.dateFormat
|
||||
this.datetime_format = localization.dateTimeFormat
|
||||
this.ks_date_filter_data;
|
||||
|
||||
|
||||
// To make sure date filter show date in specific order.
|
||||
this.ks_date_filter_selection_order = ['l_day', 't_week', 't_month', 't_quarter','t_year',
|
||||
'td_week','td_month','td_quarter', 'td_year','n_day','n_week', 'n_month', 'n_quarter', 'n_year',
|
||||
'ls_day','ls_week', 'ls_month', 'ls_quarter', 'ls_year', 'l_week', 'l_month', 'l_quarter', 'l_year',
|
||||
'ls_past_until_now', 'ls_pastwithout_now','n_future_starting_now', 'n_futurestarting_tomorrow',
|
||||
'l_custom'
|
||||
];
|
||||
|
||||
this.ks_dashboard_id = this.props.action.params.ks_dashboard_id;
|
||||
this.isReloadOnFirstCreate = this.props.action?.params?.isReloadOnFirstCreate ? true : false
|
||||
this.explain_ai_whole = true;
|
||||
this.explain_ai_whole = this.props.action.params.explain_ai_whole === undefined ? true : false;
|
||||
|
||||
var ks_fav_filter_remove = $('.ks_dn_fav_filters').find('.ks_fav_filters_checked');
|
||||
if (ks_fav_filter_remove.length){
|
||||
var ks_fav_filter = ks_fav_filter_remove.attr('fav-name');
|
||||
ks_fav_filter_remove.removeClass('ks_fav_filters_checked');
|
||||
this.ks_remove_favourite_filter(ks_fav_filter);
|
||||
}
|
||||
|
||||
|
||||
this.gridstackConfig = {};
|
||||
this.grid = true;
|
||||
this.state = useState({
|
||||
ks_dashboard_name: '',
|
||||
ks_multi_layout: false,
|
||||
ks_dash_name: '',
|
||||
ks_dashboard_manager :false,
|
||||
date_selection_data: {},
|
||||
date_selection_order :[],
|
||||
ks_show_create_layout_option : true,
|
||||
ks_show_layout :false,
|
||||
ks_selected_board_id:false,
|
||||
ks_child_boards:false,
|
||||
ks_dashboard_data:{},
|
||||
ks_dn_pre_defined_filters:[],
|
||||
ks_dashboard_items:[],
|
||||
update:false,
|
||||
ksDateFilterSelection :'none',
|
||||
pre_defined_filter :{},
|
||||
ksDateFilterStartDate: DateTime.now(),
|
||||
ksDateFilterEndDate:DateTime.now(),
|
||||
stateToggle: false,
|
||||
dialog_header: true,
|
||||
should_loading: true,
|
||||
itemsToUpdateList: []
|
||||
|
||||
})
|
||||
this.ksChartColorOptions = ['default', 'cool', 'warm', 'neon'];
|
||||
this.ksDateFilterSelection = false;
|
||||
this.ksDateFilterStartDate = false;
|
||||
this.ksDateFilterEndDate = false;
|
||||
this.ksUpdateDashboard = {};
|
||||
$("head").append('<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">');
|
||||
if(this.props.action.context.ks_reload_menu){
|
||||
this.trigger_up('reload_menu_data', { keep_open: true, scroll_to_bottom: true});
|
||||
}
|
||||
var context = {
|
||||
ksDateFilterSelection: this.ksDateFilterSelection,
|
||||
ksDateFilterStartDate: this.ksDateFilterStartDate,
|
||||
ksDateFilterEndDate: this.ksDateFilterEndDate,
|
||||
}
|
||||
this.dn_state = {}
|
||||
this.dn_state['user_context']=context
|
||||
this.isFavFilter = false;
|
||||
this.activeFavFilterName = "FavouriteFilter"
|
||||
this.ks_speeches = [];
|
||||
onWillStart(this.willStart);
|
||||
onWillRender(this.dashboard_mount);
|
||||
//
|
||||
this.modelsListForAutoUpdate = []
|
||||
this.env.services.bus_service.addChannel('ks_notification')
|
||||
|
||||
useEffect(() => {
|
||||
this.ks_fetch_items_data();
|
||||
}, ()=>[]
|
||||
)
|
||||
|
||||
useEffect( () => {
|
||||
if(this.ks_dashboard_data.ks_set_interval){
|
||||
this._debounced_items_for_update = debounce(this.update_dashboard_items.bind(this), parseInt(this.ks_dashboard_data.ks_set_interval))
|
||||
this.env.services.bus_service.subscribe('Update: Dashboard Items', (detail) => {
|
||||
this.modelsListForAutoUpdate.push(detail.model)
|
||||
this._debounced_items_for_update();});
|
||||
return this.env.services.bus_service.removeEventListener('Update: Dashboard Items', (detail) => {
|
||||
this.modelsListForAutoUpdate.push(detail.model)
|
||||
this._debounced_items_for_update();})
|
||||
}
|
||||
}, ()=>[])
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
$(".modal-footer").find("button").addClass('d-none')
|
||||
let filterFacetCountTag = this.header.el.querySelector('.filters-amount')
|
||||
if (document.body.classList.contains("ks_body_class")){
|
||||
document.querySelector(".ks-zoom-view")?.classList.add("d-none")
|
||||
}
|
||||
});
|
||||
|
||||
onRendered(()=>{
|
||||
|
||||
|
||||
if(this.isReloadOnFirstCreate){
|
||||
this.isReloadOnFirstCreate = false;
|
||||
if(this.props.action.params && this.props.action.params.isReloadOnFirstCreate)
|
||||
this.props.action.params.isReloadOnFirstCreate = false
|
||||
this.env.services.menu.reload();
|
||||
this.notification.add(_t('New Dashboard is successfully created'),{
|
||||
title:_t("New Dashboard"),
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
})
|
||||
// TODO: make items independent , graph component,etc should not be dependent on some other components,
|
||||
// TODO: presently we are using many functions in env , can be removed to make component fully independent
|
||||
|
||||
|
||||
useChildSubEnv({
|
||||
getContext : this.getContext.bind(this),
|
||||
ksGetParamsForItemFetch: (item_id) => this.ksGetParamsForItemFetch(item_id),
|
||||
ks_update_date_filter_state: (selected_filter_id, start_date, end_date) => this.ks_update_date_filter_state(selected_filter_id, start_date, end_date),
|
||||
update_dashboard_filters: (domainsToUpdate) => this.update_dashboard_filters(domainsToUpdate),
|
||||
replace_dashboard_filters: (domain_data) => this.replace_dashboard_filters(domain_data),
|
||||
onKsEditLayoutClick: () => this.onKsEditLayoutClick(),
|
||||
isMobile: this.isMobile,
|
||||
update_dashboard_mode: this.update_dashboard_mode.bind(this),
|
||||
get mode(){ return self.ks_mode},
|
||||
getDashboardDataAsObj: this.getDashboardDataAsObj.bind(this),
|
||||
gridStackRootRef: this.gridStackRootRef,
|
||||
isExplainDashboardWithAi: this.isExplainDashboardWithAi,
|
||||
})
|
||||
|
||||
onWillUnmount(()=>{
|
||||
document.querySelector(".ks-zoom-view")?.classList.remove("d-none")
|
||||
})
|
||||
}
|
||||
|
||||
get isMobile(){
|
||||
return isMobileOS();
|
||||
}
|
||||
|
||||
|
||||
get isExplainDashboardWithAi(){
|
||||
return this.props.action.params.explain_ai_whole ? true : false;
|
||||
}
|
||||
|
||||
|
||||
willStart(){
|
||||
let self = this;
|
||||
let def;
|
||||
if (this.reload_menu_option.reload && this.reload_menu_option.menu_id) {
|
||||
def = this.getParent().actionService.ksDnReloadMenu(this.reload_menu_option.menu_id);
|
||||
}
|
||||
this.setFilterObjFromCookies();
|
||||
return $.when(def, loadBundle("ks_dashboard_ninja.ks_dashboard_lib")).then(function() {
|
||||
return self.ks_fetch_data().then(function(){
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
update_dashboard_items(){
|
||||
let itemsToUpdateList = []
|
||||
this.modelsListForAutoUpdate?.forEach( (model_name) => {
|
||||
itemsToUpdateList.push( ...this.ks_dashboard_data.ks_model_item_relation[model_name] || [])
|
||||
})
|
||||
this.state.itemsToUpdateList = JSON.parse(JSON.stringify(itemsToUpdateList))
|
||||
this.modelsListForAutoUpdate = []
|
||||
}
|
||||
|
||||
getDashboardDataAsObj(params){ // params - list of parameters to be get in child components , empty list return whole data
|
||||
let data = {}
|
||||
params.forEach( (param) => {
|
||||
if(this.ks_dashboard_data[param]){
|
||||
data[param] = this.ks_dashboard_data[param]
|
||||
}
|
||||
})
|
||||
return Object.keys(data).length ? data : this.ks_dashboard_data;
|
||||
}
|
||||
|
||||
setFilterObjFromCookies(){
|
||||
let dashboard_domain_data_from_cky = getObjectFromCookie('Filter' + this.ks_dashboard_id)
|
||||
this.dashboard_domain_data = dashboard_domain_data_from_cky ?? {}
|
||||
}
|
||||
|
||||
makeCtxFromCookies(){
|
||||
let dateFilterCookieObj = getObjectFromCookie('FilterDateData' + this.ks_dashboard_id);
|
||||
let context = {}
|
||||
if (dateFilterCookieObj != null){
|
||||
context = {
|
||||
ksDateFilterSelection: dateFilterCookieObj.filter_selection ?? false,
|
||||
ksDateFilterStartDate: false, ksDateFilterEndDate: false,
|
||||
}
|
||||
if(context.ksDateFilterSelection === 'l_custom'){
|
||||
try {
|
||||
context.ksDateFilterStartDate = dateFilterCookieObj.date_range.start_date
|
||||
context.ksDateFilterEndDate = dateFilterCookieObj.date_range.end_date
|
||||
} catch (error) {
|
||||
context.ksDateFilterStartDate = false
|
||||
context.ksDateFilterEndDate = false
|
||||
eraseCookie('FilterDateData' + this.ks_dashboard_id);
|
||||
}
|
||||
}
|
||||
let ctx_to_be_added = { ...session.user_context, ...{ allowed_company_ids: this.env.services.company.activeCompanyIds }}
|
||||
return Object.assign(context, ctx_to_be_added);
|
||||
|
||||
|
||||
}
|
||||
let ctx_to_be_added = { ...session.user_context, ...{ allowed_company_ids: this.env.services.company.activeCompanyIds }}
|
||||
return Object.assign(context, ctx_to_be_added);
|
||||
}
|
||||
|
||||
ks_fetch_data(){
|
||||
let self = this;
|
||||
return rpc("/web/dataset/call_kw",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_dashboard_data',
|
||||
args: [ self.ks_dashboard_id ],
|
||||
kwargs : { context: self.makeCtxFromCookies() },
|
||||
}).then(function(result) {
|
||||
if(self.props?.action?.params?.dashboard_data){
|
||||
self.ks_dashboard_data = JSON.parse(JSON.stringify(self.props.action.params.dashboard_data))
|
||||
}
|
||||
else{
|
||||
self.ks_dashboard_data = result;
|
||||
}
|
||||
self.ks_dashboard_item_length = self.ks_dashboard_data.ks_dashboard_items_ids.length
|
||||
self.ks_dashboard_data.ks_ai_explain_dash = self.props.action.params.explainWithAi ? true : false
|
||||
self.ks_dashboard_data['ks_dashboard_id'] = self.props.action.params.ks_dashboard_id
|
||||
self.ks_dashboard_data['context'] = self.getContext()
|
||||
self.ks_dashboard_data['ks_ai_dashboard'] = false
|
||||
|
||||
self.ks_favourite_filters = JSON.parse(JSON.stringify(self.ks_dashboard_data.ks_dashboard_favourite_filter))
|
||||
});
|
||||
}
|
||||
|
||||
async ks_fetch_items_data(){
|
||||
let self = this;
|
||||
let items_promises = []
|
||||
let item_ids = self.ks_dashboard_data.ks_dashboard_items_ids
|
||||
await Promise.all(
|
||||
item_ids.map(async (item_id) => {
|
||||
const itemData = await rpc("/web/dataset/call_kw",{
|
||||
model: "ks_dashboard_ninja.board",
|
||||
method: "ks_fetch_item",
|
||||
args : [[item_id], self.ks_dashboard_id, self.ksGetParamsForItemFetch(item_id)],
|
||||
kwargs: { context: self.getContext() }
|
||||
})
|
||||
if(itemData[item_id].ks_list_view_data){
|
||||
itemData[item_id].ks_list_view_data = convert_data_to_utc(itemData[item_id].ks_list_view_data)
|
||||
}
|
||||
Object.assign(self.ks_dashboard_data.ks_item_data, itemData)
|
||||
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
this.state.should_loading = false
|
||||
|
||||
}
|
||||
|
||||
getContext() {
|
||||
let context = {
|
||||
ksDateFilterSelection: this.ks_dashboard_data?.ks_date_filter_selection ?? false,
|
||||
ksDateFilterStartDate: this.ks_dashboard_data?.ks_date_filter_selection === 'l_custom' ? this.ks_dashboard_data.ks_dashboard_start_date : false,
|
||||
ksDateFilterEndDate: this.ks_dashboard_data?.ks_date_filter_selection === 'l_custom' ? this.ks_dashboard_data.ks_dashboard_end_date : false,
|
||||
}
|
||||
var ctx_to_be_added = { ...session.user_context, ...{ allowed_company_ids: this.env.services.company.activeCompanyIds }}
|
||||
return Object.assign(context, ctx_to_be_added);
|
||||
}
|
||||
|
||||
update_dashboard_mode(mode){
|
||||
this.ks_mode = mode;
|
||||
}
|
||||
|
||||
ksGetParamsForItemFetch(item_id) {
|
||||
let self = this;
|
||||
|
||||
let model1 = self.ks_dashboard_data.ks_item_model_relation[item_id][0];
|
||||
let model2 = self.ks_dashboard_data.ks_item_model_relation[item_id][1];
|
||||
|
||||
|
||||
var ks_domain_1 = self.dashboard_domain_data[model1] && self.dashboard_domain_data[model1].domain || [];
|
||||
var ks_domain_2 = self.dashboard_domain_data[model2] && self.dashboard_domain_data[model2].domain || [];
|
||||
|
||||
return {
|
||||
ks_domain_1: ks_domain_1,
|
||||
ks_domain_2: ks_domain_2,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
update_dashboard_filters(domainsToUpdate){ // params:- domainsToUpdate ( Should be object with key as model_name )
|
||||
let itemsToUpdateList = []
|
||||
Object.keys(domainsToUpdate).forEach( (model) => {
|
||||
this.dashboard_domain_data[model] ??= {}
|
||||
this.dashboard_domain_data[model] = domainsToUpdate[model]
|
||||
itemsToUpdateList.push( ...this.ks_dashboard_data.ks_model_item_relation[model] || [])
|
||||
if(!Object.keys(this.dashboard_domain_data[model].sub_domains ?? {}).length){
|
||||
delete this.dashboard_domain_data[model]
|
||||
}
|
||||
})
|
||||
if(!Object.keys(this.dashboard_domain_data).length){
|
||||
eraseAllCookies(this.ks_dashboard_id, ['PFilter', 'PFilterDataObj', 'Filter', 'CFilter'])
|
||||
}
|
||||
this.state.itemsToUpdateList = JSON.parse(JSON.stringify(itemsToUpdateList))
|
||||
}
|
||||
|
||||
replace_dashboard_filters(domain_data){ // params:- domain_data ( Should be object with key as model_name, replace the existing domain obj )
|
||||
let itemsToUpdateList = []
|
||||
Object.keys(this.dashboard_domain_data).forEach( (model) => {
|
||||
itemsToUpdateList.push( ...this.ks_dashboard_data.ks_model_item_relation[model] || [] )
|
||||
})
|
||||
Object.keys(domain_data).forEach( (model) => {
|
||||
itemsToUpdateList.push( ...this.ks_dashboard_data.ks_model_item_relation[model] || [] )
|
||||
})
|
||||
this.dashboard_domain_data = domain_data
|
||||
this.state.itemsToUpdateList = JSON.parse(JSON.stringify(itemsToUpdateList))
|
||||
this.state.ksDateFilterSelection = 'none'
|
||||
}
|
||||
|
||||
|
||||
get ks_get_current_dashboard_data(){
|
||||
return this.ks_dashboard_data
|
||||
}
|
||||
|
||||
|
||||
dashboard_mount(){
|
||||
var self = this;
|
||||
var items = Object.values(self.ks_dashboard_data.ks_item_data)
|
||||
}
|
||||
|
||||
|
||||
ksRenderDashboard(){
|
||||
let self = this;
|
||||
if (self.ks_dashboard_data.ks_child_boards) self.ks_dashboard_data.name = this.ks_dashboard_data.ks_child_boards[self.ks_dashboard_data.ks_selected_board_id][0];
|
||||
self.ksRenderDashboardMainContent();
|
||||
}
|
||||
|
||||
ksRenderDashboardMainContent(){
|
||||
var self = this;
|
||||
if (isMobileOS() && $('#ks_dn_layout_button :first-child').length > 0) {
|
||||
$('.ks_am_element').append($('#ks_dn_layout_button :first-child')[0].innerText);
|
||||
$(self.header.el).find("#ks_dn_layout_button").addClass("ks_hide");
|
||||
}
|
||||
if (Object.keys(self.ks_dashboard_data.ks_item_data).length) {
|
||||
// todo implement below mentioned function
|
||||
self._renderDateFilterDatePicker();
|
||||
$(self.header.el).find('.ks_dashboard_link').removeClass("ks_hide");
|
||||
} else if (!Object.keys(self.ks_dashboard_data.ks_item_data).length) {
|
||||
$(self.header.el).find('.ks_dashboard_link').addClass("ks_hide");
|
||||
}
|
||||
}
|
||||
|
||||
_renderDateFilterDatePicker() {
|
||||
var self = this;
|
||||
$(self.header.el).find(".ks_dashboard_link").removeClass("ks_hide");
|
||||
self._KsGetDateValues();
|
||||
}
|
||||
|
||||
loadDashboardData(date = false){
|
||||
var self = this;
|
||||
$(self.header.el).find(".custom_date_filter_section").removeClass("ks_hide");
|
||||
$(self.header.el).find(".ks_dashboard_top_settings").addClass("d-none");
|
||||
$(self.header.el).find("#favFilterMain").addClass("ks_hide");
|
||||
$(self.header.el).find(".filters_section").addClass("ks_hide");
|
||||
}
|
||||
|
||||
_KsGetDateValues() {
|
||||
var self = this;
|
||||
var date_filter_selected = self.ks_dashboard_data.ks_date_filter_selection;
|
||||
if (self.ksDateFilterSelection == 'l_none'){
|
||||
var date_filter_selected = self.ksDateFilterSelection;
|
||||
}
|
||||
$(self.header.el).find('#' + date_filter_selected).addClass("ks_date_filter_selected global-filter");
|
||||
|
||||
if (self.ks_dashboard_data.ks_date_filter_selection === 'l_custom') {
|
||||
var ks_end_date = self.ks_dashboard_data.ks_dashboard_end_date;
|
||||
var ks_start_date = self.ks_dashboard_data.ks_dashboard_start_date;
|
||||
var start_date = parseDateTime(ks_start_date, self.datetime_format)
|
||||
var end_date = parseDateTime(ks_end_date, self.datetime_format)
|
||||
self.state.ksDateFilterStartDate = start_date
|
||||
self.state.ksDateFilterEndDate = end_date
|
||||
|
||||
$(self.header.el).find('.ks_date_input_fields').removeClass("ks_hide");
|
||||
$(self.header.el).find('.ks_date_filter_dropdown').addClass("ks_btn_first_child_radius");
|
||||
} else if (self.ks_dashboard_data.ks_date_filter_selection !== 'l_custom') {
|
||||
$(self.header.el).find('.ks_date_input_fields').addClass("ks_hide");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ks_update_date_filter_state(selected_filter_id, ksDateFilterStartDate, ksDateFilterEndDate){
|
||||
let self = this;
|
||||
self.ks_dashboard_data.ks_date_filter_selection = selected_filter_id;
|
||||
self.ks_dashboard_data.ks_dashboard_start_date = ksDateFilterStartDate
|
||||
self.ks_dashboard_data.ks_dashboard_end_date = ksDateFilterEndDate
|
||||
self.state.itemsToUpdateList = JSON.parse(JSON.stringify(this.ks_dashboard_data.ks_dashboard_items_ids))
|
||||
}
|
||||
|
||||
ks_dashboard_item_action(e){
|
||||
this.ksAllowItemClick = false;
|
||||
}
|
||||
|
||||
|
||||
stoppropagation(ev){
|
||||
ev.stopPropagation();
|
||||
this.ksAllowItemClick = false;
|
||||
}
|
||||
|
||||
ksOnLayoutSelection(layout_id){
|
||||
var self = this;
|
||||
var selected_layout_name = this.ks_dashboard_data.ks_child_boards[layout_id][0];
|
||||
var selected_layout_grid_config = this.ks_dashboard_data.ks_child_boards[layout_id][1];
|
||||
this.gridstackConfig = JSON.parse(selected_layout_grid_config);
|
||||
Object.entries(this.gridstackConfig).forEach((x,y)=>{
|
||||
self.grid.update($(self.main_body.el).find(".grid-stack-item[gs-id=" + x[0] + "]")[0],{ x:x[1]['x'], y:x[1]['y'], w:x[1]['w'], h:x[1]['h'],autoPosition:false});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
_onKsSaveLayoutClick(){
|
||||
var self = this;
|
||||
self._ksRenderActiveMode();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
_ksRenderActiveMode(){
|
||||
var self = this
|
||||
if (self.grid && $('.grid-stack').data('gridstack')) {
|
||||
$('.grid-stack').data('gridstack').disable();
|
||||
}
|
||||
}
|
||||
|
||||
ks_remove_update_interval(){
|
||||
var self = this;
|
||||
if (self.ksUpdateDashboard) {
|
||||
Object.values(self.ksUpdateDashboard).forEach(function(itemInterval) {
|
||||
clearInterval(itemInterval);
|
||||
});
|
||||
self.ksUpdateDashboard = {};
|
||||
}
|
||||
}
|
||||
|
||||
onKsEditLayoutClick(e) {
|
||||
var self = this;
|
||||
self.ksAllowItemClick = false;
|
||||
self._ksRenderEditMode();
|
||||
}
|
||||
|
||||
_ksRenderEditMode(){
|
||||
let self = this;
|
||||
self.ks_remove_update_interval();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
KsDashboardNinja.components = { KsHeader, KsItems };
|
||||
KsDashboardNinja.template = "ks_dashboard_ninja.KsDashboardNinjaHeader"
|
||||
registry.category("actions").add("ks_dashboard_ninja", KsDashboardNinja);
|
||||
|
||||
const ks_dn_webclient ={
|
||||
async loadRouterState(...args) {
|
||||
var self = this;
|
||||
const sup = await super.loadRouterState(...args);
|
||||
const ks_reload_menu = async (id) => {
|
||||
this.menuService.reload().then(() => {
|
||||
self.menuService.selectMenu(id);
|
||||
});
|
||||
}
|
||||
this.actionService.ksDnReloadMenu = ks_reload_menu;
|
||||
return sup;
|
||||
},
|
||||
};
|
||||
patch(WebClient.prototype, ks_dn_webclient)
|
||||
@@ -0,0 +1,154 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
|
||||
<t t-name="ks_dashboard_ninja.KsDashboardNinjaHeader" owl="1">
|
||||
<!-- screen -->
|
||||
<KsHeader dashboard_data="ks_get_current_dashboard_data" mode="ks_dashboard_data.ks_dashboard_manager ? 'manager' : 'user'"
|
||||
headerRootRef="headerRootRef"/>
|
||||
|
||||
|
||||
<main class="main-box" t-ref="ks_main_body">
|
||||
<t t-call="ks_dashboard_ninja.ks_main_body_container"/>
|
||||
</main>
|
||||
</t>
|
||||
|
||||
<!-- Dashboard Main Body Container -->
|
||||
<t t-name="ks_dashboard_ninja.ks_main_body_container" owl="1">
|
||||
|
||||
<div class="ks_dashboard_main_content explain-ai-main-content" t-att-class="ks_dashboard_item_length === 0 ? ' h-0' : ''" t-ref="ks_main_body">
|
||||
<t t-if="ks_dashboard_item_length != 0">
|
||||
<t t-if="!state.should_loading">
|
||||
<t t-call="ks_dashboard_item_template"/>
|
||||
</t>
|
||||
<div t-else="state.should_loading">
|
||||
<t t-call="ks_loading_template"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
<t t-if="ks_dashboard_item_length === 0">
|
||||
<t t-call="ksNoItemView"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_loading_template">
|
||||
<div t-att-class="'o_blockUI fixed-top d-flex justify-content-center align-items-center flex-column vh-100'">
|
||||
<div class="o_spinner mb-4">
|
||||
<img src="/ks_dashboard_ninja/static/images/loader.gif" alt="Loading..."/>
|
||||
</div>
|
||||
<div class="o_message text-center px-4">Loading...</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Empty Dashboard View Layout -->
|
||||
<t t-name="ksNoItemView">
|
||||
<section class="overview-sec-dasboards container-fluid h-100">
|
||||
<div t-if="!filteredDashboardsInfo" class="d-flex flex-column justify-content-center align-items-center h-100 no-data">
|
||||
<div>
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/no-data.png" alt="no-data-files" class="img-fluid" loading="lazy"/>
|
||||
</div>
|
||||
<h3 class="mb-0">
|
||||
No Data Found!!
|
||||
</h3>
|
||||
<p class="mb-3">Your Personal Dashboard is Empty!</p>
|
||||
<button class="dash-btn-red d-flex align-items-center" t-if="state.ks_dashboard_manager && !isMobile" t-on-click="onAddItemTypeClick">
|
||||
<span>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="transparent" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 12H16" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 16V8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-2">
|
||||
Create New Chart
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</t>
|
||||
|
||||
<t t-name="ksNoItemChartView">
|
||||
<div class="overview-sec-dasboards container-fluid h-100 graph_text">
|
||||
<div t-if="!filteredDashboardsInfo" class="d-flex flex-column justify-content-center align-items-center h-100 no-data">
|
||||
<div>
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/no-data.png" alt="no-data-files" class="img-fluid" loading="lazy"/>
|
||||
</div>
|
||||
<h3 class="mb-0">
|
||||
No Data Found!!
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!--Item Layouts : -->
|
||||
<t t-name="ks_dashboard_item_template">
|
||||
<KsItems ks_data="ks_get_current_dashboard_data" gridStackRootRef="gridStackRootRef" domain_data_obj="dashboard_domain_data"
|
||||
date_filter_data="state.ksDateFilterSelection" itemsToUpdateList="state.itemsToUpdateList"/>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ksQuickEditButtonContainer">
|
||||
<div class="ks_dashboard_quick_edit_action grid-stack-item" t-att-gs-x="grid.x"
|
||||
t-att-gs-y="grid.y" t-att-gs-w="grid.w" t-att-gs-h="grid.h">
|
||||
<button title="Quick Customize" data-bs-toggle="dropdown"
|
||||
class="ks_dashboard_item_action btn dropdown-toggle btn-xs o-no-caret btn"
|
||||
type="button"
|
||||
aria-expanded="true">
|
||||
<i class="fa fa-cog"/>
|
||||
</button>
|
||||
<div role="menu" class="dropdown-menu ks-dropdown-menu ks_qe_dropdown_menu ">
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_dn_layout_container_new">
|
||||
<t t-if="ks_multi_layout">
|
||||
<div class="ks_am_element dash-dd-2">
|
||||
<button id="ks_dn_layout_button" class="o_dropdown_toggler_btn dashboard_name_bg dropdown-toggle"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<span>
|
||||
<t t-esc="ks_child_boards[ks_selected_board_id][0]"/>
|
||||
</span>
|
||||
<span class="caret"/>
|
||||
</button>
|
||||
<ul id="ks_dashboard_layout_dropdown_container"
|
||||
class="dropdown-menu ks_dashboard_custom_srollbar ks-dropdown-menu dropdown-max-height"
|
||||
role="menu">
|
||||
<t t-foreach="Object.keys(ks_child_boards)" t-as="layout_id" t-key="layout_id_index">
|
||||
<li t-att-class="ks_selected_board_id === layout_id ? 'ks_dashboard_layout_event ks_layout_selected': 'ks_dashboard_layout_event'"
|
||||
t-att-data-ks_layout_id="layout_id" t-on-click="(ev)=>self._ksOnDnLayoutMenuSelect(ev)">
|
||||
<span class="df_selection_text">
|
||||
<t t-esc="ks_child_boards[layout_id][0]"/>
|
||||
</span>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span id="ks_dashboard_title_label" class="ks_am_element dash-dd-2">
|
||||
<t t-esc="ks_dash_name"/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="no-data-view-without-button">
|
||||
<div class="no-data-avilable">
|
||||
<div class="d-flex align-items-center justify-content-center flex-column">
|
||||
<div class="no-data-img">
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/no-data.png" alt="no-data-available" loading="lazy"
|
||||
class="img-fluid w-75"/>
|
||||
</div>
|
||||
<div class="title mb-1">
|
||||
<t t-esc="header_text"/>
|
||||
</div>
|
||||
<p>
|
||||
<t t-esc="body_text"/>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,222 @@
|
||||
/** @odoo-module **/
|
||||
import { Component, useState ,useEffect,onWillUpdateProps,useRef, onMounted, onWillUnmount} from "@odoo/owl";
|
||||
import {globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { loadBundle } from "@web/core/assets";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { onAudioEnded } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { KsItemButton } from '@ks_dashboard_ninja/components/chart_buttons/chart_buttons';
|
||||
|
||||
|
||||
export class Ksdashboardtile extends Component{
|
||||
file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
|
||||
|
||||
setup(){
|
||||
var self = this;
|
||||
this._rpc = rpc
|
||||
this.actionService = useService("action");
|
||||
this.ks_tile = useRef('ks_tile');
|
||||
this.ks_container_class = 'grid-stack-item';
|
||||
this.aiAudioRef = useRef("aiAudioRef");
|
||||
this.ks_inner_container_class = 'grid-stack-item-content';
|
||||
this.state = useState({data_count:""})
|
||||
this.item = this.props.item
|
||||
this.file_type_magic_word= {'/': 'jpg','R': 'gif','i': 'png','P': 'svg+xml'}
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.item.ksIsDashboardManager = this.props.dashboard_data.ks_dashboard_manager
|
||||
this.item.ks_dashboard_list = this.props.dashboard_data.ks_dashboard_list
|
||||
this.ks_ai_analysis = this.ks_dashboard_data.ks_ai_explain_dash
|
||||
if (this.ks_ai_analysis){
|
||||
this.ks_container_class = 'grid-stack-item ks_ai_explain_tile'
|
||||
this.ks_inner_container_class = 'grid-stack-item-content ks_ai_dashboard_item'
|
||||
}else{
|
||||
this.ks_container_class = 'grid-stack-item'
|
||||
this.ks_inner_container_class = 'encapsulated-kpi-tile grid-stack-item-content'
|
||||
}
|
||||
if (this.item.ks_ai_analysis && this.item.ks_ai_analysis){
|
||||
var ks_analysis = this.item.ks_ai_analysis.split('ks_gap')
|
||||
this.ks_ai_analysis_1 = ks_analysis[0]
|
||||
this.ks_ai_analysis_2 = ks_analysis[1]
|
||||
}
|
||||
this.prepare_item();
|
||||
var update_interval = this.props.dashboard_data.ks_set_interval
|
||||
onWillUpdateProps(async(nextprops)=>{
|
||||
if (nextprops.itemsToUpdateList.length){
|
||||
if (nextprops.itemsToUpdateList?.includes(this.item.id)){
|
||||
await this.ksFetchUpdateItem(this.item.id)
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
onMounted(()=>{
|
||||
if (this.ks_ai_analysis){
|
||||
$(this.ks_tile.el).find('.ks_dashboarditem_id').addClass('ks_ai_chart_body')
|
||||
}
|
||||
this.aiAudioRef.el?.addEventListener('ended', onAudioEnded)
|
||||
|
||||
})
|
||||
onWillUnmount( () => {
|
||||
this.aiAudioRef.el?.removeEventListener('ended', onAudioEnded)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
get isMobile() {
|
||||
return isMobileOS();;
|
||||
}
|
||||
|
||||
ksFetchUpdateItem(item_id) {
|
||||
|
||||
var self = this;
|
||||
return rpc("/web/dataset/call_kw/",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_item',
|
||||
args: [
|
||||
[parseInt(item_id)], self.ks_dashboard_data.ks_dashboard_id, self.env.ksGetParamsForItemFetch(self.item.id)
|
||||
],
|
||||
kwargs: { context: self.env.getContext() },
|
||||
}).then(function(new_item_data) {
|
||||
this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id];
|
||||
this.item = this.ks_dashboard_data.ks_item_data[item_id] ;
|
||||
this.__owl__.parent.component.ks_dashboard_data.ks_item_data[this.item.id] = new_item_data[item_id]
|
||||
this.prepare_item()
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ksStopClickPropagation(e){
|
||||
this.ksAllowItemClick = false;
|
||||
}
|
||||
|
||||
prepare_item() {
|
||||
var self = this;
|
||||
var ks_icon_url, item_view;
|
||||
var ks_rgba_background_color, ks_rgba_font_color, ks_rgba_default_icon_color, ks_rgba_button_color;
|
||||
var style_main_body, style_image_body_l2, style_domain_count_body, style_button_customize_body, style_button_delete_body;
|
||||
if (this.item.ks_multiplier_active){
|
||||
var ks_record_count = this.item.ks_record_count * this.item.ks_multiplier
|
||||
if (this.item.ks_unit){
|
||||
var ks_selection = this.item.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = this.item.ks_currency_id;
|
||||
var ks_data = globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
ks_data = globalfunction.ks_monetary(ks_data, ks_currency_id);
|
||||
var data_count = ks_data;
|
||||
} else{
|
||||
var ks_field = this.item.ks_chart_unit;
|
||||
var data_count= ks_field+" "+globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
}
|
||||
}else {
|
||||
var data_count= globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
}
|
||||
var count = ks_record_count;
|
||||
}else{
|
||||
var ks_record_count = this.item.ks_record_count
|
||||
if (this.item.ks_unit){
|
||||
var ks_selection = this.item.ks_unit_selection;
|
||||
if (ks_selection === 'monetary') {
|
||||
var ks_currency_id = this.item.ks_currency_id;
|
||||
var ks_data = globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
ks_data = globalfunction.ks_monetary(ks_data, ks_currency_id);
|
||||
var data_count = ks_data;
|
||||
} else{
|
||||
var ks_field = this.item.ks_chart_unit;
|
||||
var data_count= ks_field+" "+globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
}
|
||||
}else {
|
||||
var data_count= globalfunction._onKsGlobalFormatter(ks_record_count, this.item.ks_data_format, this.item.ks_precision_digits);
|
||||
}
|
||||
var count = ks_record_count;
|
||||
}
|
||||
if (this.item.ks_icon_select == "Custom") {
|
||||
if (this.item.ks_icon[0]) {
|
||||
ks_icon_url = 'data:image/' + (self.file_type_magic_word[this.item.ks_icon[0]] || 'png') + ';base64,' + this.item.ks_icon;
|
||||
} else {
|
||||
ks_icon_url = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.item.ksIsDashboardManager = self.ks_dashboard_data.ks_dashboard_manager;
|
||||
this.item.ksIsUser = true;
|
||||
this.ks_rgba_background_color = self._ks_get_rgba_format(this.item.ks_background_color);
|
||||
this.ks_rgba_font_color = self._ks_get_rgba_format(this.item.ks_font_color);
|
||||
this.ks_rgba_default_icon_color = self._ks_get_rgba_format(this.item.ks_default_icon_color);
|
||||
this.ks_rgba_button_color = self._ks_get_rgba_format(this.item.ks_button_color);
|
||||
if (this.item.ks_info){
|
||||
var ks_description = this.item.ks_info.replace?.(/\\n/g, '\n').split?.('\n');
|
||||
var ks_description = ks_description.filter(element => element !== '')?.join?.(' ') ?? false
|
||||
}else {
|
||||
var ks_description = false;
|
||||
}
|
||||
this.ks_icon_url = ks_icon_url
|
||||
this.state.data_count = data_count
|
||||
this.count = count
|
||||
this.ks_info = ks_description
|
||||
this.ks_dashboard_list= self.ks_dashboard_data.ks_dashboard_list
|
||||
this.style_main_body = this._ksMainBodyStyle(this.ks_rgba_background_color, this.ks_rgba_font_color, this.item).background_style;
|
||||
}
|
||||
|
||||
get style_image_body_l2(){
|
||||
return this._ksMainBodyStyle(this.ks_rgba_background_color, this.ks_rgba_font_color, this.item).style_image_body_l2;
|
||||
}
|
||||
|
||||
get style_main_body_l4(){
|
||||
return "color : " + this.ks_rgba_font_color + ";border : solid;border-width : 1px;";
|
||||
}
|
||||
|
||||
get style_image_body_l4(){
|
||||
return this._ksMainBodyStyle(this.ks_rgba_background_color, this.ks_rgba_font_color, this.item).background_style;
|
||||
}
|
||||
|
||||
_ks_get_rgba_format(val){
|
||||
var rgba = val.split(',')[0].match(/[A-Za-z0-9]{2}/g);
|
||||
rgba = rgba.map(function(v) {
|
||||
return parseInt(v, 16)
|
||||
}).join(",");
|
||||
return "rgba(" + rgba + "," + val.split(',')[1] + ")";
|
||||
}
|
||||
|
||||
_ksMainBodyStyle(ks_rgba_background_color, ks_rgba_font_color, tile){
|
||||
var background_style = "background-color:" + ks_rgba_background_color + ";color : " + ks_rgba_font_color + ";";
|
||||
var ks_rgba_dark_background_color_l2 = this._ks_get_rgba_format(this.ks_get_dark_color(tile.ks_background_color.split(',')[0], tile.ks_background_color.split(',')[1], -10));
|
||||
var style_image_body_l2 = "background-color:" + ks_rgba_dark_background_color_l2 + ";";
|
||||
return {
|
||||
'background_style': background_style,
|
||||
'style_image_body_l2': style_image_body_l2
|
||||
};
|
||||
}
|
||||
|
||||
ks_get_dark_color(color, opacity, percent) {
|
||||
var num = parseInt(color.slice(1), 16),
|
||||
amt = Math.round(2.55 * percent),
|
||||
R = (num >> 16) + amt,
|
||||
G = (num >> 8 & 0x00FF) + amt,
|
||||
B = (num & 0x0000FF) + amt;
|
||||
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1) + "," + opacity;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
Ksdashboardtile.props = {
|
||||
item: { type: Object, optional:true},
|
||||
dashboard_data: { type: Object, optional:true},
|
||||
ksdatefilter : {type:String,optional:true},
|
||||
pre_defined_filter :{type:Object, optional:true},
|
||||
custom_filter :{type:Object, optional:true},
|
||||
itemsToUpdateList :{ type: Array, optional:true },
|
||||
ks_speak:{type:Function , optional:true},
|
||||
hideButtons: { type: Number, optional: true },
|
||||
on_dialog: { type: Boolean, optional: true },
|
||||
generate_dialog: { type: Boolean, optional: true },
|
||||
onItemClick: { type: Function },
|
||||
};
|
||||
|
||||
Ksdashboardtile.template = "ksdashboardtile";
|
||||
Ksdashboardtile.components = { KsItemButton };
|
||||
|
||||
@@ -0,0 +1,592 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="ksdashboardtile">
|
||||
<t t-if="props.item.ks_layout == 'layout1'" t-call="ks_dashboard_item_layout1"/>
|
||||
<t t-elif="props.item.ks_layout == 'layout2'" t-call="ks_dashboard_item_layout2"/>
|
||||
<t t-elif="props.item.ks_layout == 'layout3'" t-call="ks_dashboard_item_layout3"/>
|
||||
<t t-elif="props.item.ks_layout == 'layout4'" t-call="ks_dashboard_item_layout4"/>
|
||||
<t t-elif="props.item.ks_layout == 'layout5'" t-call="ks_dashboard_item_layout5"/>
|
||||
<t t-elif="props.item.ks_layout == 'layout6'" t-call="ks_dashboard_item_layout6"/>
|
||||
<t t-else="" t-call="ks_dashboard_item_layout_default"/>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_item_layout1">
|
||||
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-class="'ks_item_click ' + ks_container_class" t-att-id="item.id" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_1"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-class="'ks_item_click ' + ks_container_class" t-att-id="item.id" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_1"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_1"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_tile_layout_1">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carousel ks_explain_ai_view encapsulated-tile-container ks_dashboard_item ks_dashboard_item_hover ' + ks_inner_container_class"
|
||||
t-att-style="style_main_body"
|
||||
t-att-title="item.ks_info"
|
||||
t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
|
||||
<KsItemButton item_data="this.item" itemRootRef="ks_tile"/>
|
||||
<!-- main-body-lay-out-1-->
|
||||
<div class="ks_dashboard_item_main_body encapsulated-tile-1">
|
||||
<div class="ks_dashboard_icon">
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
<!--<img t-att-src="ks_icon_url"/>-->
|
||||
</div>
|
||||
<div class="ks_dashboard_item_info">
|
||||
<div class="ks_dashboard_item_domain_count" t-att-title="count">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_name" t-att-title="item.name">
|
||||
<t t-esc="item.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- main-body-lay-out-1-->
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_item_layout2">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_2"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24"
|
||||
alt="voice-img" loading="lazy" class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_2"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-class="'ks_item_click ' + ks_container_class" t-att-id="item.id" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_2"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_2"/>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_tile_layout_2">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carousel encap-layout-2-box ks_explain_ai_view ks_dashboard_item_l2 ks_dashboard_item_hover ' + ks_inner_container_class"
|
||||
t-att-style="style_main_body"
|
||||
t-att-title="item.ks_info" t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<!-- main-body-lay-out-2-->
|
||||
<div class="ks_dashboard_item_main_body_l2 ">
|
||||
<div class="ks_dashboard_item_domain_count_l2 layout-2-count" t-att-title="count">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_name_l2 layout-2-name" t-att-title="item.name">
|
||||
<t t-esc="item.name"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_icon_l2 layout-2-icon" t-att-style="style_image_body_l2">
|
||||
<!--<img t-att-src="ks_icon_url"/>-->
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="ks_tile"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_dashboard_item_layout3">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_3"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_3"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_3"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_3"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_tile_layout_3">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carouse encapsulated-tile-container ks_explain_ai_view ks_dashboard_item ks_dashboard_item_hover '+ ks_inner_container_class"
|
||||
t-att-style="'background-color: ' + ks_rgba_background_color + ' !important;'"
|
||||
t-att-title="item.ks_info" t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
|
||||
<KsItemButton item_data="this.item" itemRootRef="ks_tile"/>
|
||||
<!-- main-body-lay-out-3-->
|
||||
<div class="ks_dashboard_item_main_body minimum-180 encapsulated-main-body">
|
||||
<div class="ks_dashboard_icon_l3">
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_info ks_dashboard_item_info_l3" t-att-style="'color:'+ ks_rgba_font_color + ' !important;'">
|
||||
<div class="ks_dashboard_item_domain_count_l3" t-att-title="count" t-att-style="'color:'+ ks_rgba_font_color + ' !important;'">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_name_l3" t-att-title="item.name">
|
||||
<t t-esc="item.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- main-body-lay-out-3-->
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_item_layout4">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_4"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_4"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_4"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_4"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_tile_layout_4">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carousel encapsulated-tile-container ks_explain_ai_view ks_dashboard_item_l2 ks_dashboard_item_hover '+ ks_inner_container_class"
|
||||
t-att-style="'background-color: ' + ks_rgba_background_color + ' !important;'"
|
||||
t-att-title="item.ks_info" t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<!-- main-body-lay-out-4-->
|
||||
<div class="d-flex justify-content-between flex-column w-100">
|
||||
|
||||
|
||||
<div class="ks_dashboard_icon_l4 layout-4-icon bg-white" t-att-style="style_image_body_l4">
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_item_main_body_l2 layout-4-count ks_bg_white">
|
||||
<div class="ks_dashboard_item_domain_count_l2 ms-0" t-att-title="count" t-att-style="'color: ' + ks_rgba_font_color + ' !important;'">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_item_name_l2 layout-4-name ms-0" t-att-title="item.name" t-att-style="'color: ' + ks_rgba_font_color + ' !important;'">
|
||||
<t t-esc="item.name"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- main-body-lay-out-4-->
|
||||
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="ks_tile"/>
|
||||
|
||||
</div>
|
||||
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_item_layout5">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_5"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_5"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_5"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_5"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
|
||||
<t t-name="ks_tile_layout_5">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carousel encapsulated-tile-container ks_explain_ai_view ks_dashboard_item_l5 ks_dashboard_item_hover '+ ks_inner_container_class"
|
||||
t-att-style="style_main_body"
|
||||
t-att-title="item.ks_info" t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
<!-- main-body-lay-out-5-->
|
||||
<div class="ks_dashboard_icon_l5 dashboard-item-icon img-bg">
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_main_body_l5 dashboard-item-data">
|
||||
<div class="ks_dashboard_item_domain_count_l5" t-att-title="count">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_item_name_l5 dashboard-item-name" t-att-title="item.name">
|
||||
<t t-esc="item.name"/>
|
||||
</div>
|
||||
<!-- main-body-lay-out-5-->
|
||||
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l2'" itemRootRef="ks_tile"/>
|
||||
</div>
|
||||
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_dashboard_item_layout6">
|
||||
<t t-if="env.inDialog">
|
||||
<div class="explain-ai pt-3">
|
||||
<div class="container">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<div class="row ks_ai_explain_body">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-sec ks_explain_ai">
|
||||
<t t-call="ks_tile_layout_6"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 col-12">
|
||||
<div class="charts-data h-100">
|
||||
<div class="charts-content-box">
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<!-- <span class="fa fa-volume-up"/>-->
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_6"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class" t-ref="ks_tile">
|
||||
<t t-if="ks_ai_analysis">
|
||||
<div class="ks_ai_explain_body">
|
||||
<t t-call="ks_tile_layout_6"/>
|
||||
<t t-call="ks_item_explanation"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<t t-call="ks_tile_layout_6"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_tile_layout_6">
|
||||
<div t-att-class="'ks_dashboarditem_id ks_tile_carousel layout-6-box encapsulated-tile-container ks_explain_ai_view ks_dashboard_item_l2 ks_dashboard_item_hover '+ ks_inner_container_class"
|
||||
t-att-style="style_main_body"
|
||||
t-att-title="item.ks_info" t-att-id="item.id" t-on-click.stop="() => this.props.onItemClick(item.id)">
|
||||
|
||||
<!-- main-body-lay-out-6-->
|
||||
<div class="d-flex flex-column w-100">
|
||||
<div class="ks_dashboard_item_main_body_l2 layout-6-container">
|
||||
<div class="ks_dashboard_icon_l2">
|
||||
<t t-if="item.ks_icon_select=='Custom'">
|
||||
<t t-if="ks_icon_url">
|
||||
<img t-att-src="ks_icon_url"/>
|
||||
</t>
|
||||
</t>
|
||||
<t t-elif="item.ks_icon_select=='Default'">
|
||||
<span t-att-style="'color:'+ ks_rgba_default_icon_color + ';'"
|
||||
t-att-class="'fa fa-' + item.ks_default_icon + ' fa-4x'"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="ks_dashboard_item_domain_count_l2 layout-6-name ml-0" t-att-title="count">
|
||||
<t t-esc="state.data_count"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ks_dashboard_item_name_l2 layout-6-tile-name" t-att-title="item.name">
|
||||
<span class="ellipsis-content w-100"><t t-esc="item.name"/></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- main-body-lay-out-6-->
|
||||
<KsItemButton item_data="this.item" item_classes="'ks_dashboard_item_header_l6'" itemRootRef="ks_tile"/>
|
||||
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_item_layout_default">
|
||||
<div t-att-id="item.id" t-att-class="'ks_item_click ' + ks_container_class">
|
||||
<div class="ks_dashboard_item ks_tile_carousel ks_explain_ai_view ks_dashboard_item_hover"
|
||||
t-att-style="style_main_body">
|
||||
<t t-if="item.ksIsDashboardManager and props.hideButtons and !props.on_dialog">
|
||||
<div class="ks_dashboard_item_header ks_dashboard_item_header_hover">
|
||||
<button type="button" title="Customize Item" class="ks_dashboard_item_customize">
|
||||
<i class="fa fa-pencil"/>
|
||||
</button>
|
||||
<button type="button" title="Remove Item" class="ks_dashboard_item_delete">
|
||||
<i class="fa fa-times"/>
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
<p>Layout Coming Soon</p>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_item_explanation">
|
||||
<p><t t-esc="ks_ai_analysis_1"/></p>
|
||||
<p><t t-esc="ks_ai_analysis_2"/></p>
|
||||
<div class="voice-button" t-on-click="props.ks_speak" title="Text to speech">
|
||||
<div class="voice-cricle">
|
||||
<img src="/ks_dashboard_ninja/static/images/voice-cricle.svg" height="24" width="24" alt="voice-img" loading="lazy"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<div class="comp-gif d-none">
|
||||
<img src="/ks_dashboard_ninja/static/images/Comp.gif" alt="loading gif" height="24" width="24"
|
||||
class="img-fluid"/>
|
||||
</div>
|
||||
<audio t-ref="aiAudioRef"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,298 @@
|
||||
.encapsulated-tile-container {
|
||||
padding: 12px 10px !important;
|
||||
// border: none !important;
|
||||
|
||||
// tile-2
|
||||
.layout-2-box {
|
||||
padding: 0 !important;
|
||||
|
||||
.layout-2-count {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
margin-top: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.layout-2-icon {
|
||||
border-bottom-left-radius: 16px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 16px;
|
||||
}
|
||||
|
||||
.layout-2-name {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.encapsulated-tile-1 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
|
||||
.ks_dashboard_icon {
|
||||
margin: 0 !important;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
background: $color-white;
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.ks_dashboard_item_info {
|
||||
margin-left: 0 !important;
|
||||
|
||||
.ks_dashboard_item_domain_count {
|
||||
font-family: Poppins;
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
// color: $color-black;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
// color: $color-black;
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks_dashboard_item_button_container {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
// tile-3
|
||||
|
||||
|
||||
|
||||
.encapsulated-main-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
height: 100%;
|
||||
|
||||
|
||||
.ks_dashboard_icon_l3 {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 80px;
|
||||
overflow: hidden;
|
||||
width: 80px;
|
||||
background: $color-white;
|
||||
border-bottom-right-radius: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-top-left-radius: 16px;
|
||||
|
||||
img {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
position: relative;
|
||||
right: 3px;
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 31px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-67%, -59%);
|
||||
}
|
||||
}
|
||||
|
||||
.ks_dashboard_item_domain_count_l3 {
|
||||
text-align: left;
|
||||
font-size: $font-30;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
// color: $color-6789C6;
|
||||
margin-bottom: 5px;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name_l3 {
|
||||
text-align: left;
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
width: 100% !important;
|
||||
// color: $color-black;
|
||||
|
||||
}
|
||||
|
||||
.ks_dashboard_item_info_l3 {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: baseline;
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.layout-4-icon {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
border-top-left-radius: 100%;
|
||||
border-bottom-right-radius: 16px;
|
||||
// background-color: $color-white !important;
|
||||
|
||||
span {
|
||||
font-size: 31px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-30%, -30%);
|
||||
|
||||
}
|
||||
|
||||
img {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
position: relative;
|
||||
right: -5px;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-4-count {
|
||||
font-size: $font-36;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
// color: $color-E7495E;
|
||||
margin-left: 0;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.layout-4-name {
|
||||
font-size: $font-20;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 30px;
|
||||
text-align: left;
|
||||
width: 70% !important;
|
||||
// color: $color-black;
|
||||
}
|
||||
|
||||
.layout-6-name {
|
||||
font-size: $font-36;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
// color: $color-737791;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.layout-6-tile-name {
|
||||
margin-left: 0;
|
||||
min-height: 65px;
|
||||
width: 100%;
|
||||
background: $color-white;
|
||||
padding: 16px;
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 18px;
|
||||
text-align: left;
|
||||
// color: $color-black;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
// layout-2-css
|
||||
.encap-layout-2-box.encapsulated-kpi-tile.grid-stack-item-content {
|
||||
padding: 0 !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.layout-2-count {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
margin-top: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.layout-2-name {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.layout-2-icon {
|
||||
border-bottom-left-radius: 16px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 16px;
|
||||
padding: 17px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
font-size: 4rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.encapsulated-kpi-tile.layout-6-box.grid-stack-item-content {
|
||||
padding: 0 !important;
|
||||
|
||||
.layout-6-container {
|
||||
flex: 1;
|
||||
width: 100% !important;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
|
||||
.ks_dashboard_icon_l2 {
|
||||
padding: 20px 0 10px 13px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
width: fit-content;
|
||||
|
||||
img {
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 31px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { Component,useRef } from "@odoo/owl";
|
||||
|
||||
export class Todoeditdialog extends Component {
|
||||
setup() {
|
||||
}
|
||||
_ks_click(ev){
|
||||
this.props.confirm(event)
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
Todoeditdialog.template = "Kseditdialog";
|
||||
Todoeditdialog.props = {
|
||||
close: Function,
|
||||
confirm: { type: Function, optional: true },
|
||||
ks_description: { type: String, optional: true },
|
||||
}
|
||||
Todoeditdialog.components = { Dialog };
|
||||
|
||||
export class addtododialog extends Component{
|
||||
setup(){
|
||||
}
|
||||
ks_task_click(ev){
|
||||
this.props.confirm(event)
|
||||
this.props.close()
|
||||
}
|
||||
}
|
||||
addtododialog.template = "Ksaddtaskdialog";
|
||||
addtododialog.props = {
|
||||
close: Function,
|
||||
confirm: { type: Function, optional: true },
|
||||
}
|
||||
addtododialog.components = { Dialog };
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="Kseditdialog">
|
||||
<Dialog size="'md'" title="'Edit Task'">
|
||||
<div class="form-control form-input-box">
|
||||
<input type='text' class='ks_description w-100' t-att-value="props.ks_description" placeholder='Task'>
|
||||
</input>
|
||||
</div>
|
||||
<t t-set-slot="footer">
|
||||
<button class=" dash-btn-red" t-on-click="_ks_click">Select</button>
|
||||
<button class=" dash-default-btn" t-on-click="this.props.close">Close</button>
|
||||
</t>
|
||||
</Dialog>
|
||||
</t>
|
||||
|
||||
<t t-name="Ksaddtaskdialog">
|
||||
<Dialog size="'md'" title="'New Task'">
|
||||
<div class="form-control form-input-box">
|
||||
<input type='text' class='ks_section w-100' placeholder='Task'>
|
||||
</input>
|
||||
</div>
|
||||
<t t-set-slot="footer">
|
||||
<button class="dash-btn-red ks_create_task" t-on-click="ks_task_click">Select</button>
|
||||
<button class="dash-default-btn" t-on-click="this.props.close">Close</button>
|
||||
</t>
|
||||
</Dialog>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,263 @@
|
||||
/** @odoo-module **/
|
||||
import { Component, onWillStart, useState ,onMounted, onWillRender,useRef,onWillPatch, onRendered } from "@odoo/owl";
|
||||
import { globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
import { loadBundle } from "@web/core/assets";
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { Todoeditdialog, addtododialog } from "@ks_dashboard_ninja/components/ks_dashboard_to_do_item/editdialog";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { KsItemButton } from '@ks_dashboard_ninja/components/chart_buttons/chart_buttons';
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
export class Ksdashboardtodo extends Component{
|
||||
setup(){
|
||||
super.setup();
|
||||
this._rpc = rpc
|
||||
this.dialogService = useService("dialog");
|
||||
// this.mailChatService = useService("mail.chat_window");
|
||||
// this.threadService = useService("mail.thread");
|
||||
this.state = useState({to_do_view_data : ""})
|
||||
this.todoRootRef = useRef("todoRootRef");
|
||||
this.item = this.props.item
|
||||
this.ks_dashboard_data = this.props.dashboard_data
|
||||
this.item.ksIsDashboardManager = this.props.dashboard_data.ks_dashboard_manager
|
||||
this.item.ks_dashboard_list = this.props.dashboard_data.ks_dashboard_list
|
||||
this.prepare_item();
|
||||
}
|
||||
|
||||
get isMobile() {
|
||||
return isMobileOS();
|
||||
}
|
||||
|
||||
|
||||
ksFetchUpdateItem(item_id) {
|
||||
var self = this;
|
||||
return self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_fetch_item",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_item',
|
||||
args: [
|
||||
[parseInt(item_id)], self.ks_dashboard_data.ks_dashboard_id,{}
|
||||
],
|
||||
kwargs: { context: self.env.getContext() },
|
||||
}).then(function(new_item_data) {
|
||||
this.ks_dashboard_data.ks_item_data[item_id] = new_item_data[item_id];
|
||||
this.item = this.ks_dashboard_data.ks_item_data[item_id] ;
|
||||
this.prepare_item()
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
get ksIsDashboardManager(){
|
||||
return this.ks_dashboard_data.ks_dashboard_manager;
|
||||
}
|
||||
|
||||
get ksIsUser(){
|
||||
return true;
|
||||
}
|
||||
|
||||
get ks_dashboard_list(){
|
||||
return this.ks_dashboard_data.ks_dashboard_list;
|
||||
}
|
||||
|
||||
prepare_item() {
|
||||
var self = this;
|
||||
var item = self.item
|
||||
self.ks_to_do_view_name = 'Test';
|
||||
self.item_id = item.id;
|
||||
self.list_to_do_data = JSON.parse(item.ks_to_do_data);
|
||||
self.state.to_do_view_data = JSON.parse(item.ks_to_do_data);
|
||||
|
||||
self.ks_chart_title = item.name;
|
||||
|
||||
if (item.ks_info){
|
||||
var ks_description = item.ks_info.replace?.(/\\n/g, '\n').split?.('\n');
|
||||
var ks_description = ks_description.filter(element => element !== '')?.join?.(' ') ?? false
|
||||
}else {
|
||||
var ks_description = false;
|
||||
}
|
||||
self.ks_header_color = self._ks_get_rgba_format(item.ks_header_bg_color);
|
||||
self.ks_font_color = self._ks_get_rgba_format(item.ks_font_color);
|
||||
var ks_rgba_button_color = self._ks_get_rgba_format(item.ks_button_color);
|
||||
self.ks_rgba_button_color = ks_rgba_button_color
|
||||
self.ks_info = ks_description
|
||||
self.ks_company = item.ks_company
|
||||
|
||||
|
||||
}
|
||||
|
||||
_ks_get_rgba_format(val){
|
||||
var rgba = val.split(',')[0].match(/[A-Za-z0-9]{2}/g);
|
||||
rgba = rgba.map(function(v) {
|
||||
return parseInt(v, 16)
|
||||
}).join(",");
|
||||
return "rgba(" + rgba + "," + val.split(',')[1] + ")";
|
||||
}
|
||||
_onKsEditTask(e){
|
||||
var self = this;
|
||||
var ks_description_id = e.currentTarget.dataset.contentId;
|
||||
var ks_item_id = e.currentTarget.dataset.itemId;
|
||||
var ks_section_id = e.currentTarget.dataset.sectionId;
|
||||
var ks_description = $(e.currentTarget.parentElement.parentElement).find('.ks_description').attr('value');
|
||||
var ks_result = this.dialogService.add(Todoeditdialog,{
|
||||
ks_description :ks_description,
|
||||
confirm: (event) => {
|
||||
var content = $(event.currentTarget.parentElement.parentElement).find('.ks_description').val();
|
||||
if (content.length === 0){
|
||||
content = ks_description;
|
||||
}
|
||||
self.onSaveTask(content, parseInt(ks_description_id), parseInt(ks_item_id), parseInt(ks_section_id));
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
onSaveTask(content, ks_description_id, ks_item_id, ks_section_id){
|
||||
var self = this;
|
||||
rpc("/web/dataset/call_kw/ks_to.do.description/write",{
|
||||
model: 'ks_to.do.description',
|
||||
method: 'write',
|
||||
args: [ks_description_id, {
|
||||
"ks_description": content
|
||||
}],
|
||||
kwargs:{},
|
||||
}).then(function() {
|
||||
self.ksFetchUpdateItem(ks_item_id).then(function(){
|
||||
$(".ks_li_tab[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_li_tab[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('show');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('show');
|
||||
$(".header_add_btn[data-item-id=" + ks_item_id + "]").attr('data-section-id', ks_section_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_onKsDeleteContent(e){
|
||||
var self = this;
|
||||
var ks_description_id = e.currentTarget.dataset.contentId;
|
||||
var ks_item_id = e.currentTarget.dataset.itemId;
|
||||
var ks_section_id = e.currentTarget.dataset.sectionId;
|
||||
this.dialogService.add(ConfirmationDialog, {
|
||||
body: _t("Are you sure you want to remove this task?"),
|
||||
confirm: () => {
|
||||
self._rpc("/web/dataset/call_kw/ks_to.do.description/unlink",{
|
||||
model: 'ks_to.do.description',
|
||||
method: 'unlink',
|
||||
args: [parseInt(ks_description_id)],
|
||||
kwargs:{}
|
||||
}).then(function(result) {
|
||||
self.ksFetchUpdateItem(ks_item_id).then(function(){
|
||||
$(".ks_li_tab[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_li_tab[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('show');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('show');
|
||||
$(".header_add_btn[data-item-id=" + ks_item_id + "]").attr('data-section-id', ks_section_id);
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
cancel: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
_onKsAddTask(e){
|
||||
var self = this;
|
||||
var ks_section_id = e.currentTarget.dataset.sectionId;
|
||||
var ks_item_id = e.currentTarget.dataset.itemId;
|
||||
var ks_result = this.dialogService.add(addtododialog,{
|
||||
confirm: (event) => {
|
||||
var content = $(event.currentTarget.parentElement.parentElement).find('.ks_section').val();
|
||||
self._onCreateTask(content, parseInt(ks_section_id), parseInt(ks_item_id));
|
||||
},
|
||||
});
|
||||
}
|
||||
_onCreateTask(content, ks_section_id, ks_item_id){
|
||||
var self = this;
|
||||
this._rpc("/web/dataset/call_kw/ks_to.do.description/create",{
|
||||
model: 'ks_to.do.description',
|
||||
method: 'create',
|
||||
args: [{
|
||||
ks_to_do_header_id: ks_section_id,
|
||||
ks_description: content,
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(function() {
|
||||
self.ksFetchUpdateItem(ks_item_id).then(function(){
|
||||
$(".ks_li_tab[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_li_tab[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('show');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('show');
|
||||
$(".header_add_btn[data-item-id=" + ks_item_id + "]").attr('data-section-id', ks_section_id);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
ksOnToDoClick(ev){
|
||||
ev.preventDefault();
|
||||
var self= this;
|
||||
var tab_id = $(ev.currentTarget).attr('href');
|
||||
var $tab_section = $('#' + tab_id.substring(1));
|
||||
$(ev.currentTarget).addClass("active");
|
||||
$(ev.currentTarget).parent().siblings().each(function(){
|
||||
$(this).children().removeClass("active");
|
||||
});
|
||||
$('#' + tab_id.substring(1)).siblings().each(function(){
|
||||
$(this).removeClass("active");
|
||||
$(this).addClass("fade");
|
||||
});
|
||||
$tab_section.removeClass("fade");
|
||||
$tab_section.addClass("active");
|
||||
$(ev.currentTarget).parent().parent().siblings().attr('data-section-id', $(ev.currentTarget).data().sectionId);
|
||||
}
|
||||
|
||||
_onKsActiveHandler(e){
|
||||
var self = this;
|
||||
var ks_item_id = e.currentTarget.dataset.itemId;
|
||||
var content_id = e.currentTarget.dataset.contentId;
|
||||
var ks_task_id = e.currentTarget.dataset.contentId;
|
||||
var ks_section_id = e.currentTarget.dataset.sectionId;
|
||||
var ks_value = e.currentTarget.dataset.valueId;
|
||||
if (ks_value== 'True'){
|
||||
ks_value = false
|
||||
}else{
|
||||
ks_value = true
|
||||
}
|
||||
self.content_id = parseInt(content_id);
|
||||
rpc("/web/dataset/call_kw/ks_to.do.description/write",{
|
||||
model: 'ks_to.do.description',
|
||||
method: 'write',
|
||||
args: [parseInt(content_id), {
|
||||
"ks_active": ks_value
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(function() {
|
||||
self.ksFetchUpdateItem(ks_item_id).then(function(){
|
||||
$(".ks_li_tab[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_li_tab[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('active');
|
||||
$(".ks_tab_section[data-item-id=" + ks_item_id + "]").removeClass('show');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('active');
|
||||
$(".ks_tab_section[data-section-id=" + ks_section_id + "]").addClass('show');
|
||||
$(".header_add_btn[data-item-id=" + ks_item_id + "]").attr('data-section-id', ks_section_id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Ksdashboardtodo.props = {
|
||||
item: { type: Object, Optional:true},
|
||||
dashboard_data: { type: Object, Optional:true},
|
||||
hideButtons: { type: Number, optional: true },
|
||||
on_dialog: { type: Boolean, optional: true },
|
||||
explain_ai_whole: { type: Boolean, optional: true }
|
||||
};
|
||||
Ksdashboardtodo.components = { Todoeditdialog, addtododialog, KsItemButton }
|
||||
|
||||
Ksdashboardtodo.template = "Ksdashboardtodo";
|
||||
@@ -0,0 +1,313 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="Ksdashboardtodo">
|
||||
<t t-if="props.explain_ai_whole">
|
||||
<div class="grid-stack-item ks_tile_carousel ks_dashboarditem_id ks_explain_todo" t-att-id="item_id" t-ref="todoRootRef">
|
||||
<div class="grid-stack-item-content ks_list_view_container ks_dashboard_item_hover card border-0"
|
||||
t-att-title="ks_info" t-att-id="item_id">
|
||||
<div class="ks_card_header encapsulated-header-card" t-att-style="'background-color:'+ ks_header_color + ';' + 'color:'+ ks_font_color + '!important;'">
|
||||
<div class="p-3 py-3 d-flex flex-row align-items-center justify-content-between ">
|
||||
<div class="d-flex align-items-center w-50">
|
||||
<h6 class="m-0 font-weight-bold h3 mr-3 ks_list_view_heading text-capitalize"
|
||||
t-att-style="'color:'+ ks_font_color + ' !important' + ';'"
|
||||
t-att-title="ks_chart_title">
|
||||
<t t-esc="ks_chart_title"/>
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
<KsItemButton item_data="this.item" itemRootRef="todoRootRef"/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-header">
|
||||
<div class="nav-tabs-navigation">
|
||||
<div class="nav-tabs-wrapper">
|
||||
<t t-if="state.to_do_view_data['label']">
|
||||
<ul class="nav nav-tabs" data-tabs="tabs">
|
||||
<t t-set="ks_rec_count" t-value="0"/>
|
||||
<t t-foreach="state.to_do_view_data['label']" t-as="table_header" t-key="table_header_index">
|
||||
<li class="nav-item">
|
||||
<t t-if="ks_rec_count==0">
|
||||
<a class="nav-link active ks_li_tab" t-on-click="ksOnToDoClick"
|
||||
t-att-style="'color:'+ ks_font_color + ' !important' + ';'"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_rec_count]"
|
||||
data-toggle="pill"
|
||||
t-att-href="state.to_do_view_data['ks_link'][ks_rec_count]">
|
||||
<t t-esc="table_header"/>
|
||||
</a>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<a class="nav-link ks_li_tab" t-on-click="ksOnToDoClick"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-style="'color:'+ ks_font_color + ' !important' + ';'"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_rec_count]"
|
||||
data-toggle="pill"
|
||||
t-att-href="state.to_do_view_data['ks_link'][ks_rec_count]">
|
||||
<t t-esc="table_header"/>
|
||||
</a>
|
||||
</t>
|
||||
|
||||
</li>
|
||||
<t t-set="ks_rec_count" t-value="ks_rec_count+1"/>
|
||||
</t>
|
||||
</ul>
|
||||
<button class="header_add_btn" t-on-click="_onKsAddTask"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-style="'color:'+ ks_rgba_button_color + ' !important' + ';'"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][0]">
|
||||
<span class="fa fa-lg fa-plus-circle"/>
|
||||
</button>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<ul class="nav nav-tabs" data-tabs="tabs">
|
||||
<li class="nav-item">
|
||||
No Section Available.
|
||||
</li>
|
||||
</ul>
|
||||
</t>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ks_to_do_card_body card-body table-responsive">
|
||||
<t t-call="ks_to_do_dashboard_inner_body"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
<t t-name="ks_to_do_dashboard_inner_body">
|
||||
<div class="container-fluid p-0">
|
||||
<div>
|
||||
<div>
|
||||
<div class="card">
|
||||
<t t-if="state.to_do_view_data['label']">
|
||||
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<t t-set="ks_section_count" t-value="0"/>
|
||||
<t t-foreach="state.to_do_view_data['ks_href_id']" t-as="ks_href_id" t-key="ks_href_id_index">
|
||||
<t t-if="ks_section_count===0">
|
||||
<div class="tab-pane active ks_tab_section"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-id="ks_href_id">
|
||||
<t t-if="state.to_do_view_data['ks_content'][ks_href_id]">
|
||||
<table class="table">
|
||||
<t t-if="state.to_do_view_data['ks_content'][ks_href_id]">
|
||||
<t t-set="ks_temp_count" t-value="0"/>
|
||||
<t t-foreach="state.to_do_view_data['ks_content'][ks_href_id]"
|
||||
t-as="table_row" t-key="table_row_index">
|
||||
<tr>
|
||||
<t t-if="!ks_tv_play">
|
||||
<td class="ks_custom_check">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
|
||||
<t t-if="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]=='True'">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
value=""/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input class="form-check-input"
|
||||
type="checkbox" value=""
|
||||
checked=""/>
|
||||
</t>
|
||||
|
||||
<span class="form-check-sign ks_do_item_active_handler" t-on-click="_onKsActiveHandler"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-data-value-id="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]">
|
||||
<span class="check"/>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]=='True'">
|
||||
<td class="ks_description"
|
||||
t-att-value="table_row"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]">
|
||||
<t t-esc="table_row"/>
|
||||
</td>
|
||||
</t>
|
||||
|
||||
<t t-else="">
|
||||
<td class="ks_description ks_do_item_line_through"
|
||||
t-att-value="table_row"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]">
|
||||
<t t-esc="table_row"/>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="!ks_tv_play">
|
||||
<td class="td-actions text-right">
|
||||
<button type="button" rel="tooltip"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
class="btn-link btn-sm ks_edit_content" t-on-click="_onKsEditTask"
|
||||
data-original-title="Edit Task">
|
||||
<!-- <i class="material-icons">Edit</i>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
class="btn btn-danger btn-link btn-sm ks_delete_content" t-on-click="_onKsDeleteContent"
|
||||
data-original-title="Remove">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" fill="#4B5563"/>
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.66699 3.31337L5.81366 2.44004C5.92033 1.80671 6.00033 1.33337 7.12699 1.33337H8.87366C10.0003 1.33337 10.087 1.83337 10.187 2.44671L10.3337 3.31337" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.5669 6.09338L12.1336 12.8067C12.0603 13.8534 12.0003 14.6667 10.1403 14.6667H5.86026C4.00026 14.6667 3.94026 13.8534 3.86693 12.8067L3.43359 6.09338" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88672 11H9.10672" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.33301 8.33337H9.66634" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</td>
|
||||
</t>
|
||||
<t t-set="ks_temp_count" t-value="ks_temp_count+1"/>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
</table>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span class="nav-tabs-title">No Tasks Available</span>
|
||||
</t>
|
||||
|
||||
<t t-set="ks_section_count" t-value="ks_section_count+1"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="tab-pane fade ks_tab_section"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-id="ks_href_id">
|
||||
<t t-if="state.to_do_view_data['ks_content'][ks_href_id]">
|
||||
<table class="table">
|
||||
<t t-if="state.to_do_view_data['ks_content'][ks_href_id]">
|
||||
<t t-set="ks_temp_count" t-value="0"/>
|
||||
<t t-foreach="state.to_do_view_data['ks_content'][ks_href_id]"
|
||||
t-as="table_row" t-key="table_row_index">
|
||||
<tr>
|
||||
<t t-if="!ks_tv_play">
|
||||
<td class="ks_custom_check">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<t t-if="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]=='True'">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
value="True"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<input class="form-check-input"
|
||||
type="checkbox"
|
||||
value="False"
|
||||
checked=""/>
|
||||
</t>
|
||||
<span class="form-check-sign ks_do_item_active_handler" t-on-click="_onKsActiveHandler"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-data-value-id="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]">
|
||||
<span class="check"></span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="state.to_do_view_data['ks_content_active'][ks_href_id][ks_temp_count]=='True'">
|
||||
<td class="ks_description"
|
||||
t-att-value="table_row"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]">
|
||||
<t t-esc="table_row"/>
|
||||
</td>
|
||||
</t>
|
||||
|
||||
<t t-else="">
|
||||
<td class="ks_description ks_do_item_line_through"
|
||||
t-att-value="table_row"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]">
|
||||
<t t-esc="table_row"/>
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="!ks_tv_play">
|
||||
<td class="td-actions text-right">
|
||||
<button type="button" rel="tooltip"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
class="btn-link btn-sm ks_edit_content" t-on-click="_onKsEditTask"
|
||||
data-original-title="Edit Task">
|
||||
<!-- <i class="material-icons">Edit</i>-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M9.16675 1.66663H7.50008C3.33341 1.66663 1.66675 3.33329 1.66675 7.49996V12.5C1.66675 16.6666 3.33341 18.3333 7.50008 18.3333H12.5001C16.6667 18.3333 18.3334 16.6666 18.3334 12.5V10.8333" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M13.3666 2.51663L6.7999 9.0833C6.5499 9.3333 6.2999 9.82497 6.2499 10.1833L5.89157 12.6916C5.75823 13.6 6.3999 14.2333 7.30823 14.1083L9.81657 13.75C10.1666 13.7 10.6582 13.45 10.9166 13.2L17.4832 6.6333C18.6166 5.49997 19.1499 4.1833 17.4832 2.51663C15.8166 0.849966 14.4999 1.3833 13.3666 2.51663Z" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
<path d="M12.425 3.45837C12.9834 5.45004 14.5417 7.00837 16.5417 7.57504" stroke="currentColor" stroke-width="1.25" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button type="button"
|
||||
t-att-data-item-id="item_id"
|
||||
t-att-data-section-id="state.to_do_view_data['ks_section_id'][ks_section_count]"
|
||||
t-att-data-content-id="state.to_do_view_data['ks_content_record_id'][ks_href_id][ks_temp_count]"
|
||||
class="btn btn-danger btn-link btn-sm ks_delete_content" t-on-click="_onKsDeleteContent"
|
||||
data-original-title="Remove">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" fill="#4B5563"/>
|
||||
<path d="M14 3.98665C11.78 3.76665 9.54667 3.65332 7.32 3.65332C6 3.65332 4.68 3.71999 3.36 3.85332L2 3.98665" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M5.66699 3.31337L5.81366 2.44004C5.92033 1.80671 6.00033 1.33337 7.12699 1.33337H8.87366C10.0003 1.33337 10.087 1.83337 10.187 2.44671L10.3337 3.31337" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12.5669 6.09338L12.1336 12.8067C12.0603 13.8534 12.0003 14.6667 10.1403 14.6667H5.86026C4.00026 14.6667 3.94026 13.8534 3.86693 12.8067L3.43359 6.09338" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.88672 11H9.10672" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.33301 8.33337H9.66634" stroke="#4B5563" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</td>
|
||||
</t>
|
||||
<t t-set="ks_temp_count" t-value="ks_temp_count+1"/>
|
||||
</tr>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
</table>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span class="nav-tabs-title">No Tasks Available</span>
|
||||
</t>
|
||||
<t t-set="ks_section_count" t-value="ks_section_count+1"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<span class="nav-tabs-title">No Tasks Available</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,3 @@
|
||||
.ks_body_class .nav-tabs-wrapper {
|
||||
word-break: break-word;
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, useEffect, onMounted } from "@odoo/owl"
|
||||
import { useForwardRefToParent } from "@web/core/utils/hooks";
|
||||
import { Ksdashboardtile } from '../ks_dashboard_tile_view/ks_dashboard_tile';
|
||||
import { Ksdashboardtodo } from '../ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||
import { Ksdashboardkpiview } from '../ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||
import { Ksdashboardgraph } from '../ks_dashboard_graphs/ks_dashboard_graphs';
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
|
||||
export class KsItems extends Component {
|
||||
static props = {
|
||||
ks_data : { type: Object, optional:true },
|
||||
domain_data_obj : { type: Object, optional:true },
|
||||
itemsToUpdateList : { type: Array, optional:true },
|
||||
date_filter_data : { type: String, optional:true },
|
||||
gridStackRootRef: { type: Function, optional: true },
|
||||
}
|
||||
static template = "Ks_items"
|
||||
static components = { Ksdashboardtile, Ksdashboardtodo, Ksdashboardkpiview, Ksdashboardgraph }
|
||||
|
||||
setup(){
|
||||
this.ks_dashboard_data = this.props.ks_data
|
||||
this.on_dialog = false;
|
||||
this.gridstackConfig = {};
|
||||
this.actionService = useService('action');
|
||||
this.gridStackRootRef = useForwardRefToParent("gridStackRootRef")
|
||||
this.explain_ai_whole = true;
|
||||
this.gridstack_options = {
|
||||
staticGrid:true,
|
||||
float: false,
|
||||
cellHeight: 68,
|
||||
styleInHead : true,
|
||||
disableOneColumnMode: true,
|
||||
};
|
||||
if (isMobileOS()) {
|
||||
this.gridstack_options.disableOneColumnMode = false
|
||||
}
|
||||
onMounted( () => this.onMount())
|
||||
|
||||
}
|
||||
|
||||
onMount(){
|
||||
this.grid = GridStack.init(this.gridstack_options, $(".grid-stack")[0]);
|
||||
if(!this.env.inDialog) this.grid_initiate();
|
||||
}
|
||||
|
||||
grid_initiate(){
|
||||
var self=this;
|
||||
var $gridstackContainer = $(".grid-stack");
|
||||
if($gridstackContainer.length){
|
||||
var item = self.ksSortItems(self.ks_dashboard_data.ks_item_data)
|
||||
if(this.ks_dashboard_data.ks_gridstack_config){
|
||||
this.gridstackConfig = JSON.parse(this.ks_dashboard_data.ks_gridstack_config);
|
||||
}
|
||||
for (var i = 0; i < item.length; i++) {
|
||||
var graphs = ['ks_scatter_chart','ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart','ks_polarArea_chart','ks_pie_chart','ks_flower_view', 'ks_radar_view','ks_radialBar_chart','ks_map_view','ks_funnel_chart','ks_bullet_chart', 'ks_to_do', 'ks_list_view']
|
||||
var $ks_preview = $('#' + item[i].id)
|
||||
if ($ks_preview.length && !this.ks_dashboard_data.ks_ai_explain_dash) {
|
||||
if (item[i].id in self.gridstackConfig) {
|
||||
var min_width = graphs.includes(item[i].ks_dashboard_item_type) ? 3 : 2
|
||||
self.grid.addWidget($ks_preview[0], {x:self.gridstackConfig[item[i].id].x, y:self.gridstackConfig[item[i].id].y, w:self.gridstackConfig[item[i].id].w, h: self.gridstackConfig[item[i].id].h, autoPosition:false, minW:min_width, maxW:null, minH:3, maxH:null, id:item[i].id});
|
||||
} else if ( graphs.includes(item[i].ks_dashboard_item_type)) {
|
||||
self.grid.addWidget($ks_preview[0], {x:0, y:0, w:5, h:6,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :item[i].id});
|
||||
}else{
|
||||
self.grid.addWidget($ks_preview[0], {x:0, y:0, w:2, h:2,autoPosition:true,minW:2,maxW:null,minH:3,maxH:2,id:item[i].id});
|
||||
}
|
||||
}else{
|
||||
if (item[i].id in self.gridstackConfig) {
|
||||
var min_width = graphs.includes(item[i].ks_dashboard_item_type)? 3:2
|
||||
self.grid.addWidget($ks_preview[0], {x:self.gridstackConfig[item[i].id].x, y:self.gridstackConfig[item[i].id].y, w:12, h: 6, autoPosition:false, minW:min_width, maxW:null, minH:2, maxH:null, id:item[i].id});
|
||||
} else {
|
||||
self.grid.addWidget($ks_preview[0], {x:0, y:0, w:12, h:6,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :item[i].id});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
this.grid.setStatic(true);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ksSortItems(ks_item_data) {
|
||||
let items = []
|
||||
let self = this;
|
||||
var item_data = Object.assign({}, ks_item_data);
|
||||
if (self.ks_dashboard_data.ks_gridstack_config) {
|
||||
self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_gridstack_config);
|
||||
let a = Object.values(self.gridstackConfig);
|
||||
let b = Object.keys(self.gridstackConfig);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
a[i]['id'] = b[i];
|
||||
}
|
||||
a.sort(function(a, b) {
|
||||
return (35 * a.y + a.x) - (35 * b.y + b.x);
|
||||
});
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
if (item_data[a[i]['id']]) {
|
||||
items.push(item_data[a[i]['id']]);
|
||||
delete item_data[a[i]['id']];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items.concat(Object.values(item_data));
|
||||
}
|
||||
|
||||
_onKsItemClick(item_id){
|
||||
let self = this;
|
||||
let action ;
|
||||
// To Handle only allow item to open when not clicking on item
|
||||
if(self.env.mode === 'edit' || this.env.inDialog) return;
|
||||
let item_data = self.ks_dashboard_data.ks_item_data[item_id];
|
||||
if (item_data && item_data.ks_show_records && item_data.ks_data_calculation_type != 'query' && item_data.ks_model_name) {
|
||||
|
||||
if (item_data.action) {
|
||||
action = Object.assign({}, item_data.action);
|
||||
if (action.view_mode.includes('tree')) action.view_mode = action.view_mode.replace('tree', 'list');
|
||||
for (var i = 0; i < action.views.length; i++) action.views[i][1].includes('tree') ? action.views[i][1] = action.views[i][1].replace('tree', 'list') : action.views[i][1];
|
||||
action['domain'] = item_data.ks_domain || [];
|
||||
action['search_view_id'] = [action.search_view_id, 'search']
|
||||
|
||||
} else {
|
||||
action = {
|
||||
name: _t(item_data.name),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: item_data.ks_model_name,
|
||||
domain: item_data.ks_domain || "[]",
|
||||
views: [
|
||||
[false, 'list'],
|
||||
[false, 'form']
|
||||
],
|
||||
view_mode: 'list',
|
||||
target: 'current',
|
||||
}
|
||||
}
|
||||
|
||||
if(action){
|
||||
self.actionService.doAction(action);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async speak_once(ev,item){
|
||||
ev.preventDefault()
|
||||
var ks_audio = ev.currentTarget;
|
||||
let ks_speeches = []
|
||||
ev.currentTarget.parentElement.querySelector('.voice-cricle').classList.toggle("d-none");
|
||||
ev.currentTarget.parentElement.querySelector('.comp-gif').classList.toggle("d-none");
|
||||
$(document.querySelectorAll('audio')).each((index,item)=>{
|
||||
if ($(ks_audio).find('audio')[0] !== item && !item.paused){
|
||||
item.pause()
|
||||
item.parentElement?.querySelector('.voice-cricle')?.classList.toggle("d-none");
|
||||
item.parentElement?.querySelector('.comp-gif')?.classList.toggle("d-none");
|
||||
}
|
||||
})
|
||||
if (!ks_speeches.length){
|
||||
if ($(ks_audio).find('audio').attr('src') && $(ks_audio).find('audio')[0].paused){
|
||||
$(ks_audio).find('audio')[0].play();
|
||||
$(ks_audio).find('.fa.fa-volume-up').removeClass('d-none');
|
||||
$(ks_audio).find('.comp-gif').removeClass('d-none');
|
||||
$(ks_audio).find('.voice-cricle').addClass('d-none');
|
||||
$(ks_audio).find('.fa.fa-pause').remove();
|
||||
}else if ($(ks_audio).find('audio').attr('src') && !$(ks_audio).find('audio')[0].paused){
|
||||
$(ks_audio).find('audio')[0].pause();
|
||||
$(ks_audio).find('.voice-cricle').removeClass('d-none');
|
||||
$(ks_audio).find('.comp-gif').addClass('d-none');
|
||||
$(ks_audio).find('.fa.fa-volume-up').addClass('d-none');
|
||||
}else{
|
||||
$(ks_audio).find('.comp-gif').removeClass('d-none');
|
||||
$(ks_audio).find('.voice-cricle').addClass('d-none');
|
||||
ks_speeches.push(rpc('/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_generatetext_to_speech',{
|
||||
model : "ks_dashboard_ninja.arti_int",
|
||||
method:"ks_generatetext_to_speech",
|
||||
args:[item.id],
|
||||
kwargs:{}
|
||||
}).then(function(result){
|
||||
if (result){
|
||||
$(ks_audio).find('span').removeClass('d-none')
|
||||
var audio = (JSON.parse(result)).snd;
|
||||
$(ks_audio).find('audio')[0].src="data:audio/wav;base64, "+audio;
|
||||
$(ks_audio).find('audio')[0].play()
|
||||
ks_speeches.pop()
|
||||
}
|
||||
else{
|
||||
$(ks_audio).find('.comp-gif').addClass('d-none');
|
||||
$(ks_audio).find('.voice-cricle').removeClass('d-none');
|
||||
ks_speeches.pop()
|
||||
}
|
||||
}.bind(this))
|
||||
)
|
||||
return Promise.resolve(ks_speeches)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
.ks_body_class .grid-stack-item>.grid-stack-item-content {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.ks_body_class .grid-stack-item.ui-draggable{
|
||||
cursor: move;
|
||||
.ks_dashboard_item_header_hover {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="Ks_items">
|
||||
<div class="ks_dashboard_item_content grid-stack ks_dashboard_items_list m-3" gs-w="36" t-ref="gridStackRootRef"/>
|
||||
<t t-call="items_renderer"/>
|
||||
</t>
|
||||
<t t-name="items_renderer">
|
||||
<t t-foreach="Object.values(props.ks_data.ks_item_data)" t-as="item" t-key="item.id">
|
||||
<t t-if="item.ks_dashboard_item_type === 'ks_tile'">
|
||||
<Ksdashboardtile item="item" hideButtons="1" on_dialog="on_dialog" dashboard_data="props.ks_data"
|
||||
ksdatefilter="props.date_filter_data" itemsToUpdateList="props.itemsToUpdateList"
|
||||
onItemClick.bind="_onKsItemClick" ks_speak="(ev) => this.speak_once(ev, item)"/>
|
||||
</t>
|
||||
<t t-elif="item.ks_dashboard_item_type === 'ks_kpi'">
|
||||
<Ksdashboardkpiview item="item" hideButtons="1" on_dialog="on_dialog" dashboard_data="props.ks_data"
|
||||
ksdatefilter="props.date_filter_data" itemsToUpdateList="props.itemsToUpdateList"
|
||||
onItemClick.bind="_onKsItemClick" ks_speak="(ev) => this.speak_once(ev, item)"/>
|
||||
</t>
|
||||
<t t-elif="item.ks_dashboard_item_type === 'ks_to_do'">
|
||||
<Ksdashboardtodo item="item" hideButtons="1" dashboard_data="ks_dashboard_data" explain_ai_whole="explain_ai_whole"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<Ksdashboardgraph item="item" hideButtons="1" explain_ai_whole="explain_ai_whole" dashboard_data="props.ks_data"
|
||||
ksdatefilter="props.date_filter_data" itemsToUpdateList="props.itemsToUpdateList" ks_speak="(ev) => this.speak_once(ev, item)"
|
||||
onItemClick.bind="_onKsItemClick"/>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -0,0 +1,103 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onWillStart, onWillUpdateProps } from "@odoo/owl";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { useBus } from "@web/core/utils/hooks";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { useGetTreeDescription } from "@web/core/tree_editor/utils";
|
||||
import { treeFromDomain } from "@web/core/tree_editor/condition_tree";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
|
||||
|
||||
export class ModelDrivenFilterApplicator extends Component {
|
||||
|
||||
/*
|
||||
* This component is based on event bus
|
||||
* Takes any model name , group [ domain with key ]
|
||||
* Applies it to dashboard and maintains its history
|
||||
*/
|
||||
|
||||
static template = "ks_dashboard_ninja.model_driven_filter_applicator"
|
||||
static props = {
|
||||
update: { type: Function },
|
||||
remove: { type: Function },
|
||||
removeAllFilters: { type: Boolean },
|
||||
options: { type: Object, optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
options: {},
|
||||
};
|
||||
|
||||
setup(){
|
||||
this.getDomainTreeDescription = useGetTreeDescription();
|
||||
this.state = useState({
|
||||
'facets' : {}
|
||||
})
|
||||
if(!this.env.inDialog)
|
||||
useBus(this.env.bus, 'APPLY: Dashboard Filter', ({ detail }) => this.addFacet(detail.model_display_name, detail.model_name, detail.field_name,
|
||||
detail.operator, detail.value))
|
||||
|
||||
onWillStart( () => this.apply_cookies_data() )
|
||||
onWillUpdateProps((nextProps) => this.onPropsUpdated(nextProps))
|
||||
}
|
||||
|
||||
onPropsUpdated(nextProps){
|
||||
if(nextProps.removeAllFilters){
|
||||
eraseCookie('ChartFilter' + this.props.options.ks_dashboard_id)
|
||||
this.clearFacets();
|
||||
}
|
||||
}
|
||||
|
||||
apply_cookies_data(){
|
||||
let facets_data = getObjectFromCookie('ChartFilter' + this.props.options.ks_dashboard_id)
|
||||
this.state.facets = facets_data ?? {}
|
||||
}
|
||||
|
||||
clearFacets(){
|
||||
this.state.facets = {}
|
||||
}
|
||||
|
||||
async make_label(model, domain){
|
||||
let label = await this.getDomainTreeDescription(model, treeFromDomain(domain));
|
||||
return label;
|
||||
}
|
||||
|
||||
async addFacet(model_display_name, model_name, field_name, operator, value){
|
||||
let group_name = `${model_name + '_' + field_name + operator + value}`
|
||||
let domain = new Domain([[field_name , operator, value]]).toList();
|
||||
|
||||
let facets_to_update = this.state.facets[model_name] || { groups: {}, model_name: model_display_name }
|
||||
|
||||
if(!facets_to_update.groups[group_name]){
|
||||
let label = await this.make_label(model_name, domain)
|
||||
|
||||
facets_to_update.groups[group_name] = { label: label, domain: domain }
|
||||
this.state.facets[model_name] = facets_to_update
|
||||
this.apply_domain(model_name, group_name, domain);
|
||||
}
|
||||
}
|
||||
|
||||
onRemoveFacet(model, group){
|
||||
/**
|
||||
* This method remove the facet or domain showing through facet from the dashboard
|
||||
*/
|
||||
eraseCookie('ChartFilter' + this.props.options.ks_dashboard_id)
|
||||
delete this.state.facets[model].groups[group];
|
||||
|
||||
if(!Object.values(this.state.facets[model].groups).length) delete this.state.facets[model];
|
||||
setObjectInCookie('ChartFilter' + this.props.options.ks_dashboard_id, this.state.facets, 1)
|
||||
this.props.remove([model], [group]);
|
||||
}
|
||||
|
||||
apply_domain(model_name, group_name, domain){
|
||||
/**
|
||||
* This method create the domain and update to the dashboards domain data
|
||||
*/
|
||||
eraseCookie('ChartFilter' + this.props.options.ks_dashboard_id)
|
||||
let domain_data_to_update = { [model_name]: { [group_name]: { domain: domain}}}
|
||||
setObjectInCookie('ChartFilter' + this.props.options.ks_dashboard_id, this.state.facets, 1)
|
||||
|
||||
this.props.update(domain_data_to_update)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
.custom-dash-collapse{
|
||||
.o_input{
|
||||
button{
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
.dropdown-toggle.d-flex.encapsulated-link{
|
||||
overflow: auto;
|
||||
max-height: 75px;
|
||||
}
|
||||
.dash-default-btn{
|
||||
svg{
|
||||
fill: transparent !important;
|
||||
}
|
||||
}
|
||||
.table-dlt-btn{
|
||||
&:hover{
|
||||
border-color: #E7495E !important;
|
||||
svg{
|
||||
stroke: #E7495E !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 150px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks-nav-link{
|
||||
button{
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
.dash-dd-2{
|
||||
.selcted-opt.opted{
|
||||
background-color: #F5F8FB;
|
||||
padding-right: 22px;
|
||||
}
|
||||
.dropdown-toggle{
|
||||
&:after{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.encapsulated-cross {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 1600px) {
|
||||
.custom-dash-collapse{
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 80px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1600px) {
|
||||
.custom-dash-collapse{
|
||||
.o-dropdown{
|
||||
.ks-nav-link{
|
||||
button{
|
||||
min-width: 60px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name='ks_dashboard_ninja.model_driven_filter_applicator'>
|
||||
<t t-if="Object.values(state.facets).length" t-call="ks_dn.facets_container">
|
||||
<t t-set="filter_data" t-value="state.facets"/>
|
||||
<t t-set="remove" t-value="onRemoveFacet.bind(this)"/>
|
||||
</t>
|
||||
<t t-else="" t-call="no-data-view-without-button">
|
||||
<t t-set="header_text" t-value="'No Filter Applied'"/>
|
||||
<t t-set="body_text" t-value="'Apply from List Chart :) '"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,141 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { Component, onWillStart, useState, useEffect, onWillUnmount, onMounted } from "@odoo/owl";
|
||||
//import { dnNavBarAddClasses } from "@ks_dashboard_ninja/js/dnNavBarExtend";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { debounce } from "@web/core/utils/timing";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { WarningDialog } from "@web/core/errors/error_dialogs";
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
//import { rpc } from "@web/core/network/rpc";
|
||||
//import { user } from "@web/core/user";
|
||||
|
||||
|
||||
export class KSDashboardNinjaOverview extends Component{
|
||||
setup(){
|
||||
this.rpc = rpc
|
||||
this.orm = useService("orm");
|
||||
this.actionService = useService("action");
|
||||
this.overviewTilesNames = [['All Dashboards', 'one'], ['All Charts', 'two'], ['Total Maps', 'three'],
|
||||
['Bookmarked Dashboards', 'four'], ['All Lists', 'five']]
|
||||
this.state = useState({
|
||||
bookmarkedDashboards: false,
|
||||
filter: localStorage.getItem('dashboardFilter') || "All Dashboards",
|
||||
})
|
||||
|
||||
onWillStart(async () => {
|
||||
this.data = await rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/fetch_dashboard_overview",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'fetch_dashboard_overview',
|
||||
args: [[]],
|
||||
kwargs:{},
|
||||
});
|
||||
await rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_update_menu_id",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_update_menu_id_old_db',
|
||||
args: [[]],
|
||||
kwargs:{},
|
||||
});
|
||||
await this.env.services.menu.reload()
|
||||
});
|
||||
|
||||
onWillUnmount(()=>{
|
||||
document.querySelector(".ks-zoom-view")?.classList.remove("d-none")
|
||||
})
|
||||
|
||||
onMounted(()=>{
|
||||
if (document.body.classList.contains("ks_body_class")){
|
||||
document.querySelector(".ks-zoom-view")?.classList.add("d-none")
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
get isMobile(){
|
||||
return isMobileOS();
|
||||
}
|
||||
|
||||
get filteredDashboards(){
|
||||
if (this.state.filter === 'Bookmarked'){
|
||||
let filteredData = Object.entries(this.data.dashboardsInfo).filter( (dashboard)=> dashboard[1].is_bookmarked);
|
||||
return filteredData.length ? Object.fromEntries(filteredData) : false;
|
||||
}
|
||||
return this.data.overviewInfo[0] ? this.data.dashboardsInfo : false;
|
||||
}
|
||||
|
||||
async viewDashboard(ev){
|
||||
ev.preventDefault();
|
||||
const dashboardId = parseInt(ev.currentTarget.dataset.dashboardId)
|
||||
let clientActionId = await this.orm.silent.read(
|
||||
'ks_dashboard_ninja.board',
|
||||
[dashboardId],
|
||||
['ks_dashboard_client_action_id']
|
||||
);
|
||||
clientActionId = clientActionId[0]?.ks_dashboard_client_action_id[0]
|
||||
|
||||
|
||||
this.actionService.doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "ks_dashboard_ninja",
|
||||
params:{
|
||||
ks_dashboard_id: dashboardId
|
||||
},
|
||||
id: clientActionId
|
||||
});
|
||||
// if(menuId){
|
||||
// let response = await this.env.services.menu.selectMenu(menuId);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
onFilterChange(ev){
|
||||
this.state.filter = ev.target.text;
|
||||
this.state.bookmarkedDashboards = !this.state.bookmarkedDashboards;
|
||||
localStorage.setItem("dashboardFilter", this.state.filter);
|
||||
if($('#overviewFilter'))
|
||||
$('#overviewFilter').text(this.state.filter);
|
||||
}
|
||||
|
||||
async updateBookmark(ev){
|
||||
let dashboardId = parseInt(ev.currentTarget.dataset.dashboardId);
|
||||
let unBookmarkSvg = $(`#unBookmark${dashboardId}`);
|
||||
let bookmarkSvg = $(`#bookmark${dashboardId}`);
|
||||
let bookmarkCountTag = $('[id="Bookmarked Dashboards"]');
|
||||
if (unBookmarkSvg && bookmarkSvg){
|
||||
unBookmarkSvg.toggleClass('d-none');
|
||||
bookmarkSvg.toggleClass('d-none');
|
||||
}
|
||||
this.data.dashboardsInfo[dashboardId].is_bookmarked = !this.data.dashboardsInfo[dashboardId].is_bookmarked;
|
||||
let updatedBookmarks = await this.rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/update_bookmarks",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'update_bookmarks',
|
||||
args: [[dashboardId]],
|
||||
kwargs:{},
|
||||
});
|
||||
bookmarkCountTag.text(updatedBookmarks[0]);
|
||||
}
|
||||
|
||||
createDashboard(ev){
|
||||
let action = {
|
||||
name: _t('Create Dashboard'),
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'ks.dashboard.wizard',
|
||||
domain: [],
|
||||
context: {
|
||||
},
|
||||
views: [
|
||||
[false, 'form']
|
||||
],
|
||||
view_mode: 'form',
|
||||
target: 'new',
|
||||
}
|
||||
this.actionService.doAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
KSDashboardNinjaOverview.template = "ks_dashboard_ninja.dashboardNinjaOverView";
|
||||
|
||||
registry.category("actions").add("dashboard_ninja", KSDashboardNinjaOverview);
|
||||
@@ -0,0 +1,175 @@
|
||||
.overview-sec-one {
|
||||
h1 {
|
||||
font-size: $font-20;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 28px;
|
||||
color: $color-black;
|
||||
margin-bottom: 0;
|
||||
|
||||
@include max-575 {
|
||||
font-size: $font-12;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: $f-w-600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overview-sec-tiles {
|
||||
@media screen and (min-width:1200px) {
|
||||
.col-xl-2 {
|
||||
flex: 1;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.tile {
|
||||
min-height: 113px;
|
||||
border-radius: 16px;
|
||||
padding: 14px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 4px 12px 0px #00000040;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
&.one {
|
||||
background-color: $color-FFE2E5;
|
||||
}
|
||||
|
||||
&.two {
|
||||
background-color: $color-FFF4DE;
|
||||
}
|
||||
|
||||
&.three {
|
||||
background-color: $color-DCFCE7;
|
||||
}
|
||||
|
||||
&.four {
|
||||
background-color: $color-F3E8FF;
|
||||
}
|
||||
|
||||
&.five {
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 33.6px;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-15;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18px;
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overview-sec-dasboards {
|
||||
|
||||
.no-data {
|
||||
max-height: calc(100% - 56px);
|
||||
overflow: auto;
|
||||
|
||||
h3 {
|
||||
font-size: $font-32;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 44.8px;
|
||||
color: $color-secondary-main;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-20;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 28px;
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
.data-added {
|
||||
|
||||
max-height: calc(100vh - 467px);
|
||||
overflow: auto;
|
||||
|
||||
@include max-768 {
|
||||
max-height: unset;
|
||||
overflow: unset;
|
||||
}
|
||||
|
||||
@include custom-scrollbar;
|
||||
|
||||
@media screen and (min-width:1200px) {
|
||||
max-height: calc(100vh - 331px);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) and (orientation: landscape) {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.dashboard-box {
|
||||
box-shadow: 0px 4px 20px 0px #EEEEEE80;
|
||||
border-radius: 10px;
|
||||
background-color: $color-white;
|
||||
padding: 20px;
|
||||
min-height: 290px;
|
||||
|
||||
.dash-preview-box {
|
||||
border-radius: 10px;
|
||||
border: 0.5px solid $color-E5E7EB;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
// height: 290px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
aspect-ratio: 16/9;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-info {
|
||||
.left {
|
||||
h4 {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 22.4px;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18px;
|
||||
color: $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
.marked {
|
||||
.bookmark {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.bookmarked {
|
||||
display: block !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bookmark {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
<t t-name="ks_dashboard_ninja.dashboardNinjaOverView" owl="1">
|
||||
<main class="main-box">
|
||||
<section class="overview-sec-one mb-4 pb-1">
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<h1>Welcome <span t-esc="data.user_name"/></h1>
|
||||
<div class="d-flex align-items-center">
|
||||
<!-- custom-dd-2-start -->
|
||||
<div class="dropdown dash-dd-2">
|
||||
<a t-ref="overviewFilter" class="text-decoration-none dropdown-toggle" href="#" role="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<t t-esc="state.filter"/>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu ks-dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" t-on-click="onFilterChange">All Dashboards</a></li>
|
||||
<li><a class="dropdown-item" href="#" t-on-click="onFilterChange">Bookmarked</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- custom-dd-2-end -->
|
||||
<button class="dash-btn-red d-flex align-items-center ms-3 d-none d-md-flex" t-if="data.isManager" t-on-click="createDashboard">
|
||||
<span>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="transparent" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 12H16" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 16V8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-1">
|
||||
Add New Dashboard
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="overview-sec-tiles mb-4 pb-1 container-fluid">
|
||||
<div class="d-flex align-items-center row-gap-3 row">
|
||||
<t t-foreach="[0,1,2,3,4]" t-as="i" t-key="i">
|
||||
<div class="col-xl-2 col-lg-3 col-md-4 col-sm-6 col-12">
|
||||
<div t-attf-class="tile {{overviewTilesNames[i][1]}} d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<div t-attf-id="{{overviewTilesNames[i][0]}}" class="num mb-1">
|
||||
<t t-esc="data.overviewInfo[i]"/>
|
||||
</div>
|
||||
<p class="mb-1"><t t-esc="overviewTilesNames[i][0]"/></p>
|
||||
</div>
|
||||
<div>
|
||||
<img t-attf-src="/ks_dashboard_ninja/static/images/dashboardOverview/{{overviewTilesNames[i][0]}}.svg" alt="category" loading="lazy" class="img-fluid"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</section>
|
||||
<section class="overview-sec-dasboards container-fluid">
|
||||
<t t-set="filteredDashboardsInfo" t-value="filteredDashboards"/>
|
||||
<!-- no-data-found -->
|
||||
<div t-if="!filteredDashboardsInfo" class="d-flex flex-column justify-content-center align-items-center h-100 no-data">
|
||||
<div>
|
||||
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/no-data.png" alt="no-data-files" class="img-fluid" loading="lazy"/>
|
||||
</div>
|
||||
<h3 class="mb-0">
|
||||
No Data Found!!
|
||||
</h3>
|
||||
<p class="mb-3">No Dashboard’s have been Found</p>
|
||||
<button class="dash-btn-red d-flex align-items-center" t-if="data.isManager && !isMobile" t-on-click="createDashboard">
|
||||
<span>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="transparent" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 22C17.5 22 22 17.5 22 12C22 6.5 17.5 2 12 2C6.5 2 2 6.5 2 12C2 17.5 6.5 22 12 22Z" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M8 12H16" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 16V8" stroke="#fff" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="ms-2">
|
||||
Add New Dashboard
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="row row-gap-34 data-added" t-if="filteredDashboardsInfo">
|
||||
<t t-foreach="filteredDashboardsInfo" t-as="dashboard" t-key="dashboard">
|
||||
<div class="col-xl-4 col-md-6 col-12">
|
||||
<div class="dashboard-box flex-column d-flex align-items-center justify-content-center">
|
||||
<div class="mb-2 dash-preview-box">
|
||||
<img t-att-src="data.dashboardsInfo[dashboard].image" alt="dashboard-img" class="img-fluid"
|
||||
loading="lazy"/>
|
||||
</div>
|
||||
<div class="d-flex w-100 justify-content-between align-items-center dashboard-info">
|
||||
<div class="left w-50">
|
||||
<h4 class="text-truncate"><t t-esc="data.dashboardsInfo[dashboard].name"/></h4>
|
||||
<p><t t-esc="data.dashboardsInfo[dashboard].chartCount"/>
|
||||
Charts</p>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div class="right w-50">
|
||||
<div class="marked mb-2 d-flex justify-content-end align-items-center">
|
||||
<div t-attf-id="unBookmark{{data.dashboardsInfo[dashboard].id}}" t-att-class="data.dashboardsInfo[dashboard].is_bookmarked ? 'd-none' : ''"
|
||||
t-on-click="updateBookmark" t-att-data-dashboard-id="data.dashboardsInfo[dashboard].id"
|
||||
title="Bookmark the dashboard">
|
||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" class="bookmark"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.70831 7.54163C9.19165 8.08329 10.8083 8.08329 12.2916 7.54163"
|
||||
stroke="#292D32" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M14.0169 1.66669H5.98357C4.20857 1.66669 2.76691 3.11669 2.76691 4.88335V16.625C2.76691 18.125 3.84191 18.7584 5.15857 18.0334L9.22524 15.775C9.65857 15.5334 10.3586 15.5334 10.7836 15.775L14.8502 18.0334C16.1669 18.7667 17.2419 18.1334 17.2419 16.625V4.88335C17.2336 3.11669 15.7919 1.66669 14.0169 1.66669Z"
|
||||
stroke="#292D32" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
<path
|
||||
d="M14.0169 1.66669H5.98357C4.20857 1.66669 2.76691 3.11669 2.76691 4.88335V16.625C2.76691 18.125 3.84191 18.7584 5.15857 18.0334L9.22524 15.775C9.65857 15.5334 10.3586 15.5334 10.7836 15.775L14.8502 18.0334C16.1669 18.7667 17.2419 18.1334 17.2419 16.625V4.88335C17.2336 3.11669 15.7919 1.66669 14.0169 1.66669Z"
|
||||
stroke="#292D32" stroke-width="1.25" stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- bookmarked -->
|
||||
<div t-attf-id="bookmark{{data.dashboardsInfo[dashboard].id}}" t-on-click="updateBookmark"
|
||||
t-att-class="data.dashboardsInfo[dashboard].is_bookmarked ? '' : 'd-none'"
|
||||
t-att-data-dashboard-id="data.dashboardsInfo[dashboard].id"
|
||||
title="Bookmarked">
|
||||
<svg width="16" height="18" viewBox="0 0 16 18" fill="none"
|
||||
class="bookmarked cursor-pointer" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12.0165 0.666687H3.98318C2.20818 0.666687 0.766518 2.11669 0.766518 3.88335V15.625C0.766518 17.125 1.84152 17.7584 3.15818 17.0334L7.22485 14.775C7.65818 14.5334 8.35818 14.5334 8.78318 14.775L12.8499 17.0334C14.1665 17.7667 15.2415 17.1334 15.2415 15.625V3.88335C15.2332 2.11669 13.7915 0.666687 12.0165 0.666687ZM10.5082 7.12502C9.69985 7.41669 8.84985 7.56669 7.99985 7.56669C7.14985 7.56669 6.29985 7.41669 5.49152 7.12502C5.16652 7.00835 4.99985 6.65002 5.11652 6.32502C5.24152 6.00002 5.59985 5.83335 5.92485 5.95002C7.26652 6.43335 8.74152 6.43335 10.0832 5.95002C10.4082 5.83335 10.7665 6.00002 10.8832 6.32502C10.9999 6.65002 10.8332 7.00835 10.5082 7.12502Z"
|
||||
fill="#6789C6"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<button class="img-bg bookmark-capture ms-lg-2 ms-1 d-md-block d-none"
|
||||
t-att-data-dashboard-id="data.dashboardsInfo[dashboard].id" t-on-click="viewDashboard"
|
||||
title="To update the Dashboard image, go to dashboard and update through camera icon. We can also scroll in the dashboard and capture only the visible part.">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.75992 22H17.2399C19.9999 22 21.0999 20.31 21.2299 18.25L21.7499 9.99C21.8899 7.83 20.1699 6 17.9999 6C17.3899 6 16.8299 5.65 16.5499 5.11L15.8299 3.66C15.3699 2.75 14.1699 2 13.1499 2H10.8599C9.82992 2 8.62992 2.75 8.16992 3.66L7.44992 5.11C7.16992 5.65 6.60992 6 5.99992 6C3.82992 6 2.10992 7.83 2.24992 9.99L2.76992 18.25C2.88992 20.31 3.99992 22 6.75992 22Z" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10.5 8H13.5" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M12 18C13.79 18 15.25 16.54 15.25 14.75C15.25 12.96 13.79 11.5 12 11.5C10.21 11.5 8.75 12.96 8.75 14.75C8.75 16.54 10.21 18 12 18Z" stroke="" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
<a class="dash-link d-flex align-items-center justify-content-end" t-att-data-dashboard-id="data.dashboardsInfo[dashboard].id"
|
||||
t-on-click="viewDashboard" title="Click to view the Dashboard">
|
||||
View Dashboard
|
||||
<i class="fa fa-angle-right ms-1" aria-hidden="true"/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</t>
|
||||
@@ -0,0 +1,167 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Component, useState, onWillUpdateProps, onWillStart, onRendered } from "@odoo/owl";
|
||||
import { useBus } from "@web/core/utils/hooks";
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
|
||||
import { useGetTreeDescription } from "@web/core/tree_editor/utils";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import { treeFromDomain } from "@web/core/tree_editor/condition_tree";
|
||||
import { setObjectInCookie, getObjectFromCookie, eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
|
||||
|
||||
export class PreDefinedFilterDropdown extends Component{
|
||||
static template = "ks_dashboard_ninja.pre_defined_filter_dropdown"
|
||||
static props = {
|
||||
dropdown_items: { type: Array },
|
||||
onDropDownSelect: { type: Function },
|
||||
removeAllFilters: { type: Boolean, optional: true }
|
||||
};
|
||||
static components = { DropdownItem }
|
||||
setup(){
|
||||
this.state = useState({
|
||||
searchText: '',
|
||||
});
|
||||
}
|
||||
|
||||
get dropdown_items(){
|
||||
let searchedFilters = this.props.dropdown_items.filter(
|
||||
(item) => item.name.toLowerCase().includes(this.state.searchText.toLowerCase()) || item.type === 'separator')
|
||||
while(this.state.searchText && searchedFilters.length && searchedFilters[searchedFilters.length - 1].type === 'separator')
|
||||
searchedFilters.pop();
|
||||
while(this.state.searchText && searchedFilters.length && searchedFilters[0].type === 'separator') searchedFilters.shift();
|
||||
return searchedFilters;
|
||||
}
|
||||
}
|
||||
|
||||
export class PreDefinedFilter extends Component{
|
||||
static template = "ks_dashboard_ninja.pre_defined_filter"
|
||||
static props = {
|
||||
domain: { type: String, optional: true },
|
||||
update: { type: Function, optional: true },
|
||||
removeAllFilters: { type: Boolean, optional: true },
|
||||
remove: { type: Function, optional: true },
|
||||
options: { type: Object, optional: true }, // Tobe used for extra data provides to the component
|
||||
filters_data: { type: Object, optional: true },
|
||||
};
|
||||
static defaultProps = {
|
||||
|
||||
};
|
||||
static components = { Dropdown, PreDefinedFilterDropdown }
|
||||
|
||||
setup(){
|
||||
this.getDomainTreeDescription = useGetTreeDescription();
|
||||
this.defaultState = {"Select Filter": { model_name: 'Select Filter', groups: {}}}
|
||||
this.state = useState({
|
||||
activeFilterModels : {"Select Filter": { model_name: 'Select Filter', groups: {}}},
|
||||
});
|
||||
this.filter_id = 0
|
||||
this.filters_data = this.props.filters_data;
|
||||
|
||||
onWillStart( () => {
|
||||
this.setObjFromCookies();
|
||||
this.filters_data_list = Object.values(this.filters_data).sort(function(a, b){return a.sequence - b.sequence})
|
||||
})
|
||||
onWillUpdateProps((nextProps) => this.onPropsUpdated(nextProps))
|
||||
}
|
||||
|
||||
onPropsUpdated(nextProps){
|
||||
if(nextProps.removeAllFilters)
|
||||
this.clearFilters()
|
||||
}
|
||||
|
||||
setObjFromCookies(){
|
||||
let activeFilterModels_from_cky = getObjectFromCookie('PFilter' + this.props.options.ks_dashboard_id)
|
||||
let filters_data_from_cky = getObjectFromCookie('PFilterDataObj' + this.props.options.ks_dashboard_id)
|
||||
this.state.activeFilterModels = activeFilterModels_from_cky ?? {"Select Filter": { model_name: 'Select Filter', groups: {}}}
|
||||
if(!activeFilterModels_from_cky) this.setActiveFilters()
|
||||
this.filters_data = filters_data_from_cky ?? this.filters_data
|
||||
}
|
||||
|
||||
setActiveFilters(){
|
||||
Object.values(this.filters_data).forEach((filter)=> {
|
||||
if(filter.active){
|
||||
this.addFilter(filter.id, filter.categ, filter.model)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
clearFilters(){
|
||||
Object.values(this.filters_data).forEach( (filter) => { filter.active = false })
|
||||
this.state.activeFilterModels = {"Select Filter": { model_name: 'Select Filter', groups: {}}}
|
||||
eraseCookie('PFilter' + this.props.options.ks_dashboard_id)
|
||||
eraseCookie('PFilterDataObj' + this.props.options.ks_dashboard_id)
|
||||
}
|
||||
|
||||
onPredefinedFilterSelect(filterId, filterCategory, filterModel){
|
||||
let isAppliedFilter = this.state.activeFilterModels[filterModel]?.groups?.[filterCategory]?.filters?.[filterId]
|
||||
isAppliedFilter ? this.removeFilter(filterId, filterCategory, filterModel) : this.addFilter(filterId, filterCategory, filterModel)
|
||||
}
|
||||
|
||||
async removeFilter(filterId, filterCategory, filterModel){
|
||||
delete this.state.activeFilterModels[filterModel].groups[filterCategory].filters[filterId]
|
||||
this.filters_data[filterId].active = false
|
||||
await this.update(filterModel, filterCategory, filterId)
|
||||
this.pruneEmptyFilterGroups(this.state.activeFilterModels, filterModel, filterCategory)
|
||||
}
|
||||
|
||||
|
||||
addFilter(filterId, filterCategory, filterModel){
|
||||
if (this.state.activeFilterModels["Select Filter"]) {
|
||||
delete this.state.activeFilterModels["Select Filter"];
|
||||
}
|
||||
this.filters_data[filterId].active = true
|
||||
this.state.activeFilterModels[filterModel] ??= { model_name: this.filters_data[filterId].model_name, groups: {} };
|
||||
this.state.activeFilterModels[filterModel].groups[filterCategory] ??= {filters: {}, label: ''};
|
||||
|
||||
this.state.activeFilterModels[filterModel].groups[filterCategory].filters[filterId] = this.filters_data[filterId].domain;
|
||||
this.update(filterModel, filterCategory, filterId);
|
||||
}
|
||||
|
||||
makeLabelForModelGroup(model, group){
|
||||
let filters = this.state.activeFilterModels[model]?.groups?.[group]?.filters
|
||||
let labels = ''
|
||||
if(filters){
|
||||
labels = Object.keys(filters).map(filterId => this.filters_data[filterId].name).join(' or ');
|
||||
}
|
||||
return labels ? labels : 'Applied Filter'
|
||||
}
|
||||
|
||||
update(model, group , filter_id){
|
||||
eraseCookie('PFilter' + this.props.options.ks_dashboard_id)
|
||||
eraseCookie('PFilterDataObj' + this.props.options.ks_dashboard_id)
|
||||
let domainToUpdate = { [model]: { [group]: {}}}
|
||||
let domain = Domain.or([ ...Object.values(this.state.activeFilterModels[model].groups[group].filters) ]).toList();
|
||||
let label = this.makeLabelForModelGroup(model, group)
|
||||
domainToUpdate[model][group].domain = domain
|
||||
this.state.activeFilterModels[model].groups[group].label = label === '' ? this.filters_data[filter_id].name : label
|
||||
this.state.activeFilterModels[model].groups[group].domain = domain
|
||||
setObjectInCookie('PFilter' + this.props.options.ks_dashboard_id, this.state.activeFilterModels, 1)
|
||||
setObjectInCookie('PFilterDataObj' + this.props.options.ks_dashboard_id, this.filters_data, 1)
|
||||
this.props.update(domainToUpdate)
|
||||
}
|
||||
|
||||
pruneEmptyFilterGroups(filterData, modelName, groupName){
|
||||
if(!Object.values(this.state.activeFilterModels[modelName].groups[groupName]?.filters ?? {}).length)
|
||||
delete this.state.activeFilterModels[modelName].groups[groupName]
|
||||
if(!Object.values(this.state.activeFilterModels[modelName].groups).length)
|
||||
delete this.state.activeFilterModels[modelName]
|
||||
if(!Object.values(this.state.activeFilterModels).length)
|
||||
this.state.activeFilterModels = {"Select Filter": { model_name: 'Select Filter', groups: {}}}
|
||||
}
|
||||
|
||||
removeGroup(model, group){
|
||||
eraseCookie('PFilter' + this.props.options.ks_dashboard_id)
|
||||
eraseCookie('PFilterDataObj' + this.props.options.ks_dashboard_id)
|
||||
let model_group = this.state.activeFilterModels[model].groups[group]
|
||||
Object.keys(model_group.filters).forEach( (filter_id) => this.filters_data[filter_id].active = false)
|
||||
delete this.state.activeFilterModels[model].groups[group]
|
||||
this.pruneEmptyFilterGroups(this.state.activeFilterModels, model, group)
|
||||
setObjectInCookie('PFilter' + this.props.options.ks_dashboard_id, this.state.activeFilterModels, 1)
|
||||
setObjectInCookie('PFilterDataObj' + this.props.options.ks_dashboard_id, this.filters_data, 1)
|
||||
this.props.remove([model], [group])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
.ks_body_class .predefined-filters {
|
||||
.ks_dn_filter_applied_container {
|
||||
width: 100% !important;
|
||||
margin-left: 0 !important;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: $font-12;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 16.8px;
|
||||
text-align: left;
|
||||
color: $color-paragraph;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
button{
|
||||
border: none !important;
|
||||
padding: 0px !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
border: 0.81px solid $color-D1D5DB;
|
||||
border-radius: 6px !important;
|
||||
padding: 10px;
|
||||
min-height: 53px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-right: 21px;
|
||||
|
||||
.placeholder-custom {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18.52px;
|
||||
text-align: left;
|
||||
color: $color-placeholders;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.selcted-opt {
|
||||
// display: none;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
background-color: $color-bg-main;
|
||||
border-radius: 5px;
|
||||
padding: 4px 8px;
|
||||
width: fit-content;
|
||||
|
||||
|
||||
.opt-title {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18.52px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
text-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: 35%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
width: 30%;
|
||||
|
||||
li:not(:nth-child(1)) {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
li {
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.line-seperator-ks {
|
||||
border: 1px dashed $color-paragraph;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--Border-Color, #E5E7EB);
|
||||
border-radius: 4px;
|
||||
|
||||
& input[type="search"] {
|
||||
color: $color-black;
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
border: none;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-search-decoration,
|
||||
&::-webkit-search-cancel-button {
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
|
||||
color: $color-placeholders;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ks-dropdown-menu {
|
||||
|
||||
li:not(:nth-child(1)) {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
li {
|
||||
&:hover {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.line-seperator-ks {
|
||||
border: 1px dashed $color-paragraph;
|
||||
width: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--Border-Color, #E5E7EB);
|
||||
border-radius: 4px;
|
||||
|
||||
& input[type="search"] {
|
||||
color: $color-black;
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
border: none;
|
||||
width: 100%;
|
||||
|
||||
&::-webkit-search-decoration,
|
||||
&::-webkit-search-cancel-button {
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
|
||||
color: $color-placeholders;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<templates>
|
||||
<t t-name="ks_dashboard_ninja.pre_defined_filter" owl="1">
|
||||
<div class="predefined-filters">
|
||||
<t t-foreach="Object.keys(state.activeFilterModels)" t-as="model" t-key="model_index">
|
||||
<h4 class="">
|
||||
<t t-esc="state.activeFilterModels[model].model_name"/>
|
||||
</h4>
|
||||
<Dropdown menuClass="'ks-dropdown-menu'">
|
||||
<t t-set-slot="content">
|
||||
<div class="w-500">
|
||||
<PreDefinedFilterDropdown dropdown_items="filters_data_list" onDropDownSelect.bind="onPredefinedFilterSelect"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-call="ks_dn.model_facets_renderer">
|
||||
<t t-set="model_data" t-value="state.activeFilterModels[model]"/>
|
||||
<t t-set="ks_model" t-value="model"/>
|
||||
<t t-set="remove" t-value="removeGroup.bind(this)"/>
|
||||
</t>
|
||||
</Dropdown>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="ks_dashboard_ninja.pre_defined_filter_dropdown">
|
||||
<div class="search-input d-flex align-items-center">
|
||||
<div class="me-1">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.66634 14.4999C3.89967 14.4999 0.833008 11.4333 0.833008 7.66659C0.833008 3.89992 3.89967 0.833252 7.66634 0.833252C11.433 0.833252 14.4997 3.89992 14.4997 7.66659C14.4997 11.4333 11.433 14.4999 7.66634 14.4999ZM7.66634 1.83325C4.44634 1.83325 1.83301 4.45325 1.83301 7.66659C1.83301 10.8799 4.44634 13.4999 7.66634 13.4999C10.8863 13.4999 13.4997 10.8799 13.4997 7.66659C13.4997 4.45325 10.8863 1.83325 7.66634 1.83325Z"
|
||||
fill="#4b5563" stroke="none"/>
|
||||
<path d="M14.6666 15.1666C14.54 15.1666 14.4133 15.12 14.3133 15.02L12.98 13.6866C12.7866 13.4933 12.7866 13.1733 12.98 12.98C13.1733 12.7866 13.4933 12.7866 13.6866 12.98L15.02 14.3133C15.2133 14.5066 15.2133 14.8266 15.02 15.02C14.92 15.12 14.7933 15.1666 14.6666 15.1666Z"
|
||||
fill="#4b5563" stroke="none"/>
|
||||
</svg>
|
||||
</div>
|
||||
<input class="predefinedFilterSearchInput" placeholder="Search" type="search" href="#" t-model="state.searchText"/>
|
||||
</div>
|
||||
<t t-if="dropdown_items.length">
|
||||
<DropdownItem t-foreach="dropdown_items" t-as="dropdown_item" t-key="dropdown_item_index"
|
||||
class="{ 'global-active': dropdown_item.active, 'ks-disabled' : dropdown_item['type'] !== 'filter', 'ellipsis-content' : true}"
|
||||
onSelected="() => this.props.onDropDownSelect(dropdown_item.id, dropdown_item.categ, dropdown_item.model)">
|
||||
<span t-if="dropdown_item['type'] === 'filter'"><t t-esc="dropdown_item.name"/> ( <t t-esc="dropdown_item.model_name"/> )</span>
|
||||
<a t-else="" class="line-seperator-ks" href="#"/>
|
||||
</DropdownItem>
|
||||
</t>
|
||||
<t t-else="" t-call="no-data-view-without-button">
|
||||
<t t-set="header_text" t-value="'No Filter Available'"/>
|
||||
<t t-set="body_text" t-value="'No search results :) '"/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
52
addons/ks_dashboard_ninja/static/src/css/ks_ai_dash.css
Normal file
52
addons/ks_dashboard_ninja/static/src/css/ks_ai_dash.css
Normal file
@@ -0,0 +1,52 @@
|
||||
.ks_new_tag{
|
||||
position: absolute;
|
||||
font-size: 6px;
|
||||
background: #71639e;
|
||||
padding: 2px 6px;
|
||||
margin: 0px;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
margin-right: 6px;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: -4px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.ks_img_selected{
|
||||
background:#f2f2f2;
|
||||
}
|
||||
.ks_dashboard_kpi_dashboard .ks_img_display{
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-top: -7em
|
||||
}
|
||||
.ks_breadcrumb {
|
||||
padding: 5px 5px;
|
||||
}
|
||||
.ks_breadcrumb ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.ks_breadcrumb ul li {
|
||||
list-style: none;
|
||||
display: inline;
|
||||
text-transform: uppercase;
|
||||
font-size: 15px;
|
||||
}
|
||||
.ks_breadcrumb ul li+li:before {
|
||||
content: "\27E9";
|
||||
padding: 0 8px;
|
||||
color: #EA4335;
|
||||
}
|
||||
.ks_breadcrumb ul li:last-child:after {
|
||||
content: "";
|
||||
}
|
||||
.ks_breadcrumb ul li span {
|
||||
color: #4285F4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.ks_breadcrumb ul li span:hover {
|
||||
color: #202f47;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*rtl:begin:ignore*/
|
||||
/* Gridstack container custom css */
|
||||
.ks_o_graph_svg_container{
|
||||
height:calc(100% - 25px);
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.ksChartTitle{
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
display: block;
|
||||
height:calc(100% - 87%);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ks_o_graph_svg_container > svg.ks_svg_chart{
|
||||
height: calc(100% - 13%);
|
||||
width:100%;
|
||||
}
|
||||
|
||||
|
||||
/* Mobile view item no scroll fix */
|
||||
.grid-stack>.grid-stack-item>.ui-draggable-handle{
|
||||
touch-action: unset;
|
||||
}
|
||||
|
||||
|
||||
.grid-stack > .grid-stack-item > .grid-stack-item-content {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*rtl:end:ignore*/
|
||||
@@ -0,0 +1,75 @@
|
||||
.ks_dashboard_theme_input::before {
|
||||
content: '';
|
||||
position: relative;
|
||||
width: 25px;
|
||||
height: 20px;
|
||||
color: black;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.ks_color_white::before {
|
||||
background: #DAEAF6;
|
||||
color:black;
|
||||
}
|
||||
|
||||
.ks_color_white {
|
||||
border: 1px solid #bdbdbd
|
||||
}
|
||||
|
||||
.ks_color_blue::before {
|
||||
background: #FFF4DE;
|
||||
}
|
||||
.ks_color_red::before{
|
||||
background: #DCFCE7;
|
||||
}
|
||||
.ks_color_yellow::before{
|
||||
background: #F3E8FF;
|
||||
}
|
||||
.ks_color_green::before{
|
||||
background: #FFE2E5;
|
||||
}
|
||||
.ks_dashboard_theme_view_render{
|
||||
display: flex;
|
||||
}
|
||||
.ks_dashboard_theme_input:checked:before{
|
||||
content: '✔';
|
||||
}
|
||||
|
||||
.ks_dashboard_theme_input_container{
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ks_dashboard_top_settings .fa-cog{
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ks_dashboard_setting_container{
|
||||
padding: 5px 10px 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ks_dashboard_setting_container:hover{
|
||||
color: #333333;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_ninja_toggle_menu::after {
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Define here the CSS styles applied only to Safari browsers
|
||||
(any version and any device)
|
||||
*/
|
||||
.ks_dashboard_theme_input{
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/*Kpi CSS here*/
|
||||
.ks_kpi_target_grey {
|
||||
color: #777777;
|
||||
}
|
||||
747
addons/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss
Normal file
747
addons/ks_dashboard_ninja/static/src/css/ks_dashboard_ninja.scss
Normal file
@@ -0,0 +1,747 @@
|
||||
/* TO make whole page in white ks_dashboard_linkbackground(below grey screen start) : Hiding it for now */
|
||||
.ks_dashboard_form {
|
||||
min-height: 100%;
|
||||
}
|
||||
.ks_dashboard_ninja {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ks_dashboard_main_content {
|
||||
overflow: auto;
|
||||
// height: calc(100vh - 175px);
|
||||
max-height:100%;
|
||||
}
|
||||
.ks_dashboard_ninja_header{
|
||||
text-align : right;
|
||||
display: flex ;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
padding: 15px 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.ks_overflow {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ks_dashboard_header_name {
|
||||
margin: 0;
|
||||
max-width: 35%;
|
||||
}
|
||||
|
||||
.ks_header_container_div{
|
||||
float:none;
|
||||
background: #f2f2f2;
|
||||
margin-top: -20px;
|
||||
box-shadow: 2px 3px 6px #bbb5b5;
|
||||
}
|
||||
|
||||
|
||||
.ks_white_background{
|
||||
background-color : white;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_header_name {
|
||||
margin: 0;
|
||||
width: 80vmin;
|
||||
overflow-wrap: break-word;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ks_layout_color{
|
||||
background-color : #F9F9F9;
|
||||
margin-left : 35px;
|
||||
margin-top : 20px;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_item{
|
||||
padding: 8px 15px 20px 15px;
|
||||
/*border : 1px solid #CDD1D9;*/
|
||||
color : black;
|
||||
margin-top: 15px;
|
||||
border-radius : 6px;
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
overflow:visible !important;
|
||||
}
|
||||
.ks_dashboard_item:hover{
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
|
||||
}
|
||||
.ks_dashboard_item_header{
|
||||
text-align : right;
|
||||
min-height: 21px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_main_body{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_info{
|
||||
margin-left : 10px;
|
||||
width : 100%;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name{
|
||||
font-weight : bold;
|
||||
font-size: 23px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: none;
|
||||
min-height : 34px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_domain_count{
|
||||
font-size: 28px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon{
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon>img {
|
||||
width : 50px;
|
||||
height : 50px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header>button{
|
||||
visibility:hidden;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
.ks_dashboard_item_hover:hover .ks_dashboard_item_header_hover > button {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_menu_show > button{
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_hover>button:hover{
|
||||
transition: 0.2s linear;
|
||||
transform: scale(1.1);
|
||||
cursor: pointer !important;
|
||||
}
|
||||
|
||||
|
||||
.ks_item_not_click {
|
||||
cursor : move;
|
||||
}
|
||||
|
||||
|
||||
/* For Layout 2 Css */
|
||||
|
||||
.ks_dashboard_item_l2{
|
||||
display : flex;
|
||||
border-radius: 6px;
|
||||
margin-top : 15px;
|
||||
height: auto;
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.ks_dashboard_item_l2:hover{
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_icon_l2{
|
||||
padding : 20px;
|
||||
border-top-left-radius: 6px;
|
||||
border-bottom-left-radius: 6px;
|
||||
width: 100px;
|
||||
/* width: 36%; */
|
||||
padding-top: 35px;
|
||||
position:relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* font awesome resposive CSS for layou 2*/
|
||||
.ks_dashboard_icon_l2>span{
|
||||
font-size:5em;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_icon_l2>img {
|
||||
width: 60px;
|
||||
height : 60px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_main_body_l2{
|
||||
position : relative;
|
||||
width: calc(100% - 100px);
|
||||
border-top-right-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_l2{
|
||||
position : absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_l2>button{
|
||||
visibility:hidden;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_domain_count_l2{
|
||||
font-size: 35px;
|
||||
margin-left: 20px;
|
||||
margin-top: 25px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name_l2{
|
||||
font-weight: bold;
|
||||
font-size: medium;
|
||||
width: 80%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-left: 20px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* layout 3 */
|
||||
|
||||
.ks_dashboard_item_info_l3{
|
||||
padding-left: 10px;
|
||||
width: calc(100% - 60px);
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon_l3 {
|
||||
display: block;
|
||||
max-width: 70px;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon_l3 > img{
|
||||
width: 50px;
|
||||
height : 50px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name_l3{
|
||||
text-transform: none;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: right;
|
||||
font-size: medium;
|
||||
min-height : 24px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_domain_count_l3{
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
font-size: 35px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
/* Item Layout 4 */
|
||||
|
||||
.ks_dashboard_item_l4{
|
||||
display: flex;
|
||||
border-radius: 6px;
|
||||
margin-top: 15px;
|
||||
height: auto;
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.ks_dashboard_item_l4:hover{
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_icon_l4{
|
||||
padding : 20px;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
width : 100px;
|
||||
padding-top: 35px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon_l4>img {
|
||||
width: 60px;
|
||||
height : 60px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_main_body_l5{
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_l5{
|
||||
position : relative;
|
||||
margin-top: 15px;
|
||||
height: auto;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.ks_dashboard_item_l5:hover{
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
|
||||
}
|
||||
|
||||
.ks_dashboard_icon_l5{
|
||||
position : absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.ks_dashboard_icon_l5 > img{
|
||||
width: 20px !important;
|
||||
height: 20px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_main_body_l5{
|
||||
text-align: center;
|
||||
padding: 0 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_domain_count_l5{
|
||||
font-size: 50px;
|
||||
margin-left: 10px;
|
||||
margin-top: 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_name_l5{
|
||||
font-weight: bold;
|
||||
font-size: medium;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_l5{
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
.ks_dashboard_icon_l5 span
|
||||
{
|
||||
font-size: 20px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_l6{
|
||||
position : absolute;
|
||||
right: 25px;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_header_l6>button{
|
||||
visibility:hidden;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.ks_item_click{
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
|
||||
/* Dashboard filter related CSS */
|
||||
|
||||
.ks_action_btns{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.welcome_note{
|
||||
margin-top:10px;
|
||||
}
|
||||
.welcome_note h3{
|
||||
font-size: 26px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.welcome_note h3 span{
|
||||
color:#777777
|
||||
}
|
||||
|
||||
.welcome_note img {
|
||||
width: 30px;
|
||||
}
|
||||
@media (max-width: 1075px){
|
||||
.ks_dashboard_header_name {
|
||||
max-width: 100%;
|
||||
}
|
||||
.ks_dashboard_top_menu{
|
||||
|
||||
margin-top: 10px;
|
||||
}
|
||||
.ks_dashboard_top_menu.filter_design{
|
||||
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_header_sticky{
|
||||
position: -webkit-sticky; /* Safari */
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 7;
|
||||
}
|
||||
|
||||
.ks_dashboard_datepicker_z-index{
|
||||
z-index: 10 !important;
|
||||
}
|
||||
|
||||
|
||||
/* Date Filter Selection CSS*/
|
||||
#ks_date_filter_selection, #ks_dn_filter_selection{
|
||||
font-family: inherit;
|
||||
font-weight: bold;
|
||||
padding: 0px 8px 0px 8px;
|
||||
}
|
||||
|
||||
|
||||
.ks_date_filter_selection_input{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.ks_date_selection_box{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ks_date_input_fields{
|
||||
display: flex;
|
||||
// align-items: center;
|
||||
}
|
||||
|
||||
.flex_column_datetimerow .ks_date_input_fields{
|
||||
display: flex;
|
||||
width:350px;
|
||||
}
|
||||
.flex_column_datetimerow .ks_date_apply_clear_print{margin-left:5px}
|
||||
.flex_column_datetimerow #ks_btn_middle_child{margin:0 10px}
|
||||
|
||||
.ks_date_filter_selected > span, .ks_layout_selected > span{
|
||||
font-weight: bold;
|
||||
}
|
||||
.ks_layout_selected > span::before{
|
||||
font-family: FontAwesome;
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
content: "\f00c";
|
||||
}
|
||||
|
||||
ul.nav li.dropdown:hover ul.dropdown-menu{ display: block; }
|
||||
|
||||
.df_selection_text{
|
||||
display: block;
|
||||
padding: 3px 12px;
|
||||
font-weight: normal;
|
||||
line-height: 1.42857143;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
.ks_date_filter_dropdown{
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-color: #dee2e6;
|
||||
border-radius: 3px !important;
|
||||
}
|
||||
|
||||
.ks_btn_first_child_radius{
|
||||
border-bottom-right-radius: 0 !important;
|
||||
border-top-right-radius: 0 !important;
|
||||
border-bottom-left-radius: 3px !important;
|
||||
border-top-left-radius: 3px !important;
|
||||
}
|
||||
|
||||
#ks_btn_middle_child{
|
||||
border-radius: 0 !important;
|
||||
height: 100%;
|
||||
margin-right:10px;
|
||||
|
||||
}
|
||||
|
||||
#ks_btn_middle_child, #ks_btn_last_child {
|
||||
padding: inherit !important;
|
||||
}
|
||||
|
||||
.ks_btn_last_child{
|
||||
border-bottom-left-radius: 0 !important;
|
||||
border-top-left-radius: 0 !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ks_hide{
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ks_dashboard_item_action{
|
||||
background-color : inherit;
|
||||
}
|
||||
|
||||
|
||||
/* Dev Code here */
|
||||
.ks_dashboard_header{
|
||||
border-bottom: 1px solid #cccccc;
|
||||
}
|
||||
|
||||
.ks_select_none{
|
||||
-webkit-user-select: none; /* Chrome all / Safari all */
|
||||
-moz-user-select: none; /* Firefox all */
|
||||
-ms-user-select: none; /* IE 10+ */
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#ks_dashboard_title_input{
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
// #ks_dashboard_title{
|
||||
// padding-left: 1rem !important;
|
||||
// }
|
||||
|
||||
|
||||
.ks_preview_item {
|
||||
width: calc(50% - 30px);
|
||||
position: fixed;
|
||||
margin-left:53%;
|
||||
margin-top:3%;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_ninja_toggle_menu{
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.ks_dashboard_ninja_toggle_menu:before {
|
||||
font-family: FontAwesome;
|
||||
top:0;
|
||||
left:-5px;
|
||||
padding-right:10px;
|
||||
content: "\f013";
|
||||
font-size: 2em;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.ks_bg_white{
|
||||
background : white;
|
||||
}
|
||||
/*
|
||||
|
||||
.dropdown-submenu {
|
||||
position: relative;
|
||||
}
|
||||
*/
|
||||
|
||||
#ks_dashboard_title_label{
|
||||
color: #777777;
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
@media (max-width: 992px){
|
||||
.ks_dashboard_ninja_toggle_menu:before {
|
||||
content: "\f142";
|
||||
}
|
||||
|
||||
|
||||
#ks_dashboard_title_label{
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
#ks_dashboard_title{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.config_dropdown .dropdown-item{
|
||||
padding: 6px 20px;
|
||||
}
|
||||
.config_dropdown .dropdown-item .fa{
|
||||
opacity: 0.8;
|
||||
}
|
||||
.config_dropdown .dropdown-item-lable {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 5px 20px;
|
||||
clear: both;
|
||||
font-weight: bold;
|
||||
color: #495057;
|
||||
text-align: inherit;
|
||||
white-space: nowrap;
|
||||
margin: 3px 0px;
|
||||
}
|
||||
|
||||
.button-50 {
|
||||
appearance: button;
|
||||
background-color: #000;
|
||||
background-image: none;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
box-shadow: #fff 4px 4px 0 0,#000 4px 4px 0 1px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-family: ITCAvantGardeStd-Bk,Arial,sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
margin: 0 5px 10px 0;
|
||||
overflow: visible;
|
||||
padding: 4px 15px;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
touch-action: manipulation;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
vertical-align: middle;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.button-50:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-50:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button-50:active {
|
||||
box-shadow: rgba(0, 0, 0, .125) 0 3px 5px inset;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.button-50:not([disabled]):active {
|
||||
box-shadow: #fff 2px 2px 0 0, #000 2px 2px 0 1px;
|
||||
transform: translate(2px, 2px);
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.button-50 {
|
||||
padding: 4px 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 350px) {
|
||||
.ks_dashboard_item_button_container {
|
||||
flex-wrap: wrap;
|
||||
position: relative;
|
||||
z-index: 11
|
||||
}
|
||||
}
|
||||
// @media (max-width: 575px){
|
||||
// #ks_date_filter_selection{
|
||||
// display:none;
|
||||
// }
|
||||
// }
|
||||
@media (max-width: 575px){
|
||||
#play_button{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
@media (max-width: 575px){
|
||||
#print_dashboard{
|
||||
display:none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_quick_edit_action .ks_qe_form_view .o_field_translate.btn.btn-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ks_import_dashboard_d_none .btn.btn-secondary.fa.fa-download {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.ks_dashboard_ninja .o_view_nocontent {
|
||||
background-image: NONE !important;
|
||||
}
|
||||
.ks_user{
|
||||
position:relative !important;
|
||||
}
|
||||
.o_rtl .o_action_manager .ks_dashboard_main_content .ks_dashboard_item_content{
|
||||
direction:rtl !important;
|
||||
}
|
||||
.o_rtl .o_action_manager .ks_dashboard_main_content .grid-stack-item{
|
||||
direction:ltr !important;
|
||||
}
|
||||
|
||||
.ks_list_item_table{
|
||||
overflow: scroll !important;
|
||||
}
|
||||
|
||||
.ks_save_filter_to_fav {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ks_save_filter_to_fav .ks_fav_dropdown {
|
||||
top: 0;
|
||||
left: 100%;
|
||||
margin-top: -1px;
|
||||
}
|
||||
.ks_date_filters_menu_drop_down.ks_favourite_filters_menu_drop_down {
|
||||
overflow: visible !important;
|
||||
}
|
||||
.ks_o_add_favorite:hover .ks_dropdown_hover {
|
||||
display: block !important;
|
||||
}
|
||||
.ks_dropdown_hover {
|
||||
position: absolute;
|
||||
right: auto !important;
|
||||
left: 100% !important;
|
||||
}
|
||||
.ks_fav_checked{
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
transform: translate(-1.5em, 90%);
|
||||
font: .7em / 1em FontAwesome;
|
||||
color: #71639e;
|
||||
}
|
||||
.ks_fav_filters_checked > span{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ks_fav_filters_checked > span::before{
|
||||
font-family: FontAwesome;
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
content: "\f00c";
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
.ks_item_icon {
|
||||
width : 110px !important;
|
||||
}
|
||||
|
||||
.ks_item_icon>img {
|
||||
width : 50px;
|
||||
}
|
||||
|
||||
.ks_field_required{
|
||||
color : red;
|
||||
}
|
||||
|
||||
.ks_db_item_preview{
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.ks_not_click{
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ks_color_picker{
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.ks_color_opacity{
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
/* Icon Container in image widget render view*/
|
||||
.ks_image_widget_icon_container{
|
||||
background : transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ks_domain_content{
|
||||
overflow : auto;
|
||||
}
|
||||
|
||||
|
||||
/* Preview Footer Note */
|
||||
.ks_db_item_preview_footer_note{
|
||||
margin-top : 10px;
|
||||
}
|
||||
|
||||
|
||||
/*Container CSS*/
|
||||
|
||||
.ks_md_heading{
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
/* Dashboard Menu CSS*/
|
||||
.ks_dashboard_menu_container{
|
||||
padding: 10px;
|
||||
box-shadow: rgba(0, 0, 0, 0.25) 0px 14px 28px, rgba(0, 0, 0, 0.22) 0px 10px 10px;
|
||||
border-radius: 5px;
|
||||
max-width: 174px;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_menu_container > li{
|
||||
margin: 2px;
|
||||
display:flex;
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboard_menu_container > li > button, .ks_dashboard_layout_dropdown_container > li > button{
|
||||
margin-top : 5px;
|
||||
margin-left: 2px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
|
||||
#ks_add_item_selection,#ks_date_selector_container{
|
||||
box-shadow: rgba(0, 0, 0, 0.19) 0px 10px 20px, rgba(0, 0, 0, 0.23) 0px 6px 6px;
|
||||
}
|
||||
|
||||
#ks_dashboard_layout_edit{
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
/*background-color: #357bb7;*/
|
||||
/*border: 1px solid #357bb7;*/
|
||||
}
|
||||
|
||||
.ks_add_item_type_button{
|
||||
color:#fff;
|
||||
/*background-color: #357bb7;
|
||||
border: 1px solid #357bb7;*/
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* kpi css*/
|
||||
|
||||
.ks_dashboard_kpi_name_preview {
|
||||
font-size: 21px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ks_kpi_main_body {
|
||||
width: 100%;
|
||||
/*
|
||||
height: 67%;
|
||||
*/
|
||||
}
|
||||
|
||||
.ks_dashboard_kpi_count_preview {
|
||||
font-weight: bold;
|
||||
width:auto;
|
||||
font-size: x-large;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-transform: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ks_dashboard_kpi_arrow_preview {
|
||||
font-size: medium;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-left: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.ks_db_kpi_preview {
|
||||
width: 249px;
|
||||
}
|
||||
|
||||
.ks_dashboard_kpi {
|
||||
position : relative;
|
||||
margin-top: 15px;
|
||||
height: auto;
|
||||
border-radius: 6px;
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
}
|
||||
|
||||
.ks_target_previous {
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
padding: 0 15px 0px 15px;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.ks_progress progress {
|
||||
background-color: #000;
|
||||
border: 0;
|
||||
width: 80%;
|
||||
height: 5px;
|
||||
border-radius: 9px;
|
||||
}
|
||||
.ks_progress progress::-webkit-progress-bar {
|
||||
background-color: #000;
|
||||
border-radius: 9px;
|
||||
}
|
||||
.ks_progress progress::progress-value {
|
||||
background: #fff;
|
||||
border-radius: 9px;
|
||||
}
|
||||
.ks_progress progress::progress-bar {
|
||||
background: #fff;
|
||||
border-radius: 9px;
|
||||
}
|
||||
|
||||
.ks_list_view_layout_3 .ks_tr:nth-child(even),
|
||||
.ks_list_view_layout_1 .ks_tr:nth-child(even) {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.ks_list_view_layout_3 .ks_tr:hover,
|
||||
.ks_list_view_layout_1 .ks_tr:hover {
|
||||
color: #666666 !important;
|
||||
background-color: rgba(0, 0, 0, 0.26) !important;
|
||||
|
||||
}
|
||||
.ks_map_card_body{
|
||||
z-index:1;
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
.ks_dashboard_item {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Form pie chart no data */
|
||||
.ks_dn_graph_preview > .nv-noData > .ks_pie_chart_nocontent{
|
||||
padding: 100px 0 0 137px;
|
||||
min-height: 327px;
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_action {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.ks_group_width {
|
||||
width : 40% !important;
|
||||
}
|
||||
.ks_dashboard_quick_edit_action_popup {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_button_container > .ks_chart_inner_buttons > button {
|
||||
color:black;
|
||||
}
|
||||
/* Chart No Content Css */
|
||||
.ks_chart_nocontent_form {
|
||||
display: inherit !important;
|
||||
}
|
||||
|
||||
.ks_pie_chart_nocontent > .nv-noData {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-moz-transform: translateX(-50%) translateY(-50%);
|
||||
-webkit-transform: translateX(-50%) translateY(-50%);
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
font-size: 125%;
|
||||
}
|
||||
|
||||
.ks_pie_chart_nocontent > .ksChartTitle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
-moz-transform: translateX(-50%) translateY(-50%);
|
||||
-webkit-transform: translateX(-50%) translateY(-50%);
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
|
||||
|
||||
.ks_dashboarditem_id, .ks_dashboarditem_chart_container{
|
||||
overflow-x : visible !important;
|
||||
overflow-y : visible !important;
|
||||
}
|
||||
|
||||
.ks_previous_period .ks_dashboard_kpi{
|
||||
overflow-y : auto !important;
|
||||
}
|
||||
|
||||
.ks_dashboarditem_chart_container{
|
||||
background : white;
|
||||
}
|
||||
|
||||
/* Layout 6 exception case CSS */
|
||||
.ks_dashboard_item_header_l6{
|
||||
top: 5px !important;
|
||||
right: 10px;
|
||||
position:absolute;
|
||||
}
|
||||
|
||||
.ks_chart_json_export {
|
||||
padding-right: 10px !important;
|
||||
}
|
||||
|
||||
|
||||
.ks_chart_card_body{
|
||||
position: absolute;
|
||||
top: 65px;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
bottom: 8px;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------*/
|
||||
table#ksListViewTable {
|
||||
margin: 0 auto;
|
||||
border-collapse: collapse;
|
||||
font-family: Agenda-Light, sans-serif;
|
||||
/*font-weight: 100;*/
|
||||
/*background: #333;*/ /*color: #fff;*/
|
||||
text-rendering: optimizeLegibility;
|
||||
border-radius: 5px;
|
||||
width: -webkit-fill-available;
|
||||
}
|
||||
|
||||
|
||||
#ks_item_info {
|
||||
cursor:pointer;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.ks_chart_heading{
|
||||
/*width: 50%; */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_drill_up {
|
||||
min-width:110px;
|
||||
margin-left:50px
|
||||
}
|
||||
|
||||
.ks_list_view_heading{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 75%
|
||||
}
|
||||
|
||||
.ks_pager {
|
||||
min-width:98px;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_hover:hover .ks_dashboard_item_header_hover > .ks_chart_inner_buttons{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.ks_chart_inner_buttons{
|
||||
visibility: hidden;
|
||||
|
||||
}
|
||||
|
||||
.ks_chart_color_options, .ks_item_size_options{
|
||||
display: block;
|
||||
padding: 3px 10px;
|
||||
font-weight: normal;
|
||||
line-height: 1.42857143;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
margin-left: 24px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.ks_chart_color_options:hover, .ks_item_size_options:hover{
|
||||
color: #333333;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.ks_pro_print_hide{
|
||||
display:none !important;
|
||||
}
|
||||
|
||||
.ks_dashboard_item_menu_show > .ks_chart_inner_buttons{
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.ksMaxTableContent{
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
|
||||
.ks_list_view_container{
|
||||
background : white;
|
||||
}
|
||||
|
||||
.ks_chart_export_menu{
|
||||
padding: 6px 0 6px 0;
|
||||
}
|
||||
|
||||
.ks_chart_export_menu_header{
|
||||
font-weight: 600;
|
||||
padding: 0 14px 10px 14px;
|
||||
}
|
||||
|
||||
.ks_chart_export_menu_item{
|
||||
padding: 5px 14px 5px 14px;
|
||||
cursor : pointer;
|
||||
}
|
||||
|
||||
.ks_chart_image_export{
|
||||
line-height: 29.5px;
|
||||
padding-top: 7.5px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
.ks_chart_export_menu_item{
|
||||
color: #4c4c4c;;
|
||||
}
|
||||
|
||||
|
||||
.ks_chart_export_menu_item:hover{
|
||||
color: #4d4c4c;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
|
||||
.ks_chart_export_menu_item > i{
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ks_date_filters_menu_drop_down {
|
||||
max-height: 270px !important;
|
||||
overflow: auto !important;
|
||||
background-clip:unset;
|
||||
}
|
||||
/*.ks_ai_chart_body{
|
||||
width:49% !important;
|
||||
padding:0px !important
|
||||
}
|
||||
.ks_ai_explanation{
|
||||
width: 49%;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 60px;
|
||||
font-size: medium;
|
||||
font-family: serif;
|
||||
}
|
||||
.ks_speaker{
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
bottom: 20px;
|
||||
right: 30px;
|
||||
position: absolute;
|
||||
}
|
||||
.ks_speaker span.fa.fa-volume-up, .ks_speaker span.fa.fa-pause {
|
||||
border: 1px solid #71639e;
|
||||
background: #71639e;
|
||||
height: 35px;
|
||||
width: 36px;
|
||||
line-height: 35px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.ks_ai_dashboard_item {
|
||||
height: auto !important;
|
||||
}
|
||||
.ks_ai_explain_tile{
|
||||
background: #fff;
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||
margin: 0px 10px;
|
||||
width: -webkit-fill-available !important;
|
||||
border-radius: 5px;
|
||||
height:calc(100vh - 290px)!important;
|
||||
}
|
||||
.ks_ai_explain_tile .ks_ai_dashboard_item, .ks_ai_explain_tile .ks_ai_dashboard_item:hover{ box-shadow: none !important;}*/
|
||||
|
||||
.ks_ai_explain_body{
|
||||
display: flex;
|
||||
position:relative;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ks_ai_explain_body .ks_ai_dashboard_item{
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
.ks_ai_explain_body{
|
||||
height:100%;
|
||||
|
||||
}
|
||||
.ks_ai_explain_body .ks_ai_explanation{
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
padding:10px 20px;
|
||||
height: 400px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.ks_speaker span.fa.fa-volume-up, .ks_speaker span.fa.fa-pause {
|
||||
border: 1px solid #71639e;
|
||||
background: #71639e;
|
||||
height: 35px;
|
||||
width: 36px;
|
||||
line-height: 35px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.ks_speaker{
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
bottom: 20px;
|
||||
right: 30px;
|
||||
position: absolute;
|
||||
}
|
||||
.ks_ai_explain_body .ks_chart_card_body,.ks_ai_explain_body .ks_list_card_body{
|
||||
position:relative !important;
|
||||
top:inherit !important;
|
||||
bottom:inherit !important;
|
||||
right:inherit !important;
|
||||
left: inherit !important;
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
padding:inherit;
|
||||
}
|
||||
.ks_ai_explain_tile{
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
|
||||
background-color:white;
|
||||
width: 98% !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, 0) !important;
|
||||
}
|
||||
.ks_ai_dashboard_item {
|
||||
height: auto !important;
|
||||
}
|
||||
.ks_ai_explanation{
|
||||
font-size: medium;
|
||||
font-family: serif;
|
||||
}
|
||||
.ks_ai_explain_body .ks_list_card_body{
|
||||
overflow-y: auto;
|
||||
height: calc(100% - 75px);
|
||||
}
|
||||
.ks_list_view_container .ks_speaker{
|
||||
bottom: 65px !important
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
.ks-options-btn{
|
||||
border-radius: 25px;
|
||||
margin-top: 2%;
|
||||
visibility:collapse;
|
||||
}
|
||||
|
||||
.ks_dashboard_link{
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.ks_date_apply_clear_print,.ks_dashboard_top_menu{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex-wrap: wrap;
|
||||
margin-right:1px;
|
||||
}
|
||||
i.ks-options-plus {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
border-radius: 60px;
|
||||
background: #7c7bad;
|
||||
box-shadow: 0px 0px 2px #888;
|
||||
padding: 0.5em 0.6em;
|
||||
}
|
||||
|
||||
.apply-dashboard-date-filter{
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.clear-dashboard-date-filter{
|
||||
margin-left:5px;
|
||||
}
|
||||
|
||||
#ks_start_date_picker{
|
||||
height: 30px;
|
||||
width: 100px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 2px 4px;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
#ks_end_date_picker{
|
||||
height: 30px;
|
||||
width: 100px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
padding: 2px 4px;
|
||||
color: #1f1f1f;
|
||||
}
|
||||
|
||||
|
||||
.ui-datepicker .ui-datepicker-title {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.o_view_manager_content{
|
||||
font-family: arial;
|
||||
}
|
||||
.html2canvas-container {
|
||||
height: 4000px !important;
|
||||
}
|
||||
|
||||
.ks_dashboard_header_name {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.ks-dashboard-date-labels{
|
||||
font-weight: bold;
|
||||
margin-top: inherit;
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.ks_event_offer_list {
|
||||
pointer-events: none;
|
||||
color: #8080805e !important;
|
||||
}
|
||||
|
||||
.ks_event_offer_list:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
90
addons/ks_dashboard_ninja/static/src/css/ks_dn_filter.css
Normal file
90
addons/ks_dashboard_ninja/static/src/css/ks_dn_filter.css
Normal file
@@ -0,0 +1,90 @@
|
||||
.dropdown-menu.show.ks_dn_filter_dropdown_container {
|
||||
display: flex !important;
|
||||
}
|
||||
|
||||
.dn_dynamic_filter_selected > span{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dn_dynamic_filter_selected > span::before{
|
||||
font-family: FontAwesome;
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
content: "\f00c";
|
||||
}
|
||||
|
||||
.ks_dn_pre_filter_menu .df_selection_text {
|
||||
padding: 3px 4px;
|
||||
}
|
||||
|
||||
.ks_dn_pre_filter_menu {
|
||||
list-style: none;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
.ks_dn_pre_filter_menu > li {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.ks_dn_pre_filter_menu > li:hover {
|
||||
color: #333333;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.ks_dn_filter_dropdown_container > div {
|
||||
/*
|
||||
width: 225px;
|
||||
*/
|
||||
min-width :240px
|
||||
}
|
||||
|
||||
.ks_dn_filter_dropdown_container > div > div.o_generator_menu > span {
|
||||
margin-left: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ks_dn_filter_dropdown_container > div > div.o_generator_menu .ks_dn_custom_filter_input_container_section {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ks_custom_filter_section_delete {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
right: -15px;
|
||||
}
|
||||
|
||||
.o_or_filter {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -14px;
|
||||
bottom: auto;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.ks_dn_or_container {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.ks_dn_filter_applied_container {
|
||||
width: 500px !important;
|
||||
padding: 0px 10px;
|
||||
margin-left: 5px;
|
||||
border-width: 1px;
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
|
||||
.ks_dn_pre_model_text {
|
||||
|
||||
}
|
||||
@media screen and (max-width: 575px) {
|
||||
.ks_o_add_favorite.o_add_favorite {
|
||||
display: none;
|
||||
}
|
||||
.ks_dashboard_top_menu{
|
||||
margin:0 auto;
|
||||
}
|
||||
}
|
||||
21
addons/ks_dashboard_ninja/static/src/css/ks_flower_view.css
Normal file
21
addons/ks_dashboard_ninja/static/src/css/ks_flower_view.css
Normal file
@@ -0,0 +1,21 @@
|
||||
#ks_flower_chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
#text {
|
||||
margin-left:70px;
|
||||
margin-top:25px;
|
||||
}
|
||||
|
||||
.ks_flower_item_container{
|
||||
margin-right:25px;
|
||||
}
|
||||
|
||||
.flower_text{
|
||||
font:3rem Lucida Grande;
|
||||
align-items:center;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
19
addons/ks_dashboard_ninja/static/src/css/ks_funnel_view.css
Normal file
19
addons/ks_dashboard_ninja/static/src/css/ks_funnel_view.css
Normal file
@@ -0,0 +1,19 @@
|
||||
#chartdiv {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
#text {
|
||||
margin-left:50px;
|
||||
margin-top:25px;
|
||||
}
|
||||
|
||||
|
||||
.funnel_text , .graph_text{
|
||||
font:2rem Lucida Grande;
|
||||
align-items:center;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
.ks_icon_container_grid_view{
|
||||
width:100%;
|
||||
/* height:100%;*/
|
||||
}
|
||||
|
||||
.ks_icon_container_list{
|
||||
border: 1px solid transparent;
|
||||
position: relative;
|
||||
padding:2%;
|
||||
float:left;
|
||||
display:block;
|
||||
transition: 0.3s ease-in-out;
|
||||
width: 16.66%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ks_font {
|
||||
font-weight: bold;
|
||||
min-width: 129px
|
||||
}
|
||||
|
||||
|
||||
.ks_icon_container_list:hover {
|
||||
transform: scale(1.2);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ks_icon_selected{
|
||||
background: #f2f2f2;
|
||||
border-radius: 5px;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.ks_icon_selected img{
|
||||
transform: scale(0.7) !important;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ks_modal_icon_input_div{
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ks_modal_icon_input{
|
||||
padding: 6px;
|
||||
margin-top: 8px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.ks_fa_icon_search{
|
||||
float: right;
|
||||
padding: 6px 10px;
|
||||
margin-top: 8px;
|
||||
margin-right: 16px;
|
||||
background: #ddd;
|
||||
font-size: 17px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ks_search_modal_container{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.x-tree-icon-leaf, .x-tree-icon-text::before {
|
||||
font: normal normal normal 14px/1 "FontAwesome";
|
||||
display: inline-block;
|
||||
color: #5fa2dd;
|
||||
}
|
||||
@media (max-width: 475px){
|
||||
.ks_icon_container_list{
|
||||
width: 33.33%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Responsive CSS */
|
||||
@media (max-width: 1024px){
|
||||
.ks_dashboard_item_header_hover > button, .ks_dashboard_item_header_hover > .ks_chart_inner_buttons{
|
||||
visibility: visible !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.dropdown-max-height {
|
||||
max-height: 40vh;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
125
addons/ks_dashboard_ninja/static/src/css/ks_input_bar.css
Normal file
125
addons/ks_dashboard_ninja/static/src/css/ks_input_bar.css
Normal file
@@ -0,0 +1,125 @@
|
||||
.input_bar{
|
||||
border-radius: 8px;
|
||||
border: 0.5px solid #DADADA;
|
||||
background: #FF;
|
||||
color: #A8A8A8 !important;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
height: 40px;
|
||||
padding-left: 24px !important;
|
||||
}
|
||||
input#ks_selection_field:focus {
|
||||
border: 1px solid #797979;
|
||||
}
|
||||
.ks_input_custom{
|
||||
position: relative;
|
||||
}
|
||||
.ks_input_custom svg{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
top: 9px;
|
||||
}
|
||||
.search_style{
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
color: #444;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.search_style{
|
||||
overflow-y: scroll;
|
||||
max-height: calc(100vh - 400px);
|
||||
}
|
||||
.search_style::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
.search_style::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
.search_style::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
.search_style::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
.ks_response_container_list{
|
||||
border-bottom: 1px solid #d4d4d4;
|
||||
border-left: 1px solid transparent;
|
||||
padding: 17px 6px 18px 24px;
|
||||
background-color: #fff;
|
||||
color: #A8A8A8;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
}
|
||||
.ks_response_container_list:hover{
|
||||
color: #9C5789;
|
||||
border-left: 2px solid #9C5789;
|
||||
}
|
||||
.ks_response_container_list:hover svg path{
|
||||
stroke: #9C5789;
|
||||
}
|
||||
.ks_response_container_list:hover svg line{
|
||||
stroke: #9C5789;
|
||||
}
|
||||
|
||||
.ks_dashboard_option_category span.ks_dashboard_option{
|
||||
color: #9C5789;
|
||||
height: 21px;
|
||||
padding: 3px;
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: normal;
|
||||
}
|
||||
.ks_dashboard_option_category span{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
width: fit-content;
|
||||
font-size: 8px;
|
||||
background: #EEE;
|
||||
padding: 0px 10px;
|
||||
margin: 0px;
|
||||
border-radius: 4px;
|
||||
color: #888;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
margin-right: 6px;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.ks_dashboard_ai_chart_icons{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
width: fit-content;
|
||||
padding: 0px 10px;
|
||||
margin: 0px;
|
||||
font-weight: 600;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.ks_border_class{
|
||||
border-radius: 8px !important;
|
||||
border: 1px solid #DADADA !important;
|
||||
background: #FFF !important;
|
||||
margin-top: 8px !important;
|
||||
height: 40px !important;
|
||||
padding: 11px 11px 11px 24px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
.ks_border_class .ks_response{
|
||||
width: 100%;
|
||||
}
|
||||
21
addons/ks_dashboard_ninja/static/src/css/ks_map_view.css
Normal file
21
addons/ks_dashboard_ninja/static/src/css/ks_map_view.css
Normal file
@@ -0,0 +1,21 @@
|
||||
#map_chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
#text {
|
||||
margin-left:70px;
|
||||
margin-top:25px;
|
||||
}
|
||||
|
||||
.ks_map_item_container{
|
||||
margin-right:25px;
|
||||
}
|
||||
|
||||
.map_text{
|
||||
font:2rem Lucida Grande;
|
||||
align-items:center;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
22
addons/ks_dashboard_ninja/static/src/css/ks_radial_chart.css
Normal file
22
addons/ks_dashboard_ninja/static/src/css/ks_radial_chart.css
Normal file
@@ -0,0 +1,22 @@
|
||||
#radial_chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
#text {
|
||||
margin-left:70px;
|
||||
margin-top:25px;
|
||||
}
|
||||
|
||||
.ks_radial_item_container{
|
||||
margin-right:25px;
|
||||
}
|
||||
|
||||
.radial_text{
|
||||
font:3rem Lucida Grande;
|
||||
align-items:center;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
160
addons/ks_dashboard_ninja/static/src/css/ks_to_do_item.css
Normal file
160
addons/ks_dashboard_ninja/static/src/css/ks_to_do_item.css
Normal file
@@ -0,0 +1,160 @@
|
||||
.ks_list_view_container .nav-tabs-wrapper .nav-tabs-title{
|
||||
float: left;
|
||||
line-height: 33px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
.ks_list_view_container .nav-tabs-wrapper .nav-tabs{
|
||||
border: none;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.ks_list_view_container .nav-tabs-wrapper .nav-tabs .nav-item{
|
||||
margin-right: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.ks_list_view_container .nav-tabs-wrapper .nav-tabs .nav-link {
|
||||
border: none;
|
||||
background: none;
|
||||
color: #fff;
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ks_list_view_container .nav-tabs-wrapper .nav-tabs .nav-link.active{
|
||||
background-color: hsla(0,0%,100%,.2);
|
||||
transition: background-color .3s .2s;
|
||||
}
|
||||
.ks_list_view_container .card{
|
||||
border: none;
|
||||
/*box-shadow: 0 1px 4px 0 rgb(0 0 0 / 14%);*/
|
||||
}
|
||||
.ks_list_view_container .card-header{
|
||||
border: none;
|
||||
border-radius: 0px;
|
||||
background: none;
|
||||
padding: 0 12px 0px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ks_to_do_card_body{
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.ks_to_do_card_body .form-check {
|
||||
padding: 0;
|
||||
margin: -22px 0 0;
|
||||
}
|
||||
.form-check .form-check-label {
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
.ks_custom_check .form-check .form-check-input {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
z-index: -1;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ks_custom_check.form-check .form-check-label span {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -1px;
|
||||
top: -1px;
|
||||
transition-duration: .2s;
|
||||
}
|
||||
.ks_custom_check.form-check .form-check-sign {
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
float: left;
|
||||
padding-right: 0px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
||||
.form-check .form-check-sign:before {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
content: "";
|
||||
background-color: rgba(0,0,0,.84);
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 100%;
|
||||
z-index: 1;
|
||||
opacity: 0;
|
||||
margin: 0;
|
||||
top: 0;
|
||||
transform: scale3d(2.3,2.3,1);
|
||||
}
|
||||
|
||||
.ks_custom_check .form-check .form-check-input:checked~.form-check-sign .check {
|
||||
background: #9c27b0;
|
||||
}
|
||||
.form-check .form-check-sign .check {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid rgba(0,0,0,.54);
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.ks_custom_check .form-check .form-check-input:checked~.form-check-sign .check:before {
|
||||
color: #fff;
|
||||
box-shadow: 0 0 0 10px, 10px -10px 0 10px, 32px 0 0 20px, 0 32px 0 20px, -5px 5px 0 10px, 20px -12px 0 11px;
|
||||
}
|
||||
.form-check .form-check-sign .check:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
transform: rotate(45deg);
|
||||
display: block;
|
||||
margin-top: -3px;
|
||||
margin-left: 7px;
|
||||
width: 0;
|
||||
color: #fff;
|
||||
height: 0;
|
||||
box-shadow: 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, 0 0 0 0, inset 0 0 0 0;
|
||||
}
|
||||
|
||||
.ks_to_do_card_body .ks_description{
|
||||
text-align: left;
|
||||
}
|
||||
.ks_to_do_card_body .td-actions{
|
||||
width: 70px;
|
||||
}
|
||||
.ks_to_do_card_body .ks_custom_check{
|
||||
width: 30px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ks_to_do_card_body .ks_edit_content{
|
||||
background: none;
|
||||
border:none;
|
||||
}
|
||||
|
||||
.ks_card_header{
|
||||
}
|
||||
.ks_card_header .nav-tabs-wrapper{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.ks_card_header .nav-tabs-wrapper .header_add_btn{
|
||||
background: none;
|
||||
margin-left: auto;
|
||||
border: none;
|
||||
background: none;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ks_do_item_line_through {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
150
addons/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css
Normal file
150
addons/ks_dashboard_ninja/static/src/css/ks_toggle_icon.css
Normal file
@@ -0,0 +1,150 @@
|
||||
.ks_toggle_icon_input{
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ks_select_dashboard_item_toggle{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ks_select_icon_div{
|
||||
margin-right : 45px;
|
||||
}
|
||||
|
||||
|
||||
/*New Quick Edit View*/
|
||||
.ks_dashboard_item_button_container{
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ks_dashboard_quick_edit_action > button{
|
||||
position: absolute;
|
||||
right: -30px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.ks_dashboard_quick_edit_action{
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
|
||||
/*UI CHANGES*/
|
||||
|
||||
.ks_qe_footer_span{
|
||||
display: block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
-webkit-transform: rotate(-135deg) translateZ(0);
|
||||
transform: rotate(-135deg) translateZ(0);
|
||||
outline: 1px solid transparent;
|
||||
background-color: white;
|
||||
border-top: 1px solid #c7c7c7;
|
||||
border-right: 1px solid #c7c7c7;
|
||||
position: absolute;
|
||||
left: -9px;
|
||||
top: 22px;
|
||||
}
|
||||
|
||||
|
||||
.ks_qe_dropdown_menu{
|
||||
max-width: 280px;
|
||||
box-shadow: 3px 7px 12px 1px rgba(0, 0, 0, 0.32);
|
||||
}
|
||||
|
||||
.ks_item_field_info{
|
||||
/*width: 230px;*/
|
||||
max-height: 225px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.ks_quick_edit_footer{
|
||||
padding-top: 1rem !important;
|
||||
padding-bottom: 0.7rem !important;
|
||||
border-top: 1px solid #dcdada;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ks_qe_form_view{
|
||||
padding-bottom: 0px !important;
|
||||
padding-top: 0px !important;
|
||||
}
|
||||
|
||||
.ks_qe_form_view > .ks_qe_form_view_group{
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* width */
|
||||
.ks_item_field_info::-webkit-scrollbar,
|
||||
.ks_dashboard_custom_srollbar::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
.ks_item_field_info::-webkit-scrollbar-track,
|
||||
.ks_dashboard_custom_srollbar::-webkit-scrollbar-track,
|
||||
{
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
.ks_item_field_info::-webkit-scrollbar-thumb,
|
||||
.ks_dashboard_custom_srollbar::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
}
|
||||
|
||||
/* Handle on hover */
|
||||
.ks_item_field_info::-webkit-scrollbar-thumb:hover,
|
||||
.ks_dashboard_custom_srollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.ks_quick_edit_footer > .ks_discard {
|
||||
border-color: #dee2e6;
|
||||
}
|
||||
|
||||
|
||||
@media(min-width: 768px){
|
||||
.ks_dashboard_item_hover .ks_dashboard_item_header_hover > .dn-setting-panel{
|
||||
visibility: hidden;
|
||||
}
|
||||
.ks_dashboard_item_hover:hover .ks_dashboard_item_header_hover > .dn-setting-panel{
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
}
|
||||
@media(max-width: 768px){
|
||||
.ks_dashboard_header {
|
||||
height: 145px !important;
|
||||
}
|
||||
.ks_dashboard_top_menu{
|
||||
|
||||
margin-top: -6px;
|
||||
|
||||
}
|
||||
}
|
||||
@media(max-width: 767.8px){
|
||||
.ks_dashboard_item_name{
|
||||
font-size: 16px;
|
||||
}
|
||||
.ks_dashboard_item_hover .ks_dashboard_item_header_hover > .dn-setting-panel button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
a.dropdown-item.ks_dashboard_item_chart_info.d-none {
|
||||
display: block !important;
|
||||
}
|
||||
.ks_dashboard_item_fa_con {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ks_chart_inner_min_width {
|
||||
min-width: 10rem;
|
||||
}
|
||||
.ks_info_display {
|
||||
display: block !important;
|
||||
}
|
||||
1011
addons/ks_dashboard_ninja/static/src/css/style.css
Normal file
1011
addons/ks_dashboard_ninja/static/src/css/style.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { KsItemButton } from '@ks_dashboard_ninja/components/chart_buttons/chart_buttons';
|
||||
import { CustomDialog } from '@ks_dashboard_ninja/components/charts_insights/chart_insights';
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
patch(KsItemButton.prototype,{
|
||||
_onButtonClick() {
|
||||
let dashboard_data = this.env.getDashboardDataAsObj([])
|
||||
let item = dashboard_data.ks_item_data[this.id]
|
||||
let openDialog = () => {
|
||||
this.env.services.dialog.add(CustomDialog,{
|
||||
ks_dashboard_manager: item.ks_dashboard_manager,
|
||||
ks_dashboard_items: dashboard_data.ks_dashboard_items_ids,
|
||||
ks_dashboard_data: dashboard_data,
|
||||
item: item,
|
||||
ks_dashboard_item_type: item.ks_dashboard_item_type,
|
||||
dashboard_data: dashboard_data,
|
||||
ksdatefilter: 'none',
|
||||
ks_speak: () => {},
|
||||
ksDateFilterSelection: '',
|
||||
pre_defined_filter: {},
|
||||
custom_filter: {},
|
||||
title:"Hello",
|
||||
hideButtons: 0,
|
||||
current_graph: this.__owl__.parent.component,
|
||||
getDomainParams: this.env.ksGetParamsForItemFetch,
|
||||
getDashboardContext: this.env.getContext,
|
||||
});
|
||||
}
|
||||
|
||||
let self = this
|
||||
if(!item.ks_ai_analysis){
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.arti_int/ks_generate_analysis",{
|
||||
model: 'ks_dashboard_ninja.arti_int',
|
||||
method: 'ks_generate_analysis',
|
||||
args: [[item],[],item.ks_dashboard_id],
|
||||
kwargs:{context: {explain_items_with_ai: true}},
|
||||
}).then((result) => {
|
||||
if (result){
|
||||
rpc("/web/dataset/call_kw/ks_dashboard_ninja.arti_int/get_ai_explain",{
|
||||
model: 'ks_dashboard_ninja.arti_int',
|
||||
method: 'get_ai_explain',
|
||||
args: [item.id, item.id],
|
||||
kwargs:{ },
|
||||
}).then(function(res) {
|
||||
item.ks_ai_analysis = res
|
||||
openDialog();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
openDialog();
|
||||
}
|
||||
}
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
38
addons/ks_dashboard_ninja/static/src/js/cookies.js
Normal file
38
addons/ks_dashboard_ninja/static/src/js/cookies.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { isMobileOS } from "@web/core/browser/feature_detection";
|
||||
|
||||
const setCookie = (name, value, days) => {
|
||||
var expires = "";
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days*24*60*60*1000));
|
||||
expires = "; expires=" + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + expires + "; path=/";
|
||||
}
|
||||
|
||||
export const setObjectInCookie = (name, object, days) => {
|
||||
var jsonString = JSON.stringify(object);
|
||||
!isMobileOS() ? setCookie(name, jsonString, days) : '';
|
||||
}
|
||||
|
||||
const getCookie = (name) => {
|
||||
var nameEQ = name + "=";
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export const getObjectFromCookie = (name) => {
|
||||
var jsonString = getCookie(name);
|
||||
return !isMobileOS() && jsonString ? JSON.parse(jsonString) : null;
|
||||
}
|
||||
export const eraseCookie = (name) => {
|
||||
document.cookie = name + '=; Max-Age=-99999999; path=/';
|
||||
}
|
||||
|
||||
96
addons/ks_dashboard_ninja/static/src/js/domainfix.js
Normal file
96
addons/ks_dashboard_ninja/static/src/js/domainfix.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import {RecordAutocomplete} from "@web/core/record_selectors/record_autocomplete";
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Domain } from "@web/core/domain";
|
||||
import {getFormat,DomainSelectorSingleAutocomplete,DomainSelectorAutocomplete} from "@web/core/tree_editor/tree_editor_autocomplete"
|
||||
|
||||
const SEARCH_LIMIT = 7;
|
||||
const SEARCH_MORE_LIMIT = 320;
|
||||
|
||||
//Patching to add uid and mycompany in dropdown
|
||||
patch(RecordAutocomplete.prototype,{
|
||||
async loadOptionsSource(name) {
|
||||
if (this.env.services.action.currentController?.action?.tag === "ks_dashboard_ninja"){
|
||||
if (this.lastProm) {
|
||||
this.lastProm.abort(false);
|
||||
}
|
||||
this.lastProm = this.search(name, SEARCH_LIMIT + 1);
|
||||
const nameGets = (await this.lastProm).map(([id, label]) => ([id, label ? label.split("\n")[0] : _t("Unnamed")]));
|
||||
this.addNames(nameGets);
|
||||
const options = nameGets.map(([value, label]) => ({value, label}));
|
||||
if (this.props.resModel !== 'res.company' && !this.props.ks_res_ids?.includes("%UID")){
|
||||
options.push({value:"%UID",label:"%UID"})
|
||||
}
|
||||
if (this.props.resModel === 'res.company' && !this.props.ks_res_ids?.includes("%MYCOMPANY")){
|
||||
options.push({value:"%MYCOMPANY",label:"%MYCOMPANY"})
|
||||
}
|
||||
if (SEARCH_LIMIT < nameGets.length) {
|
||||
options.push({
|
||||
label: _t("Search More..."),
|
||||
action: this.onSearchMore.bind(this, name),
|
||||
classList: "o_m2o_dropdown_option",
|
||||
});
|
||||
}
|
||||
if (options.length === 0) {
|
||||
options.push({ label: _t("(no result)"), unselectable: true });
|
||||
}
|
||||
return options;
|
||||
}else{
|
||||
return await super.loadOptionsSource(...arguments);
|
||||
}
|
||||
},
|
||||
});
|
||||
RecordAutocomplete.props = {...RecordAutocomplete.props,ks_res_ids:{ type: Array,optional:true}};
|
||||
|
||||
//Patching to remove invalid domain uid and mycompany from domain-modal
|
||||
patch(DomainSelectorAutocomplete.prototype,{
|
||||
getTags(props, displayNames) {
|
||||
if (this.env.services.action.currentController?.action?.tag === "ks_dashboard_ninja"){
|
||||
return props.resIds.map((val, index) => {
|
||||
const { text, colorIndex } = ksgetFormat(val, displayNames);
|
||||
return {
|
||||
text,
|
||||
colorIndex,
|
||||
onDelete: () => {
|
||||
this.props.update([
|
||||
...this.props.resIds.slice(0, index),
|
||||
...this.props.resIds.slice(index + 1),
|
||||
]);
|
||||
},
|
||||
};
|
||||
});
|
||||
}else{
|
||||
return super.getTags(...arguments)
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
patch(DomainSelectorSingleAutocomplete.prototype,{
|
||||
getDisplayName(props = this.props, displayNames) {
|
||||
if (this.env.services.action.currentController?.action?.tag === "ks_dashboard_ninja"){
|
||||
const { resId } = props;
|
||||
if (resId === false) {
|
||||
return "";
|
||||
}
|
||||
const { text } = ksgetFormat(resId, displayNames);
|
||||
return text;
|
||||
}else{
|
||||
return super.getDisplayName(...arguments)
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
export const ksgetFormat = (val, displayNames) => {
|
||||
let text;
|
||||
let colorIndex;
|
||||
if (val === '%UID'){
|
||||
return{text:'%UID',colorIndex:0}
|
||||
}else if (val === "%MYCOMPANY"){
|
||||
return{text:'%MYCOMPANY',colorIndex:0}
|
||||
}else{
|
||||
return getFormat(val,displayNames)
|
||||
}
|
||||
};
|
||||
492
addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js
Normal file
492
addons/ks_dashboard_ninja/static/src/js/ks_ai_dash_action.js
Normal file
@@ -0,0 +1,492 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { _t } from "@web/core/l10n/translation";
|
||||
import { Component, onWillStart, useState ,onMounted, onWillRender, useRef, onWillPatch } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { renderToString,renderToElement } from "@web/core/utils/render";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
//import { useSetupAction } from "@web/webclient/actions/action_hook";
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { browser } from '@web/core/browser/browser';
|
||||
import { session } from "@web/session";
|
||||
import { BlockUI } from "@web/core/ui/block_ui";
|
||||
import { WebClient } from "@web/webclient/webclient";
|
||||
import {FormViewDialog} from "@web/views/view_dialogs/form_view_dialog";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
//import { patch } from "@web/core/utils/patch";
|
||||
import { isBrowserChrome, isMobileOS } from "@web/core/browser/feature_detection";
|
||||
import { loadBundle } from '@web/core/assets';
|
||||
import { globalfunction } from '@ks_dashboard_ninja/js/ks_global_functions'
|
||||
import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_tile_view/ks_dashboard_tile';
|
||||
//import { Ksdashboardlistview } from '@ks_dashboard_ninja/components/ks_dashboard_list_view/ks_dashboard_list';
|
||||
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do';
|
||||
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
|
||||
import { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { rpc } from "@web/core/network/rpc";
|
||||
import { user } from "@web/core/user";
|
||||
|
||||
|
||||
export class KsAIDashboardNinja extends Component {
|
||||
|
||||
setup() {
|
||||
this.actionService = useService("action");
|
||||
this.dialogService = useService("dialog");
|
||||
this.notification = useService("notification");
|
||||
this._rpc = rpc
|
||||
this.dialogService = useService("dialog");
|
||||
this.header = useRef("ks_dashboard_header");
|
||||
this.footer = useRef("ks_dashboard_footer");
|
||||
this.main_body = useRef("ks_main_body");
|
||||
this.grid_stack = useRef("ks_grid_stack")
|
||||
this.reload_menu_option = {
|
||||
reload:this.props.action.context.ks_reload_menu,
|
||||
menu_id: this.props.action.context.ks_menu_id
|
||||
};
|
||||
this.generate_dialog = false;
|
||||
this.generate_dialog = this.props.action.context.generate_dialog ? true : false;
|
||||
this.ks_ai_dash_id = this.props.action.context['ks_dash_id'];
|
||||
this.ks_ai_dash_name = this.props.action.context['ks_dash_name'];
|
||||
this.ks_ai_del_id =this.props.action.context['ks_delete_dash_id'];
|
||||
this.ks_mode = 'active';
|
||||
this.action_manager = parent;
|
||||
// this.controllerID = params.controllerID;
|
||||
this.name = "ks_dashboard";
|
||||
this.ksIsDashboardManager = false;
|
||||
this.ksDashboardEditMode = false;
|
||||
this.ksNewDashboardName = false;
|
||||
this.file_type_magic_word = {
|
||||
'/': 'jpg',
|
||||
'R': 'gif',
|
||||
'i': 'png',
|
||||
'P': 'svg+xml',
|
||||
};
|
||||
this.ksAllowItemClick = true;
|
||||
|
||||
//Dn Filters Iitialization
|
||||
|
||||
this.date_format = localization.dateFormat
|
||||
// this.date_format = this.date_format.replace(/\bYY\b/g, "YYYY");
|
||||
this.datetime_format = localization.dateTimeFormat
|
||||
// this.is_dateFilter_rendered = false;
|
||||
this.ks_date_filter_data;
|
||||
|
||||
// Adding date filter selection options in dictionary format : {'id':{'days':1,'text':"Text to show"}}
|
||||
this.ks_date_filter_selections = {
|
||||
'l_none': _t('Date Filter'),
|
||||
'l_day': _t('Today'),
|
||||
't_week': _t('This Week'),
|
||||
'td_week': _t('Week To Date'),
|
||||
't_month': _t('This Month'),
|
||||
'td_month': _t('Month to Date'),
|
||||
't_quarter': _t('This Quarter'),
|
||||
'td_quarter': _t('Quarter to Date'),
|
||||
't_year': _t('This Year'),
|
||||
'td_year': _t('Year to Date'),
|
||||
'n_day': _t('Next Day'),
|
||||
'n_week': _t('Next Week'),
|
||||
'n_month': _t('Next Month'),
|
||||
'n_quarter': _t('Next Quarter'),
|
||||
'n_year': _t('Next Year'),
|
||||
'ls_day': _t('Last Day'),
|
||||
'ls_week': _t('Last Week'),
|
||||
'ls_month': _t('Last Month'),
|
||||
'ls_quarter': _t('Last Quarter'),
|
||||
'ls_year': _t('Last Year'),
|
||||
'l_week': _t('Last 7 days'),
|
||||
'l_month': _t('Last 30 days'),
|
||||
'l_quarter': _t('Last 90 days'),
|
||||
'l_year': _t('Last 365 days'),
|
||||
'ls_past_until_now': _t('Past Till Now'),
|
||||
'ls_pastwithout_now': _t('Past Excluding Today'),
|
||||
'n_future_starting_now': _t('Future Starting Now'),
|
||||
'n_futurestarting_tomorrow': _t('Future Starting Tomorrow'),
|
||||
'l_custom': _t('Custom Filter'),
|
||||
};
|
||||
// To make sure date filter show date in specific order.
|
||||
this.ks_date_filter_selection_order = ['l_day', 't_week', 't_month', 't_quarter','t_year',
|
||||
'td_week','td_month','td_quarter', 'td_year','n_day','n_week', 'n_month', 'n_quarter', 'n_year',
|
||||
'ls_day','ls_week', 'ls_month', 'ls_quarter', 'ls_year', 'l_week', 'l_month', 'l_quarter', 'l_year',
|
||||
'ls_past_until_now', 'ls_pastwithout_now','n_future_starting_now', 'n_futurestarting_tomorrow',
|
||||
'l_custom'
|
||||
];
|
||||
|
||||
this.ks_dashboard_id = this.props.action.params.ks_dashboard_id;
|
||||
|
||||
this.gridstack_options = {
|
||||
staticGrid:true,
|
||||
float: false,
|
||||
cellHeight: 80,
|
||||
styleInHead : true,
|
||||
// disableOneColumnMode: true,
|
||||
};
|
||||
this.ksSelectedgraphid = [];
|
||||
if (isMobileOS()) {
|
||||
this.gridstack_options.disableOneColumnMode = false
|
||||
}
|
||||
this.gridstackConfig = {};
|
||||
this.grid = true;
|
||||
this.chartMeasure = {};
|
||||
this.chart_container = {};
|
||||
this.list_container = {};
|
||||
this.state = useState({
|
||||
ks_dashboard_name: '',
|
||||
ks_multi_layout: false,
|
||||
ks_dash_name: '',
|
||||
ks_dashboard_manager :false,
|
||||
date_selection_data: {},
|
||||
date_selection_order :[],
|
||||
ks_show_create_layout_option : true,
|
||||
ks_show_layout :false,
|
||||
ks_selected_board_id:false,
|
||||
ks_child_boards:false,
|
||||
ks_dashboard_data:{},
|
||||
ks_dn_pre_defined_filters:[],
|
||||
ks_dashboard_item_length:0,
|
||||
ks_dashboard_items:[],
|
||||
ksDateFilterSelection:'none',
|
||||
pre_defined_filter:{},
|
||||
custom_filter:{}
|
||||
})
|
||||
this.ksChartColorOptions = ['default', 'cool', 'warm', 'neon'];
|
||||
// this.ksUpdateDashboardItem = this.ksUpdateDashboardItem.bind(this);
|
||||
this.ksDateFilterSelection = false;
|
||||
this.ksDateFilterStartDate = false;
|
||||
this.ksDateFilterEndDate = false;
|
||||
this.ksUpdateDashboard = {};
|
||||
$("head").append('<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">');
|
||||
if(this.props.action.context.ks_reload_menu){
|
||||
this.trigger_up('reload_menu_data', { keep_open: true, scroll_to_bottom: true});
|
||||
}
|
||||
var context = {
|
||||
ksDateFilterSelection: self.ksDateFilterSelection,
|
||||
ksDateFilterStartDate: self.ksDateFilterStartDate,
|
||||
ksDateFilterEndDate: self.ksDateFilterEndDate,
|
||||
}
|
||||
this.dn_state = {}
|
||||
this.dn_state['user_context']=context
|
||||
onWillStart(this.willStart);
|
||||
onWillRender(this.dashboard_mount);
|
||||
onMounted(() => {
|
||||
this.grid_initiate();
|
||||
});
|
||||
}
|
||||
|
||||
willStart(){
|
||||
var self = this;
|
||||
var def;
|
||||
if (this.reload_menu_option.reload && this.reload_menu_option.menu_id) {
|
||||
def = this.getParent().actionService.ksDnReloadMenu(this.reload_menu_option.menu_id);
|
||||
}
|
||||
return $.when(def, loadBundle("ks_dashboard_ninja.ks_dashboard_lib")).then(function() {
|
||||
return self.ks_fetch_data().then(function(){
|
||||
return self.ks_fetch_items_data()
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
grid_initiate(){
|
||||
$(".o_dialog .o_inactive_modal").remove()
|
||||
if (!this.generate_dialog) {
|
||||
var self=this;
|
||||
var $gridstackContainer = $(this.grid_stack.el);
|
||||
if($gridstackContainer.length){
|
||||
this.grid = GridStack.init(this.gridstack_options,$gridstackContainer[0]);
|
||||
if(this.ks_dashboard_data.ks_gridstack_config){
|
||||
this.gridstackConfig = JSON.parse(this.ks_dashboard_data.ks_gridstack_config);
|
||||
}
|
||||
for (var i = 0; i < this.state.ks_dashboard_items.length; i++) {
|
||||
var graphs = ['ks_scatter_chart','ks_bar_chart', 'ks_horizontalBar_chart', 'ks_line_chart', 'ks_area_chart', 'ks_doughnut_chart','ks_polarArea_chart','ks_pie_chart','ks_flower_view', 'ks_radar_view','ks_radialBar_chart','ks_map_view','ks_funnel_chart','ks_bullet_chart', 'ks_to_do', 'ks_list_view']
|
||||
var $ks_preview = $('#' + self.state.ks_dashboard_items[i].id)
|
||||
if ($ks_preview.length) {
|
||||
if (self.state.ks_dashboard_items[i].id in self.gridstackConfig) {
|
||||
self.grid.addWidget($ks_preview[0], {x:self.gridstackConfig[self.state.ks_dashboard_items[i].id].x, y:self.gridstackConfig[self.state.ks_dashboard_items[i].id].y, w:self.gridstackConfig[self.state.ks_dashboard_items[i].id].w, h: self.gridstackConfig[self.state.ks_dashboard_items[i].id].h, autoPosition:true, minW:2, maxW:null, minH:2, maxH:null, id:self.state.ks_dashboard_items[i].id});
|
||||
} else if ( graphs.includes (self.state.ks_dashboard_items[i].ks_dashboard_item_type)) {
|
||||
self.grid.addWidget($ks_preview[0], {x:0, y:0, w:5, h:5,autoPosition:true,minW:4,maxW:null,minH:3,maxH:null, id :self.state.ks_dashboard_items[i].id});
|
||||
}else{
|
||||
self.grid.addWidget($ks_preview[0], {x:0, y:0, w:3, h:2,autoPosition:true,minW:2,maxW:null,minH:2,maxH:2,id:self.state.ks_dashboard_items[i].id});
|
||||
}
|
||||
}
|
||||
}
|
||||
this.grid.setStatic(true);
|
||||
}
|
||||
}
|
||||
// Events //
|
||||
const ks_element = this.main_body.el;
|
||||
Object.values(ks_element.querySelectorAll(".ks_dashboarditem_chart_container")).map((item) => { item.addEventListener('click', this.onkschartcontainerclick.bind(this))})
|
||||
// Object.values(ks_element.querySelectorAll(".ks_list_view_container")).map((item) => { item.addEventListener('click', this.onkschartcontainerclick.bind(this))})
|
||||
Object.values(ks_element.querySelectorAll(".ks_dashboard_kpi_dashboard")).map((item) => { item.addEventListener('click', this.onkschartcontainerclick.bind(this))})
|
||||
|
||||
$(document.querySelectorAll(".modal-body .ks_dashboard_item_button_container")).remove();
|
||||
$('#ks_ai_add_item').addClass("d-none");
|
||||
$(document.querySelectorAll(".modal-header .btn-close")).remove();
|
||||
$(document.querySelectorAll(".modal-footer .o-default-button")).remove();
|
||||
|
||||
let ks_footer = $(renderToElement("ks_ai_dashboard_footer",{
|
||||
self:this
|
||||
}))
|
||||
$(document.querySelectorAll(".modal-footer")).append(ks_footer)
|
||||
|
||||
}
|
||||
|
||||
getContext() {
|
||||
var self = this;
|
||||
var context = {
|
||||
ksDateFilterSelection: self.ksDateFilterSelection,
|
||||
ksDateFilterStartDate: self.ksDateFilterStartDate,
|
||||
ksDateFilterEndDate: self.ksDateFilterEndDate,
|
||||
}
|
||||
if(self.dn_state['user_context']['ksDateFilterSelection'] !== undefined && self.ksDateFilterSelection !== 'l_none'){
|
||||
context = self.dn_state['user_context']
|
||||
}
|
||||
var ks_new_obj = {...session.user_context,...{allowed_company_ids:this.env.services.company.activeCompanyIds}}
|
||||
return Object.assign(context, ks_new_obj);
|
||||
}
|
||||
|
||||
ks_fetch_data(){
|
||||
var self = this;
|
||||
return this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_fetch_dashboard_data",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'ks_fetch_dashboard_data',
|
||||
args: [self.ks_dashboard_id],
|
||||
kwargs : {context: self.getContext()},
|
||||
}).then(function(result) {
|
||||
self.ks_dashboard_data = result;
|
||||
self.ks_dashboard_data['ks_ai_dashboard'] = true
|
||||
if(self.dn_state['domain_data'] != undefined){
|
||||
self.ks_dashboard_data.ks_dashboard_domain_data=self.dn_state['domain_data']
|
||||
Object.values(self.ks_dashboard_data.ks_dashboard_pre_domain_filter).map((x)=>{
|
||||
if(self.dn_state['domain_data'][x['model']] != undefined){
|
||||
if(self.dn_state['domain_data'][x['model']]['ks_domain_index_data'][0]['label'].indexOf(x['name']) ==-1){
|
||||
self.ks_dashboard_data.ks_dashboard_pre_domain_filter[x['id']].active = false;
|
||||
}
|
||||
}
|
||||
else{
|
||||
self.ks_dashboard_data.ks_dashboard_pre_domain_filter[x['id']].active = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async dashboard_mount(){
|
||||
var self = this;
|
||||
var items = self.ksSortItems(self.ks_dashboard_data.ks_item_data)
|
||||
self.state.ks_dashboard_items = items
|
||||
self.ksRenderDashboard();
|
||||
|
||||
}
|
||||
|
||||
ks_fetch_items_data(){
|
||||
var self = this;
|
||||
var items_promises = []
|
||||
self.ks_dashboard_data.ks_dashboard_items_ids.forEach(function(item_id){
|
||||
items_promises.push(self._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/ks_fetch_item",{
|
||||
model: "ks_dashboard_ninja.board",
|
||||
method: "ks_fetch_item",
|
||||
args : [[item_id], self.ks_dashboard_id, self.ksGetParamsForItemFetch(item_id)],
|
||||
kwargs:{context: self.getContext()}
|
||||
}).then(function(result){
|
||||
self.ks_dashboard_data.ks_item_data[item_id] = result[item_id];
|
||||
}));
|
||||
});
|
||||
self.state.ks_dash_name = self.ks_dashboard_data.name,
|
||||
self.state.ks_ai_dashboard = true,
|
||||
self.state.ks_dashboard_manager = self.ks_dashboard_data.ks_dashboard_manager,
|
||||
self.state.ks_dashboard_data = self.ks_dashboard_data,
|
||||
self.state.ks_dashboard_item_length = self.ks_dashboard_data.ks_dashboard_items_ids.length
|
||||
return Promise.all(items_promises)
|
||||
}
|
||||
|
||||
ksGetParamsForItemFetch(){
|
||||
return {};
|
||||
}
|
||||
|
||||
ksRenderDashboard(){
|
||||
var self = this;
|
||||
if (self.ks_dashboard_data.ks_child_boards) self.ks_dashboard_data.name = this.ks_dashboard_data.ks_child_boards[self.ks_dashboard_data.ks_selected_board_id][0];
|
||||
if (!isMobileOS()) {
|
||||
$(self.header.el).addClass("ks_dashboard_header_sticky")
|
||||
}
|
||||
if (Object.keys(self.ks_dashboard_data.ks_item_data).length===0){
|
||||
$(self.header.el).find('.ks_dashboard_link').addClass("d-none");
|
||||
$(self.header.el).find('.ks_dashboard_edit_layout').addClass("d-none");
|
||||
}
|
||||
}
|
||||
|
||||
ksSortItems(ks_item_data) {
|
||||
var items = []
|
||||
var self = this;
|
||||
var item_data = Object.assign({}, ks_item_data);
|
||||
if (self.ks_dashboard_data.ks_gridstack_config) {
|
||||
self.gridstackConfig = JSON.parse(self.ks_dashboard_data.ks_gridstack_config);
|
||||
var a = Object.values(self.gridstackConfig);
|
||||
var b = Object.keys(self.gridstackConfig);
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
a[i]['id'] = b[i];
|
||||
}
|
||||
a.sort(function(a, b) {
|
||||
return (35 * a.y + a.x) - (35 * b.y + b.x);
|
||||
});
|
||||
for (var i = 0; i < a.length; i++) {
|
||||
if (item_data[a[i]['id']]) {
|
||||
items.push(item_data[a[i]['id']]);
|
||||
delete item_data[a[i]['id']];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return items.concat(Object.values(item_data));
|
||||
}
|
||||
|
||||
onKsDuplicateItemClick(e) {
|
||||
var self = this;
|
||||
var ks_item_id = $($(e.target).parentsUntil(".ks_dashboarditem_id").slice(-1)[0]).parent().attr('id');
|
||||
var dashboard_id = $($(e.target).parentsUntil(".ks_dashboarditem_id").slice(-1)[0]).find('.ks_dashboard_select').val();
|
||||
var dashboard_name = $($(e.target).parentsUntil(".ks_dashboarditem_id").slice(-1)[0]).find('.ks_dashboard_select option:selected').text();
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/copy",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'copy',
|
||||
args: [parseInt(ks_item_id), {
|
||||
'ks_dashboard_ninja_board_id': parseInt(dashboard_id)
|
||||
}],
|
||||
kwargs:{},
|
||||
}).then(function(result) {
|
||||
self.notification.add(_t('Selected item is duplicated to ' + dashboard_name + ' .'),{
|
||||
title:_t("Item Duplicated"),
|
||||
type: 'success',
|
||||
});
|
||||
self.actionService.doAction({
|
||||
type: "ir.actions.client",
|
||||
tag: "reload",
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
onkschartcontainerclick(ev){
|
||||
if($(ev.currentTarget).hasClass('ks_dashboard_kpi_dashboard')){
|
||||
if(!($(ev.currentTarget).find('.select-btn').hasClass('active'))){
|
||||
$('#ks_ai_add_item').removeClass("d-none");
|
||||
$(ev.currentTarget).find('.select-btn').addClass('active');
|
||||
this.ksSelectedgraphid.push(parseInt($(ev.currentTarget).parent()[0].id));
|
||||
}else{
|
||||
$(ev.currentTarget).find('.select-btn').removeClass('active');
|
||||
const index = this.ksSelectedgraphid.indexOf(parseInt($(ev.currentTarget).parent()[0].id));
|
||||
this.ksSelectedgraphid.splice(index, 1);
|
||||
}
|
||||
}else{
|
||||
if(!($(ev.currentTarget).find('.select-btn').hasClass('active'))){
|
||||
$('#ks_ai_add_item').removeClass("d-none");
|
||||
$(ev.currentTarget).find('.select-btn').addClass('active');
|
||||
this.ksSelectedgraphid.push(parseInt($(ev.currentTarget).parent()[0].id));
|
||||
}else{
|
||||
$(ev.currentTarget).find('.select-btn').removeClass('active');
|
||||
const index = this.ksSelectedgraphid.indexOf(parseInt($(ev.currentTarget).parent()[0].id));
|
||||
this.ksSelectedgraphid.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const selectedCount = this.ksSelectedgraphid.length;
|
||||
$('#selected_chart_count').text(selectedCount);
|
||||
|
||||
if (this.ksSelectedgraphid.length == 0){
|
||||
$('#ks_ai_add_item').addClass("d-none")
|
||||
}
|
||||
}
|
||||
|
||||
onselectallitems(){
|
||||
this.ksSelectedgraphid = []
|
||||
document.querySelectorAll(".modal-body .ks_list_view_container").forEach((item) =>{
|
||||
// $(item).addClass('.active')
|
||||
$(item).find('.select-btn').addClass("active");
|
||||
this.ksSelectedgraphid.push(parseInt($(item).parent()[0].id))
|
||||
});
|
||||
document.querySelectorAll(".modal-body .ks_dashboard_kpi_dashboard").forEach((item) =>{
|
||||
// $(item).parent().addClass('.active')
|
||||
$(item).find('.select-btn').addClass("active");
|
||||
this.ksSelectedgraphid.push(parseInt($(item).parent()[0].id))
|
||||
});
|
||||
|
||||
|
||||
document.querySelectorAll(".modal-body .ks_dashboarditem_chart_container").forEach((item) =>{
|
||||
// $(item).addClass('.active')
|
||||
$(item).find('.select-btn').addClass("active");
|
||||
this.ksSelectedgraphid.push(parseInt($(item).parent()[0].id))
|
||||
});
|
||||
|
||||
$('#ks_ai_add_item').removeClass("d-none")
|
||||
$('#ks_ai_remove_all_item').removeClass("d-none")
|
||||
$('#ks_ai_add_all_item').addClass("d-none")
|
||||
|
||||
const selectedCount = this.ksSelectedgraphid.length;
|
||||
$('#selected_chart_count').text(selectedCount);
|
||||
}
|
||||
|
||||
onremoveallitems(){
|
||||
|
||||
document.querySelectorAll(".modal-body .ks_list_view_container").forEach((item) =>{
|
||||
// $(item).removeClass('ks_img_selected')
|
||||
// $(item).find('.ks_img_display').addClass("d-none");
|
||||
$(item).find('.select-btn').removeClass("active");
|
||||
})
|
||||
|
||||
document.querySelectorAll(".modal-body .ks_dashboard_kpi_dashboard").forEach((item) =>{
|
||||
// $(item).parent().removeClass('ks_img_selected')
|
||||
// $(item).find('.ks_img_display').addClass("d-none");
|
||||
$(item).find('.select-btn').removeClass("active");
|
||||
});
|
||||
|
||||
document.querySelectorAll(".modal-body .ks_dashboarditem_chart_container").forEach((item) =>{
|
||||
$(item).find('.select-btn').removeClass("active");
|
||||
// $(item).removeClass('ks_img_selected')
|
||||
// $(item).find('.ks_img_display').addClass("d-none");
|
||||
});
|
||||
this.ksSelectedgraphid = [];
|
||||
$('#ks_ai_add_item').addClass("d-none")
|
||||
$('#ks_ai_remove_all_item').addClass("d-none")
|
||||
$('#ks_ai_add_all_item').removeClass("d-none")
|
||||
$('#selected_chart_count').text(0);
|
||||
|
||||
}
|
||||
|
||||
onKsaddItemClick(e) {
|
||||
var self = this;
|
||||
var dashboard_id = this.ks_ai_dash_id;
|
||||
var dashboard_name = this.ks_ai_dash_name;
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.item/write",{
|
||||
model: 'ks_dashboard_ninja.item',
|
||||
method: 'write',
|
||||
args: [this.ksSelectedgraphid, {
|
||||
'ks_dashboard_ninja_board_id': parseInt(dashboard_id)
|
||||
}],
|
||||
kwargs:{}
|
||||
}).then(function(result) {
|
||||
self.notification.add(_t('Items are added to ' + dashboard_name + ' .'),{
|
||||
title:_t("Items added"),
|
||||
type: 'success',
|
||||
});
|
||||
$.when(self.ks_fetch_data()).then(function() {
|
||||
self.onksaideletedash();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onksaideletedash(){
|
||||
var self= this;
|
||||
this._rpc("/web/dataset/call_kw/ks_dashboard_ninja.board/unlink",{
|
||||
model: 'ks_dashboard_ninja.board',
|
||||
method: 'unlink',
|
||||
args: [this.ks_ai_del_id],
|
||||
kwargs:{}
|
||||
}).then(function(result){
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
}
|
||||
speak_once(ev,item){
|
||||
}
|
||||
}
|
||||
KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardtodo, Dialog, FormViewDialog};
|
||||
KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader"
|
||||
registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja);
|
||||
261
addons/ks_dashboard_ninja/static/src/js/ks_global_functions.js
Normal file
261
addons/ks_dashboard_ninja/static/src/js/ks_global_functions.js
Normal file
@@ -0,0 +1,261 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { getCurrency } from "@web/core/currency";
|
||||
import { formatFloat, formatInteger } from "@web/views/fields/formatters";
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { eraseCookie } from "@ks_dashboard_ninja/js/cookies";
|
||||
|
||||
export const globalfunction = {
|
||||
ksNumIndianFormatter(num, digits){
|
||||
|
||||
var negative;
|
||||
var si = [{
|
||||
value: 1,
|
||||
symbol: ""
|
||||
},
|
||||
{
|
||||
value: 1E3,
|
||||
symbol: "Th"
|
||||
},
|
||||
{
|
||||
value: 1E5,
|
||||
symbol: "Lakh"
|
||||
},
|
||||
{
|
||||
value: 1E7,
|
||||
symbol: "Cr"
|
||||
},
|
||||
{
|
||||
value: 1E9,
|
||||
symbol: "Arab"
|
||||
}
|
||||
];
|
||||
if (num < 0) {
|
||||
num = Math.abs(num)
|
||||
negative = true
|
||||
}
|
||||
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
var i;
|
||||
for (i = si.length - 1; i > 0; i--) {
|
||||
if (num >= si[i].value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (negative) {
|
||||
return "-" + (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol;
|
||||
} else {
|
||||
return (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol;
|
||||
}
|
||||
|
||||
},
|
||||
ksNumFormatter(num, digits) {
|
||||
var negative;
|
||||
var si = [{
|
||||
value: 1,
|
||||
symbol: ""
|
||||
},
|
||||
{
|
||||
value: 1E3,
|
||||
symbol: "k"
|
||||
},
|
||||
{
|
||||
value: 1E6,
|
||||
symbol: "M"
|
||||
},
|
||||
{
|
||||
value: 1E9,
|
||||
symbol: "G"
|
||||
},
|
||||
{
|
||||
value: 1E12,
|
||||
symbol: "T"
|
||||
},
|
||||
{
|
||||
value: 1E15,
|
||||
symbol: "P"
|
||||
},
|
||||
{
|
||||
value: 1E18,
|
||||
symbol: "E"
|
||||
}
|
||||
];
|
||||
if (num < 0) {
|
||||
num = Math.abs(num)
|
||||
negative = true
|
||||
}
|
||||
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
var i;
|
||||
for (i = si.length - 1; i > 0; i--) {
|
||||
if (num >= si[i].value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (negative) {
|
||||
return "-" + (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol;
|
||||
} else {
|
||||
return (num / si[i].value).toFixed(digits).replace(rx, "$1") + si[i].symbol;
|
||||
}
|
||||
},
|
||||
ks_monetary(value, currency_id) {
|
||||
///get currency changed ////
|
||||
var currency = getCurrency(currency_id);
|
||||
if (!currency) {
|
||||
return value;
|
||||
}
|
||||
if (currency.position === "after") {
|
||||
return value += ' ' + currency.symbol;
|
||||
} else {
|
||||
return currency.symbol + ' ' + value;
|
||||
}
|
||||
},
|
||||
_onKsGlobalFormatter(ks_record_count, ks_data_format, ks_precision_digits){
|
||||
var self = this;
|
||||
if (ks_data_format == 'exact'){
|
||||
return formatFloat(ks_record_count, {digits: [0, ks_precision_digits]})
|
||||
// return field_utils.format.float(ks_record_count, Float64Array,{digits:[0,ks_precision_digits]});
|
||||
}else{
|
||||
if (ks_data_format == 'indian'){
|
||||
return self.ksNumIndianFormatter( ks_record_count, 1);
|
||||
}else if (ks_data_format == 'colombian'){
|
||||
return self.ksNumColombianFormatter( ks_record_count, 1, ks_precision_digits);
|
||||
}else{
|
||||
return self.ksNumFormatter(ks_record_count, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
ksNumColombianFormatter(num, digits, ks_precision_digits) {
|
||||
var negative;
|
||||
var si = [{
|
||||
value: 1,
|
||||
symbol: ""
|
||||
},
|
||||
{
|
||||
value: 1E3,
|
||||
symbol: ""
|
||||
},
|
||||
{
|
||||
value: 1E6,
|
||||
symbol: "M"
|
||||
},
|
||||
{
|
||||
value: 1E9,
|
||||
symbol: "M"
|
||||
},
|
||||
{
|
||||
value: 1E12,
|
||||
symbol: "M"
|
||||
},
|
||||
{
|
||||
value: 1E15,
|
||||
symbol: "M"
|
||||
},
|
||||
{
|
||||
value: 1E18,
|
||||
symbol: "M"
|
||||
}
|
||||
];
|
||||
if (num < 0) {
|
||||
num = Math.abs(num)
|
||||
negative = true
|
||||
}
|
||||
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||
var i;
|
||||
for (i = si.length-1; i > 0; i--) {
|
||||
if (num >= si[i].value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (si[i].symbol === 'M'){
|
||||
// si[i].value = 1000000;
|
||||
num = parseInt(num) / 1000000
|
||||
// changes
|
||||
num = formatInteger(num)
|
||||
if (negative) {
|
||||
return "-" + num + si[i].symbol;
|
||||
} else {
|
||||
return num + si[i].symbol;
|
||||
}
|
||||
}else{
|
||||
if (num % 1===0){
|
||||
// changes
|
||||
num = formatInteger(num)
|
||||
}else{
|
||||
// num = field_utils.format.float(num, Float64Array, {digits:[0,ks_precision_digits]});
|
||||
num = formatFloat(num, {digits: [0, ks_precision_digits]})
|
||||
}
|
||||
if (negative) {
|
||||
return "-" + num;
|
||||
} else {
|
||||
return num;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
function onAudioEnded (ev){
|
||||
ev.currentTarget?.parentElement?.querySelector('.voice-cricle')?.classList.toggle("d-none");
|
||||
ev.currentTarget?.parentElement?.querySelector('.comp-gif')?.classList.toggle("d-none");
|
||||
}
|
||||
|
||||
function ks_get_current_gridstack_config(gridstackRootElement){
|
||||
if (gridstackRootElement && gridstackRootElement.gridstack){
|
||||
var items = gridstackRootElement.gridstack.el.gridstack.engine.nodes;
|
||||
}
|
||||
let grid_config = {}
|
||||
if (items){
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
grid_config[items[i].id] = {
|
||||
'x': items[i].x, 'y': items[i].y,
|
||||
'w': items[i].w, 'h': items[i].h,
|
||||
}
|
||||
}
|
||||
}
|
||||
return grid_config;
|
||||
}
|
||||
|
||||
function convert_data_to_utc(list_view_data) { // TODO Can be moved to python side for faster computation
|
||||
list_view_data = JSON.parse(list_view_data);
|
||||
let datetime_format = localization.dateTimeFormat;
|
||||
let date_format = localization.dateFormat;
|
||||
if (list_view_data && list_view_data.type === "ungrouped") {
|
||||
if (list_view_data.date_index) {
|
||||
let index_data = list_view_data.date_index;
|
||||
for (let i = 0; i < index_data.length; i++) {
|
||||
for (let j = 0; j < list_view_data.data_rows.length; j++) {
|
||||
var index = index_data[i]
|
||||
var date = list_view_data.data_rows[j]["data"][index]
|
||||
if (date) {
|
||||
if (list_view_data.fields_type[index] === 'date'){
|
||||
list_view_data.data_rows[j]["data"][index] = luxon.DateTime.fromJSDate(new Date(date + " UTC")).toFormat?.(date_format);
|
||||
}else if(list_view_data.fields_type[index] === 'datetime'){
|
||||
list_view_data.data_rows[j]["data"][index] = luxon.DateTime.fromJSDate(new Date(date + " UTC")).toFormat?.(datetime_format);
|
||||
}
|
||||
}
|
||||
// else{
|
||||
//// list_view_data.data_rows[j]["data"][index] = "";
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return list_view_data;
|
||||
}
|
||||
|
||||
|
||||
function eraseAllCookies(dashboard_id, cookie_name_list_to_be_deleted = []){
|
||||
cookie_name_list_to_be_deleted.forEach( (name) => {
|
||||
eraseCookie(name + dashboard_id)
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
globalfunction: globalfunction,
|
||||
onAudioEnded,
|
||||
ks_get_current_gridstack_config,
|
||||
convert_data_to_utc,
|
||||
eraseAllCookies
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ActionContainer } from "@web/webclient/actions/action_container";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { onPatched } from "@odoo/owl";
|
||||
|
||||
|
||||
patch(ActionContainer.prototype,{
|
||||
setup(){
|
||||
super.setup();
|
||||
onPatched( () => {
|
||||
if(this?.env.services.menu.getCurrentApp?.()?.xmlid === "ks_dashboard_ninja.board_menu_root" || this.info?.componentProps?.action?.tag === 'ks_dashboard_ninja'){
|
||||
if(!$('body').hasClass('ks_body_class'))
|
||||
$('body').addClass('ks_body_class');
|
||||
}
|
||||
else if(this?.env.services.menu.getCurrentApp?.()?.xmlid !== "ks_dashboard_ninja.board_menu_root" || this.info?.componentProps?.action?.tag !== 'ks_dashboard_ninja'){
|
||||
if($('body').hasClass('ks_body_class'))
|
||||
$('body').removeClass('ks_body_class');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { onMounted } from "@odoo/owl";
|
||||
import { renderToString } from "@web/core/utils/render";
|
||||
import { WarningDialog } from "@web/core/errors/error_dialogs";
|
||||
|
||||
patch(ConfirmationDialog.prototype,{
|
||||
setup(){
|
||||
super.setup();
|
||||
|
||||
onMounted( () => {
|
||||
let modalBody = this.modalRef?.el?.querySelector('.modal-body');
|
||||
if(modalBody && (this.env.services.menu?.getCurrentApp()?.xmlid === "ks_dashboard_ninja.board_menu_root" ||
|
||||
this.env.services.action?.currentController?.action?.tag === 'ks_dashboard_ninja')){
|
||||
modalBody.innerHTML = renderToString('ks_dashboard_ninja.ksConfirmationDialogBody', {
|
||||
body: this.props.body,
|
||||
title: this.props.title,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { FileUploader } from "@web/views/fields/file_handler";
|
||||
import { onMounted, useEffect } from "@odoo/owl";
|
||||
import { renderToString } from "@web/core/utils/render";
|
||||
|
||||
patch(FileUploader.prototype,{
|
||||
setup() {
|
||||
super.setup();
|
||||
useEffect(
|
||||
() => this.changeIcons()
|
||||
);
|
||||
},
|
||||
|
||||
changeIcons(){
|
||||
let ks_upload_parent_field_el = this.fileInputRef?.el?.closest('.upload-file-btn');
|
||||
if(ks_upload_parent_field_el){
|
||||
let pencil_icon_btn = ks_upload_parent_field_el.querySelector('.fa-pencil');
|
||||
let fileUploadIcon = ks_upload_parent_field_el.querySelector('.o_select_file_button.btn-primary');
|
||||
let download_icon_btn = ks_upload_parent_field_el.querySelector('.fa-download');
|
||||
let trash_icon_btn = ks_upload_parent_field_el.querySelector('.fa-trash');
|
||||
|
||||
if(pencil_icon_btn){
|
||||
pencil_icon_btn.classList.remove('fa', 'fa-pencil');
|
||||
pencil_icon_btn.innerHTML += renderToString("ks_dashboard_ninja.edit_svg", {})
|
||||
}
|
||||
if(download_icon_btn){
|
||||
download_icon_btn.classList.remove('fa', 'fa-download')
|
||||
download_icon_btn.innerHTML += renderToString("ks_dashboard_ninja.download_svg", {})
|
||||
}
|
||||
if(trash_icon_btn){
|
||||
trash_icon_btn.classList.remove('fa', 'fa-trash')
|
||||
trash_icon_btn.innerHTML += renderToString("ks_dashboard_ninja.trash_svg", {})
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { FormViewDialog } from '@web/views/view_dialogs/form_view_dialog';
|
||||
import { onMounted } from "@odoo/owl";
|
||||
|
||||
patch(FormViewDialog.prototype,{
|
||||
setup(){
|
||||
super.setup();
|
||||
onMounted(()=>{
|
||||
if(this.props.is_expand_icon_visible){
|
||||
let expand_icon = this.modalRef.el?.querySelector('.o_expand_button')
|
||||
expand_icon?.remove?.()
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
async onExpand(){
|
||||
if(this.props.is_expand_icon_visible) return;
|
||||
super.onExpand();
|
||||
}
|
||||
});
|
||||
|
||||
FormViewDialog.props = {
|
||||
...FormViewDialog.props,
|
||||
is_expand_icon_visible : { type: Boolean, optional: true }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { FormController } from "@web/views/form/form_controller";
|
||||
import { eraseAllCookies } from '@ks_dashboard_ninja/js/ks_global_functions';
|
||||
|
||||
|
||||
patch(FormController.prototype,{
|
||||
async onRecordSaved(record, changes){
|
||||
if(this.model?.config?.resModel === 'ks_dashboard_ninja.board' && this.model.config.resId){
|
||||
let field_names = ['ks_dashboard_custom_filters_ids', 'ks_dashboard_defined_filters_ids', 'ks_date_filter_selection',
|
||||
'ks_default_end_time', 'ks_dashboard_start_date', 'ks_dashboard_end_date']
|
||||
let is_dn_cookie_related_field_changes = field_names.some(field_name => changes.hasOwnProperty(field_name));
|
||||
if(is_dn_cookie_related_field_changes)
|
||||
eraseAllCookies(this.model.config.resId,
|
||||
['PFilter', 'PFilterDataObj', 'Filter', 'CFilter', 'FilterDateData', 'ChartFilter', 'FFilter']);
|
||||
// TODO : Apply such functionlity that we donot have to give name of the name of the filter as string to erase cookies Also dont need to remove all cookies"
|
||||
|
||||
}
|
||||
super.onRecordSaved(record, changes);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { onMounted, useRef } from "@odoo/owl";
|
||||
import { FormLabel } from "@web/views/form/form_label";
|
||||
|
||||
patch(FormLabel.prototype,{
|
||||
setup(){
|
||||
this.ksRootRef = useRef("ksRootRef");
|
||||
onMounted(()=>{
|
||||
let tooltip = this.ksRootRef.el?.querySelector('.text-info')
|
||||
if(tooltip && (this.env.model?.config?.resModel.startsWith('ks_dashboard_ninja.' ||
|
||||
this.env.services.action?.currentController?.action?.tag === 'ks_dashboard_ninja')))
|
||||
tooltip.innerHTML = '<i class="fa fa-exclamation-circle" aria-hidden="true"></i>'
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,36 @@
|
||||
.ks_body_class .o_spinner {
|
||||
padding: 50px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
img{
|
||||
display : none;
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .o_spinner:before {
|
||||
content: "";
|
||||
height: 105px;
|
||||
width: 105px;
|
||||
margin: -38px auto auto -23px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
border-radius: 100%;
|
||||
animation: rotation .9s infinite linear;
|
||||
background: conic-gradient(from 180deg at 50% 50%, #E84A5F 0deg, rgba(232, 74, 95, 0) 360deg);
|
||||
mask: radial-gradient(circle, transparent 50%, black 51%);
|
||||
-webkit-mask: radial-gradient(circle, transparent 50%, black 51%);
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(359deg);
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .o_blockUI {
|
||||
z-index: 1055 !important;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { LoadingIndicator } from "@web/webclient/loading_indicator/loading_indicator";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { BlockUI } from "@web/core/ui/block_ui";
|
||||
import { useEffect, useRef, xml } from "@odoo/owl";
|
||||
|
||||
patch(LoadingIndicator.prototype, {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.shouldBlock = false;
|
||||
},
|
||||
requestCall({ detail }) {
|
||||
if (detail.settings.silent) {
|
||||
return;
|
||||
}
|
||||
if (this.state.count === 0) {
|
||||
browser.clearTimeout(this.startShowTimer);
|
||||
this.startShowTimer = browser.setTimeout(() => {
|
||||
if (this.state.count) {
|
||||
this.state.show = true;
|
||||
let ks_active_el = this.env.services.ui.activeElement.querySelector('.chat-ai-box')?.length
|
||||
if((!ks_active_el) &&( this.env.services.menu?.getCurrentApp()?.xmlid === "ks_dashboard_ninja.board_menu_root" ||
|
||||
this.env.services.action.currentController?.action?.tag === 'ks_dashboard_ninja' )){
|
||||
|
||||
this.blockUITimer = browser.setTimeout(() => {
|
||||
this.env.services.ui.block();
|
||||
this.shouldBlock = true;
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
this.rpcIds.add(detail.data.id);
|
||||
this.state.count++;
|
||||
},
|
||||
|
||||
responseCall({ detail }) {
|
||||
if(this.blockUITimer){
|
||||
clearTimeout(this.blockUITimer)
|
||||
if(this.shouldBlock){
|
||||
this.env.services.ui.unblock();
|
||||
this.shouldBlock = false;
|
||||
}
|
||||
}
|
||||
if (detail.settings.silent) {
|
||||
return;
|
||||
}
|
||||
this.rpcIds.delete(detail.data.id);
|
||||
this.state.count = this.rpcIds.size;
|
||||
if (this.state.count === 0) {
|
||||
browser.clearTimeout(this.startShowTimer);
|
||||
this.state.show = false;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
//patch(BlockUI.prototype, {
|
||||
// setup(){
|
||||
// super.setup();
|
||||
// this.menuService = useService('menu');
|
||||
//
|
||||
// useEffect( () => {
|
||||
// let spinnerImg = document.querySelector('.o_blockUI .o_spinner img');
|
||||
// if(spinnerImg && spinnerImg.src){
|
||||
// spinnerImg.src = "/web/static/img/spin.svg"
|
||||
// }
|
||||
// let currentApp = this.menuService?.getCurrentApp();
|
||||
// if (currentApp && currentApp.xmlid === "ks_dashboard_ninja.board_menu_root"){
|
||||
// if(spinnerImg && spinnerImg.src){
|
||||
// spinnerImg.src = "/ks_dashboard_ninja/static/images/loader.gif"
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//});
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { NavBar } from "@web/webclient/navbar/navbar";
|
||||
|
||||
|
||||
|
||||
patch(NavBar.prototype,{
|
||||
async adapt(){
|
||||
if(this.currentApp?.xmlid === "ks_dashboard_ninja.board_menu_root" || this.actionService?.currentController?.action.tag === 'ks_dashboard_ninja'){
|
||||
if(!$('body').hasClass('ks_body_class'))
|
||||
$('body').addClass('ks_body_class');
|
||||
}
|
||||
else{
|
||||
if($('body').hasClass('ks_body_class'))
|
||||
$('body').removeClass('ks_body_class');
|
||||
}
|
||||
return super.adapt();
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
.ks_body_class .o_notification_manager {
|
||||
position: fixed !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
margin: 0 auto !important;
|
||||
width: 50% !important;
|
||||
top: 30px !important;
|
||||
|
||||
.o_notification_title {
|
||||
font-size: $font-18 !important;
|
||||
font-weight: $f-w-600 !important;
|
||||
line-height: 25.2px;
|
||||
text-align: left;
|
||||
padding: 0 8px !important;
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
.o_notification_body {
|
||||
padding: 0 8px !important;
|
||||
margin-top: 4px !important;
|
||||
grid-column: 2 / 3;
|
||||
}
|
||||
|
||||
.o_notification_close {
|
||||
top: 50% !important;
|
||||
left: auto;
|
||||
bottom: auto;
|
||||
right: 20px !important;
|
||||
transform: translateY(-50%);
|
||||
border: 1px solid $color-black !important;
|
||||
border-radius: 50% !important;
|
||||
height: 29px !important;
|
||||
width: 29px !important;
|
||||
display: flex !important;
|
||||
justify-content: center !important;
|
||||
align-items: center !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.border {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.o_notification_content {
|
||||
font-size: $font-16 !important;
|
||||
font-weight: $f-w-400 !important;
|
||||
line-height: 22.4px;
|
||||
text-align: left;
|
||||
color: $color-4B5563 !important;
|
||||
padding-right: 20px;
|
||||
|
||||
ul {
|
||||
padding-left: 0px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
list-style: none !important;
|
||||
|
||||
&::after {
|
||||
content: ",\00a0";
|
||||
}
|
||||
|
||||
&:last-child::after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_notification {
|
||||
border-radius: 10px !important;
|
||||
padding: 20px !important;
|
||||
background-color: $color-white !important;
|
||||
border: none !important;
|
||||
border: 3px solid $color-E5E7EB !important;
|
||||
min-height: 107px;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
justify-content: center;
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-template-columns: 1.4fr 8fr;
|
||||
grid-template-rows: 1fr;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
grid-row: 1 / 3;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { onMounted, useRef, onWillUnmount } from "@odoo/owl";
|
||||
import { Notification } from "@web/core/notifications/notification";
|
||||
import { renderToElement } from "@web/core/utils/render";
|
||||
|
||||
patch(Notification.prototype,{
|
||||
setup(){
|
||||
super.setup();
|
||||
this.notificationRef = useRef('notificationRef');
|
||||
onMounted( () => {
|
||||
let notificationContainer = this.notificationRef.el ? [this.notificationRef.el] : document.querySelectorAll('.o-main-components-container .o_notification');
|
||||
if( (this.props.ks_dn_flag && notificationContainer) || (notificationContainer && (this.env.services.menu?.getCurrentApp()?.xmlid === "ks_dashboard_ninja.board_menu_root" ||
|
||||
this.env.services.action?.currentController?.action?.tag === 'ks_dashboard_ninja'))){
|
||||
let image = renderToElement('ks_dashboard_ninja.ksNotificationImage', {
|
||||
type: this.props.type ,
|
||||
});
|
||||
notificationContainer.forEach((notification) => {
|
||||
notification.parentElement.classList.add('ks-dn-website-notification');
|
||||
notification.prepend(image);
|
||||
})
|
||||
}
|
||||
});
|
||||
onWillUnmount(() => {
|
||||
let notificationContainer = this.notificationRef.el ? [this.notificationRef.el] : document.querySelectorAll('.o-main-components-container .o_notification');
|
||||
if(notificationContainer){
|
||||
notificationContainer.forEach((notification) => {
|
||||
notification.parentElement.classList.remove('ks-dn-website-notification');
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Notification.props = {
|
||||
...Notification.props,
|
||||
ks_dn_flag: { type: Boolean, optional: true },
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
|
||||
import { onMounted } from "@odoo/owl";
|
||||
import { renderToString } from "@web/core/utils/render";
|
||||
import { WarningDialog } from "@web/core/errors/error_dialogs";
|
||||
|
||||
patch(WarningDialog.prototype,{
|
||||
setup(){
|
||||
super.setup();
|
||||
|
||||
onMounted( () => {
|
||||
let modalBody = this.env.services.ui.activeElement?.querySelector('.modal-body');
|
||||
this.env.services.ui.activeElement?.querySelector('.modal-content')?.classList?.add('error-modal-ks');
|
||||
if(modalBody && (this.env.services.menu?.getCurrentApp()?.xmlid === "ks_dashboard_ninja.board_menu_root" ||
|
||||
this.env.services.action?.currentController?.action?.tag === 'ks_dashboard_ninja')){
|
||||
modalBody.innerHTML = renderToString('ks_dashboard_ninja.ksAccessErrorDialog', {
|
||||
message: this.message ,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
245
addons/ks_dashboard_ninja/static/src/scss/chat_with_ai.scss
Normal file
245
addons/ks_dashboard_ninja/static/src/scss/chat_with_ai.scss
Normal file
@@ -0,0 +1,245 @@
|
||||
|
||||
|
||||
.chat-ai-box {
|
||||
padding-right: 11px;
|
||||
height: auto;
|
||||
padding: 0 10px !important;
|
||||
|
||||
@include max-992 {
|
||||
max-height: calc(100vh - 387px);
|
||||
|
||||
}
|
||||
|
||||
.chat-sec {
|
||||
max-height: calc(100vh - 350px);
|
||||
overflow: auto;
|
||||
@include custom-scrollbar;
|
||||
|
||||
.left,
|
||||
.right {
|
||||
.title {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 19.6px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
|
||||
@include max-992 {
|
||||
font-size: $font-12;
|
||||
}
|
||||
}
|
||||
|
||||
.answers,
|
||||
.questions {
|
||||
font-size: $font-12;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 19.2px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
|
||||
@include max-992 {
|
||||
font-size: $font-10;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.user-icon {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
border-radius: 5px;
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
background-color: $color-white;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.typer-box {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0;
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
height: auto !important;
|
||||
|
||||
.typer {
|
||||
border-radius: 16px;
|
||||
background-color: $color-white;
|
||||
padding: 10px 46px 10px 10px;
|
||||
position: relative;
|
||||
|
||||
textarea {
|
||||
min-height: 79px;
|
||||
border: none;
|
||||
flex: 1;
|
||||
resize: none;
|
||||
position: relative;
|
||||
padding: 6px;
|
||||
@include custom-scrollbar;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 18.52px;
|
||||
text-align: left;
|
||||
color: $color-placeholders;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-logo {
|
||||
border-radius: 5px;
|
||||
background-color: $color-E7495E;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.chat_explain_ai {
|
||||
.ks_chart_container {
|
||||
height: 100%;
|
||||
|
||||
.ks_dashboarditem_chart_container {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// message-with-ai-ui
|
||||
|
||||
.ks_body_class .message_with_ai {
|
||||
.modal-dialog {
|
||||
width: 50% !important;
|
||||
height: calc(100% - 90%) !important;
|
||||
min-height: calc(100% - 26%) !important;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
left: auto !important;
|
||||
border: 1px solid $color-E5E7EB !important;
|
||||
background-color: $color-F5F8FB;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-bottom: 1px solid $color-E5E7EB !important;
|
||||
}
|
||||
|
||||
.chat-ai-box {
|
||||
height: auto !important;
|
||||
padding: 0 !important;
|
||||
|
||||
.chat-sec {
|
||||
padding: 0 8px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not draggable-modal-css
|
||||
|
||||
.ks_body_class #chatid {
|
||||
.modal-dialog {
|
||||
height: calc(100vh - 75px) !important;
|
||||
right: 0;
|
||||
border-radius: 10px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// new chat-ai-css
|
||||
|
||||
.ks_body_class .answers {
|
||||
.chart-table-wrapper {
|
||||
overflow: auto;
|
||||
max-height: calc(100vh - 615px);
|
||||
border: 0.66px solid $color-EDEDED;
|
||||
box-shadow: 1.32px 1.32px 2.64px 0px #0000000F;
|
||||
border-radius: 10px;
|
||||
@include custom-scrollbar;
|
||||
|
||||
table {
|
||||
// overflow: hidden;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
thead {
|
||||
|
||||
tr {
|
||||
th {
|
||||
background-color: $color-secondary-bg;
|
||||
padding: 10px;
|
||||
font-size: $font-10;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 13.88px;
|
||||
text-align: left;
|
||||
color: $color-2C2D35;
|
||||
border-right: 0.66px solid $color-FFFCFC;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
font-size: $font-10;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 15.86px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
padding: 10px;
|
||||
border-right: 0.66px solid $color-FFFCFC;
|
||||
|
||||
|
||||
&:nth-child(2) {
|
||||
color: $color-727378;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-of-type(odd)>* {
|
||||
--bs-table-bg-type: $color-white !important;
|
||||
}
|
||||
|
||||
&:nth-of-type(even)>* {
|
||||
--bs-table-bg-type: $color-secondary-bg !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// chart-insight
|
||||
|
||||
|
||||
2092
addons/ks_dashboard_ninja/static/src/scss/common.scss
Normal file
2092
addons/ks_dashboard_ninja/static/src/scss/common.scss
Normal file
File diff suppressed because it is too large
Load Diff
208
addons/ks_dashboard_ninja/static/src/scss/explainAi.scss
Normal file
208
addons/ks_dashboard_ninja/static/src/scss/explainAi.scss
Normal file
@@ -0,0 +1,208 @@
|
||||
.explain-ai {
|
||||
|
||||
// max-height: calc(100vh - 200px);
|
||||
// overflow: auto;
|
||||
//
|
||||
// &.ks_ai_explain_body{
|
||||
// height: auto !important;
|
||||
// }
|
||||
.ks_ai_explain_tile {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@include custom-scrollbar;
|
||||
|
||||
.row {
|
||||
margin-bottom: 20px;
|
||||
row-gap: 16px;
|
||||
|
||||
.charts-sec {
|
||||
border: 0.82px solid $color-E5E7EB;
|
||||
border-radius: 16px;
|
||||
min-height: 290px;
|
||||
height: 100%;
|
||||
padding: 9px 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
|
||||
.encapsulated-tile-container {
|
||||
position: relative !important;
|
||||
min-height: 185px !important;
|
||||
border-radius:16px !important;
|
||||
&.layout-6-box {
|
||||
padding: 0px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.encap-layout-2-box {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
.layout-2-count {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-600;
|
||||
line-height: 32px;
|
||||
text-align: left;
|
||||
margin-top: 20px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.layout-2-icon {
|
||||
border-bottom-left-radius: 16px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 16px;
|
||||
}
|
||||
|
||||
.layout-2-name {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
text-align: left;
|
||||
margin-left: 10px;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.layout-2-icon {
|
||||
border-bottom-left-radius: 16px;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 16px;
|
||||
padding: 17px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
font-size: 4rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& .ks_list_explain {
|
||||
min-height: 290px;
|
||||
height: 100%;
|
||||
max-height: 290px;
|
||||
}
|
||||
|
||||
&.ks_explain_ai {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
& .ks_explain_ai_view {
|
||||
width: 100% !important;
|
||||
flex: unset !important;
|
||||
border-radius:16px;
|
||||
}
|
||||
}
|
||||
|
||||
&.ks_list_card_body {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.ks_ai_dashboard_item {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
flex: 1;
|
||||
border: none;
|
||||
|
||||
&>div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 26.35px;
|
||||
text-align: left;
|
||||
color: $color-05004E;
|
||||
margin-bottom: 12px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.chart-preview {
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
height: 226px;
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.charts-data {
|
||||
border: 1px solid $color-E5E7EB;
|
||||
border-radius: 20px;
|
||||
min-height: 290px;
|
||||
font-size: $font-12;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 19.2px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
position: relative;
|
||||
background-color: $color-bg-main;
|
||||
padding: 18px 14px;
|
||||
|
||||
.ks_ai_explanation {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.charts-content-box {
|
||||
max-height: 220px;
|
||||
overflow: auto;
|
||||
max-width: 100% !important;
|
||||
|
||||
.ks_ai_explanation {
|
||||
max-width: 100% !important;
|
||||
height: auto !important;
|
||||
padding: 9px 33px !important;
|
||||
}
|
||||
|
||||
@include custom-scrollbar;
|
||||
}
|
||||
|
||||
.voice-button {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
border-radius: 50%;
|
||||
background-color: $color-white;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ks_ai_explain_tile {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.explain-ai {
|
||||
|
||||
&+.ks_explain_todo {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
.explain-ai-header {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
1004
addons/ks_dashboard_ninja/static/src/scss/form_views.scss
Normal file
1004
addons/ks_dashboard_ninja/static/src/scss/form_views.scss
Normal file
File diff suppressed because it is too large
Load Diff
109
addons/ks_dashboard_ninja/static/src/scss/ks_ai_dashboard.scss
Normal file
109
addons/ks_dashboard_ninja/static/src/scss/ks_ai_dashboard.scss
Normal file
@@ -0,0 +1,109 @@
|
||||
.generated-chart {
|
||||
row-gap: 12px;
|
||||
column-gap: 8px;
|
||||
@media screen and (min-width:992px) {
|
||||
.col-lg-4 {
|
||||
padding:0 6px !important;
|
||||
}
|
||||
}
|
||||
.row {
|
||||
row-gap:12px;
|
||||
padding:0 24px;
|
||||
}
|
||||
.generated-cart-box {
|
||||
box-shadow: 0px 3.29px 16.47px 0px #EEEEEE80;
|
||||
border: 0.82px solid $color-E5E7EB;
|
||||
border-radius: 16px;
|
||||
min-height: 292px;
|
||||
background-color: $color-white;
|
||||
position: relative;
|
||||
// min-width: 421px;
|
||||
height:100%;
|
||||
.select-btn {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 9px;
|
||||
z-index: 10;
|
||||
display: block !important;
|
||||
|
||||
#count_selected_btn {
|
||||
border: initial;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: $color-737791;
|
||||
}
|
||||
|
||||
&.active {
|
||||
svg {
|
||||
fill: #6789C6 !important;
|
||||
stroke: white !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
padding: 8px 16px;
|
||||
position: relative;
|
||||
|
||||
h5 {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 26.35px;
|
||||
text-align: left;
|
||||
color: $color-05004E;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.chart-preview {
|
||||
padding: 8px 12px;
|
||||
min-height: 228px;
|
||||
position:relative;
|
||||
height:100%;
|
||||
.chart {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.btn-box {
|
||||
.select-deselect#ks_ai_add_all_item,.select-deselect#ks_ai_remove_all_item,.select-deselect#ks_close_dialog {
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 22.4px;
|
||||
text-align: left;
|
||||
// color: $color-151D48;
|
||||
min-height: 40px;
|
||||
padding: 0 20px;
|
||||
background-color: $color-white;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
color: inherit !important;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: #737791;
|
||||
}
|
||||
|
||||
&.active {
|
||||
svg {
|
||||
fill: #6789C6;
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*rtl:begin:ignore*/
|
||||
.grid-stack > .grid-stack-item {
|
||||
|
||||
$gridstack-columns: 36;
|
||||
|
||||
min-width: (100% / $gridstack-columns);
|
||||
|
||||
@for $i from 1 through $gridstack-columns {
|
||||
&[data-gs-width='#{$i}'] { width: (100% / $gridstack-columns) * $i; }
|
||||
&[data-gs-x='#{$i}'] { left: (100% / $gridstack-columns) * $i; }
|
||||
&[data-gs-min-width='#{$i}'] { min-width: (100% / $gridstack-columns) * $i; }
|
||||
&[data-gs-max-width='#{$i}'] { max-width: (100% / $gridstack-columns) * $i; }
|
||||
}
|
||||
}
|
||||
/*rtl:end:ignore*/
|
||||
|
||||
#dn_fav_filters .active{
|
||||
background-color: #c9dbf0;
|
||||
}
|
||||
428
addons/ks_dashboard_ninja/static/src/scss/modal.scss
Normal file
428
addons/ks_dashboard_ninja/static/src/scss/modal.scss
Normal file
@@ -0,0 +1,428 @@
|
||||
// chat-inbox
|
||||
|
||||
.ks_body_class .chart-sec-modal {
|
||||
.modal {
|
||||
background-color: transparent;
|
||||
|
||||
.modal-dialog {
|
||||
height: calc(100% - 2%) !important;
|
||||
right: 0;
|
||||
border-radius: 10px !important;
|
||||
margin: 0 !important;
|
||||
position: absolute;
|
||||
|
||||
@include max-575 {
|
||||
justify-content: end;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
top: 71px !important;
|
||||
height: 100%;
|
||||
box-shadow: 0px 0px 10px 5px #9C8B8A26;
|
||||
right: 0px;
|
||||
border-radius: 10px !important;
|
||||
border: none !important;
|
||||
|
||||
|
||||
@include max-575 {
|
||||
height: 92% !important;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-radius: 10px 10px 0 0 !important;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
>div {
|
||||
height: 100%;
|
||||
|
||||
>div {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
>* {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.ks_body_class .o-mail-ChatWindow:not(.o-folded) {
|
||||
height: 100%;
|
||||
box-shadow: 0px 0px 10px 5px #9C8B8A26;
|
||||
right: 0px !important;
|
||||
border-radius: 10px !important;
|
||||
border: none !important;
|
||||
width: 600px !important;
|
||||
max-height: 92vh !important;
|
||||
|
||||
.o-mail-Composer{
|
||||
max-height: 50vh;
|
||||
}
|
||||
}
|
||||
|
||||
.ks_body_class .modal-backdrop.show {
|
||||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.ks_body_class {
|
||||
.modal-dialog {
|
||||
|
||||
.modal-content {
|
||||
border-radius: 16px;
|
||||
|
||||
.filter {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@include max-575 {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 12px 16px;
|
||||
background-color: $color-bg-main;
|
||||
border-radius: 16px 16px 0 0;
|
||||
border-bottom: 0;
|
||||
justify-content: start !important;
|
||||
|
||||
@include max-575 {
|
||||
background-color: $color-bg-main !important;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 22.4px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
|
||||
@include max-575 {
|
||||
color: $color-black !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
background: url("../../images/icons/close-circle.svg") center/1.5em auto no-repeat;
|
||||
opacity: 1;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
.encapsulated-tile-container {
|
||||
min-height: 180px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.minimum-180 {
|
||||
min-height: 140px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ks_list_view_container {
|
||||
padding: unset !important;
|
||||
border-radius: unset;
|
||||
border: unset !important;
|
||||
}
|
||||
|
||||
.main-box {
|
||||
overflow: unset !important;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
// for double scroll of modal body on chart screen view
|
||||
.encapsulated-form-view .o_form_renderer {
|
||||
max-height: calc(100vh - 316px);
|
||||
}
|
||||
|
||||
// for chart screen double arrow fix
|
||||
.encapsulated-form-arrow {
|
||||
.o_dropdown_button::after {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.screen-info,
|
||||
.chart_button_container, .ks_explain_todo {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
// max-height: calc(100vh - 200px);
|
||||
// overflow: auto;
|
||||
@include custom-scrollbar;
|
||||
|
||||
.ks_dashboard_main_content {
|
||||
max-height: unset !important;
|
||||
overflow: unset;
|
||||
|
||||
}
|
||||
|
||||
// delete-modal
|
||||
.modal-para {
|
||||
font-size: $font-24;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 33.6px;
|
||||
text-align: center;
|
||||
color: $color-black;
|
||||
}
|
||||
|
||||
// duplicate dashboard
|
||||
.duplicate-db {
|
||||
.o_form_renderer {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 0;
|
||||
|
||||
.o_inner_group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
max-width: 378.5px;
|
||||
width: 100%;
|
||||
|
||||
label {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_form_label {
|
||||
font-size: $font-12;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 9.66px;
|
||||
letter-spacing: 0.0015em;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
margin-bottom: 8px;
|
||||
opacity: 1 !important;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $color-black;
|
||||
}
|
||||
}
|
||||
|
||||
.ks_dash_row {
|
||||
.o_wrap_field {
|
||||
@include max-768 {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.o_cell {
|
||||
width: 100% !important;
|
||||
|
||||
@include max-992 {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.o_inner_group {
|
||||
gap: 32px 16px !important;
|
||||
|
||||
@include max-992 {
|
||||
gap: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include max-768 {
|
||||
.o_cell {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.o_form_view .o_group {
|
||||
.o_inner_group {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-widget.ui-autocomplete {
|
||||
// position: absolute !important;
|
||||
// width: 100%;
|
||||
// max-width: 100% !important;
|
||||
box-shadow: 0px 4px 12px 0px #00000040;
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
|
||||
& .ui-menu-item>a {
|
||||
padding: 8px;
|
||||
font-size: $font-14;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 16px;
|
||||
text-align: left;
|
||||
color: $color-paragraph ;
|
||||
|
||||
&:hover,
|
||||
&.ui-state-active {
|
||||
color: $color-secondary-main;
|
||||
background-color: $color-E6FCF5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dashboard-settings-start
|
||||
&.o_act_window {
|
||||
|
||||
.o_notebook {
|
||||
margin-top: 20px;
|
||||
|
||||
.o_notebook_headers {
|
||||
padding: 0 16px;
|
||||
|
||||
.nav-tabs {
|
||||
border-bottom: 1px solid $color-E5E7EB;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
background-color: transparent;
|
||||
|
||||
.nav-link {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0.01em;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
padding: 16px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
|
||||
&.active {
|
||||
color: $color-E7495E;
|
||||
border-bottom: 2px solid $color-E7495E;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_notebook_content {
|
||||
margin-top: 24px;
|
||||
|
||||
.tab-pane {
|
||||
.o_renderer.table-responsive {
|
||||
margin: -16px 0;
|
||||
|
||||
table {
|
||||
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
|
||||
&:last-child {
|
||||
width: 84px !important;
|
||||
}
|
||||
|
||||
// max-width: none !important;
|
||||
// width: auto !important;
|
||||
background-color: $color-secondary-bg;
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-500;
|
||||
line-height: 18px;
|
||||
padding: 12px 24px;
|
||||
text-align: left;
|
||||
color: $color-paragraph;
|
||||
|
||||
@include max-768 {
|
||||
width: fit-content !important;
|
||||
max-width: fit-content !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
padding: 16px 24px;
|
||||
border-bottom: 1px solid $color-EAECF0;
|
||||
background-color: $color-white !important;
|
||||
--table-accent-bg: $color-white;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
color: $color-black;
|
||||
vertical-align: middle;
|
||||
|
||||
button {
|
||||
&.fa-trash-o {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: $color-bg-main !important;
|
||||
border: 0.38px solid $color-CDAAAA;
|
||||
border-radius: 50% !important;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: $font-16;
|
||||
font-weight: $f-w-400;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
color: $color-secondary-main !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border: 0;
|
||||
justify-content: flex-end !important;
|
||||
|
||||
.o_form_buttons_edit {
|
||||
justify-content: end !important;
|
||||
}
|
||||
|
||||
footer {
|
||||
justify-content: flex-end !important;
|
||||
|
||||
button {
|
||||
@include max-768 {
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.duplicate-btn-box {
|
||||
justify-content: center !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.favFilterDialog {
|
||||
.modal-footer {
|
||||
justify-content: end !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
161
addons/ks_dashboard_ninja/static/src/scss/variable.scss
Normal file
161
addons/ks_dashboard_ninja/static/src/scss/variable.scss
Normal file
@@ -0,0 +1,161 @@
|
||||
// Base colors
|
||||
$color-black: #241C1D;
|
||||
$color-white: #FFFFFF;
|
||||
$color-dark-black: #000000;
|
||||
$color-nav-bg: #E2E9F0;
|
||||
|
||||
// Primary colors
|
||||
$color-primary-main: #E84A5F;
|
||||
$color-bg-main: #F5F8FB;
|
||||
|
||||
// Secondary colors
|
||||
$color-secondary-main: #04A9CC;
|
||||
$color-secondary-bg: #F4FAFF;
|
||||
|
||||
// State colors
|
||||
$color-danger: #EC2D30;
|
||||
$color-warning: #FFC62B;
|
||||
$color-success: #0C9D61;
|
||||
$color-info: #3A70E2;
|
||||
|
||||
// Element colors
|
||||
$color-paragraph: #4b5563;
|
||||
$color-placeholders: #9ca3af;
|
||||
|
||||
$color-E6FCF5: #E6FCF5;
|
||||
$color-D9F1FD: #D9F1FD;
|
||||
$color-737791: #737791;
|
||||
$color-E5E7EB: #E5E7EB;
|
||||
$color-btn-hover: #ff2341;
|
||||
$color-FFE2E5: #FFE2E5;
|
||||
$color-FFF4DE: #FFF4DE;
|
||||
$color-DCFCE7: #DCFCE7;
|
||||
$color-F3E8FF: #F3E8FF;
|
||||
$color-E7495E: #E7495E;
|
||||
$color-292D32: #292D32;
|
||||
$color-05004E: #05004E;
|
||||
$color-D1D5DB: #D1D5DB;
|
||||
$btn-hover: #DE1D37;
|
||||
$color-1E1E1E: #1E1E1E;
|
||||
$color-EAECF0: #EAECF0;
|
||||
$color-CDAAAA: #CDAAAA;
|
||||
$color-6789C6: #6789C6;
|
||||
$color-FFF5F5: #FFF5F5;
|
||||
$color-7B91B0: #7B91B0;
|
||||
$color-F5F8FB: #F5F8FB;
|
||||
$color-F5F8FB :#F5F8FB;
|
||||
$color-2C2D35: #2C2D35;
|
||||
$color-EDEDED: #EDEDED;
|
||||
$color-FFFCFC: #FFFCFC;
|
||||
$color-727378: #727378;
|
||||
$color-4B5563: #4B5563;
|
||||
$color-fff4f4: #fff4f4;
|
||||
$color-ABC8E7: #ABC8E7;
|
||||
$color-E95266: #E95266;
|
||||
$color-597ebe: #597ebe;
|
||||
|
||||
// font-weights
|
||||
|
||||
$f-w-400: 400;
|
||||
$f-w-500: 500;
|
||||
$f-w-600: 600;
|
||||
$f-w-700: 700;
|
||||
|
||||
// font-size
|
||||
$font-8: 8px;
|
||||
$font-10: 10px;
|
||||
$font-12: 12px;
|
||||
$font-14: 14px;
|
||||
$font-15: 15px;
|
||||
$font-16: 16px;
|
||||
$font-18: 18px;
|
||||
$font-20: 20px;
|
||||
$font-22: 22px;
|
||||
$font-24: 24px;
|
||||
$font-26: 26px;
|
||||
$font-28: 28px;
|
||||
$font-30: 30px;
|
||||
$font-32: 32px;
|
||||
$font-34: 34px;
|
||||
$font-36: 36px;
|
||||
$font-40: 40px;
|
||||
|
||||
|
||||
|
||||
// media queris:
|
||||
@mixin minmax1260 {
|
||||
@media screen and (min-width:1200px) and (max-width:1300px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin min768 {
|
||||
@media screen and (min-width:768px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-1500 {
|
||||
@media screen and (max-width:1500px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-1260 {
|
||||
@media screen and (max-width:1260px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-992 {
|
||||
@media screen and (max-width:992px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-768 {
|
||||
@media screen and (max-width:768px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-575 {
|
||||
@media screen and (max-width:575.8px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin min-1600 {
|
||||
@media screen and (min-width:1600px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin custom-scrollbar {
|
||||
&::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background-color: var(--color-transparent) !important;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: $color-D1D5DB !important;
|
||||
border-radius: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-1500 {
|
||||
@media screen and (max-width: 1500px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin max-1600 {
|
||||
@media screen and (max-width: 1600px) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/** @odoo-module **/
|
||||
import { registry } from "@web/core/registry";
|
||||
import { standardFieldProps } from "@web/views/fields/standard_field_props";
|
||||
const { Component,useState,onWillUpdateProps} = owl;
|
||||
|
||||
export class KsColorPicker extends Component{
|
||||
setup(){
|
||||
var self=this.props;
|
||||
}
|
||||
get value(){
|
||||
return{
|
||||
'ks_color':this.props.record.data[this.props.name].split(",")[0] || "#376CAE",
|
||||
'ks_opacity':this.props.record.data[this.props.name].split(",")[1] ||'0.99'
|
||||
}
|
||||
}
|
||||
|
||||
_ksOnColorChange(ev) {
|
||||
var new_value=(ev.currentTarget.value.concat("," + this.props.record.data[this.props.name].split(',')[1]));
|
||||
this.props.record.update({ [this.props.name]: new_value });
|
||||
|
||||
}
|
||||
|
||||
_ksOnOpacityChange(ev) {
|
||||
var new_value=(this.props.record.data[this.props.name].split(',')[0].concat("," + event.currentTarget.value));
|
||||
this.props.record.update({ [this.props.name]: new_value });
|
||||
}
|
||||
|
||||
_ksOnOpacityInputNew(ev){
|
||||
const newOpacity = ev.currentTarget.value;
|
||||
const percentage = (newOpacity - ev.currentTarget.min) / (ev.currentTarget.max - ev.currentTarget.min) * 100;
|
||||
|
||||
ev.currentTarget.style.background = `linear-gradient(to right, rgba(231, 198, 201, 1) ${percentage}%, #d3d3d3 ${percentage}%)`;
|
||||
}
|
||||
|
||||
_ksOnOpacityInput(ev) {
|
||||
var self = this;
|
||||
var color;
|
||||
if (this.props.name == "ks_background_color") {
|
||||
color = $('.ks_db_item_preview_color_picker').css("background-color")
|
||||
$('.ks_db_item_preview_color_picker').css("background-color", self.get_color_opacity_value(color, event.currentTarget.value))
|
||||
|
||||
color = $('.ks_db_item_preview_l2').css("background-color")
|
||||
$('.ks_db_item_preview_l2').css("background-color", self.get_color_opacity_value(color, event.currentTarget.value))
|
||||
|
||||
} else if (this.props.name == "ks_default_icon_color") {
|
||||
color = $('.ks_dashboard_icon_color_picker > span').css('color')
|
||||
$('.ks_dashboard_icon_color_picker > span').css('color', self.get_color_opacity_value(color, event.currentTarget.value))
|
||||
} else if (this.props.name == "ks_font_color") {
|
||||
color = $('.ks_db_item_preview').css("color")
|
||||
color = $('.ks_db_item_preview').css("color", self.get_color_opacity_value(color, event.currentTarget.value))
|
||||
}
|
||||
}
|
||||
|
||||
get_color_opacity_value(color, val) {
|
||||
if (color) {
|
||||
return color.replace(color.split(',')[3], val + ")");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
KsColorPicker.template="Ks_color_picker_opacity_view";
|
||||
KsColorPicker.props = {
|
||||
...standardFieldProps,
|
||||
};
|
||||
export const ksColorPickerField = {
|
||||
component: KsColorPicker,
|
||||
supportedTypes: ["char"],
|
||||
};
|
||||
registry.category("fields").add('Ks_dashboard_color_picker_owl', ksColorPickerField);
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
<t t-name="Ks_color_picker_opacity_view" owl="1">
|
||||
<input class="ks_color_picker" type="color" t-att-value="value['ks_color']"
|
||||
t-on-change="(ev) => this._ksOnColorChange(ev)"/>
|
||||
|
||||
<input type="range" t-att-value="value['ks_opacity']" class="ks_color_opacity" name="ks_db_item_opacity"
|
||||
min="0" max="0.99" step="0.01" t-on-input="(ev) => this._ksOnOpacityInputNew(ev)" t-on-change="(ev) => this._ksOnOpacityChange(ev)"/>
|
||||
<!-- t-on-input="(ev) => this._ksOnOpacityInput(ev)"/>-->
|
||||
</t>
|
||||
</templates>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user