user profile dashboard

This commit is contained in:
Pranay 2025-08-18 10:28:27 +05:30
parent e50063f579
commit 457867f3b0
19 changed files with 1025 additions and 25 deletions

View File

@ -116,6 +116,7 @@ Dashboard Ninja v16.0,
'ks_dashboard_ninja/static/src/css/ks_toggle_icon.css', 'ks_dashboard_ninja/static/src/css/ks_toggle_icon.css',
'ks_dashboard_ninja/static/src/css/ks_flower_view.css', 'ks_dashboard_ninja/static/src/css/ks_flower_view.css',
'ks_dashboard_ninja/static/src/css/ks_map_view.css', 'ks_dashboard_ninja/static/src/css/ks_map_view.css',
'ks_dashboard_ninja/static/src/css/ks_profile.css',
'ks_dashboard_ninja/static/src/css/ks_funnel_view.css', 'ks_dashboard_ninja/static/src/css/ks_funnel_view.css',
'ks_dashboard_ninja/static/src/css/ks_dashboard_options.css', 'ks_dashboard_ninja/static/src/css/ks_dashboard_options.css',
'/ks_dashboard_ninja/static/lib/js/gridstack-h5.js', '/ks_dashboard_ninja/static/lib/js/gridstack-h5.js',

View File

@ -387,7 +387,8 @@ class KsDashboardNinjaItems(models.Model):
('ks_to_do', 'To Do'), ('ks_to_do', 'To Do'),
('ks_map_view', 'Map View'), ('ks_map_view', 'Map View'),
('ks_funnel_chart', 'Funnel Chart'), ('ks_funnel_chart', 'Funnel Chart'),
('ks_bullet_chart', 'Bullet Chart') ('ks_bullet_chart', 'Bullet Chart'),
('ks_profile', 'Profile Chart'),
], default=lambda self: self._context.get('ks_dashboard_item_type', ], default=lambda self: self._context.get('ks_dashboard_item_type',
'ks_tile'), required=True, 'ks_tile'), required=True,
string="Dashboard Item Type", string="Dashboard Item Type",
@ -639,6 +640,7 @@ class KsDashboardNinjaItems(models.Model):
help="Display the total sum of each legends as it grows with times") help="Display the total sum of each legends as it grows with times")
ks_radial_preview = fields.Char(string="Radial Preview", default="Radial Preview") ks_radial_preview = fields.Char(string="Radial Preview", default="Radial Preview")
ks_map_preview = fields.Char(string="Map Preview", default="Map Preview") ks_map_preview = fields.Char(string="Map Preview", default="Map Preview")
ks_profile_preview = fields.Char(string="Profile Preview", default="Profile Preview")
ks_partners_map = fields.Char(compute="_compute_map_partners") ks_partners_map = fields.Char(compute="_compute_map_partners")
ks_country_id = fields.Many2one('res.country', string="Country") ks_country_id = fields.Many2one('res.country', string="Country")
ks_country_code = fields.Char(related="ks_country_id.code", store=True) ks_country_code = fields.Char(related="ks_country_id.code", store=True)
@ -694,6 +696,11 @@ class KsDashboardNinjaItems(models.Model):
ks_three_d = fields.Boolean(string='3D View', default=False) ks_three_d = fields.Boolean(string='3D View', default=False)
@api.onchange('ks_dashboard_item_type')
def onchange_ks_dashboard_item_type(self):
for rec in self:
if rec.ks_dashboard_item_type == 'ks_profile':
rec.ks_model_id = self.env['ir.model'].sudo().search([('model','=','hr.employee')],limit=1)
@api.model @api.model
def create_ai_dash(self, data, ks_dash_id, model): def create_ai_dash(self, data, ks_dash_id, model):
@ -4533,7 +4540,9 @@ class KsDashboardItemsActions(models.Model):
('ks_radar_view', 'Radar View'), ('ks_radar_view', 'Radar View'),
('ks_flower_view', 'Flower View'), ('ks_flower_view', 'Flower View'),
('ks_funnel_chart', 'Funnel Chart'), ('ks_funnel_chart', 'Funnel Chart'),
('ks_bullet_chart', 'Bullet Chart')], ('ks_bullet_chart', 'Bullet Chart'),
('ks_profile', 'Profile Chart')
],
string="Item Type") string="Item Type")
ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item") ks_dashboard_item_id = fields.Many2one('ks_dashboard_ninja.item', string="Dashboard Item")

View File

@ -0,0 +1,6 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24 24C29.5228 24 34 19.5228 34 14C34 8.47715 29.5228 4 24 4C18.4772 4 14 8.47715 14 14C14 19.5228 18.4772 24 24 24Z"
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
<path d="M10 40C10 33.3726 16.3726 28 24 28C31.6274 28 38 33.3726 38 40"
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
</svg>

After

Width:  |  Height:  |  Size: 521 B

View File

@ -401,7 +401,6 @@ export class Ksdashboardgraph extends Component{
// 3D Bar Chart Implementation // 3D Bar Chart Implementation
create3DBarChart(chart, data, ks_data, item) { create3DBarChart(chart, data, ks_data, item) {
// Create axes // Create axes
debugger;
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis()); var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category"; categoryAxis.dataFields.category = "category";
categoryAxis.renderer.labels.template.rotation = -45; categoryAxis.renderer.labels.template.rotation = -45;
@ -736,7 +735,6 @@ export class Ksdashboardgraph extends Component{
['ks_bar_chart','ks_horizontalBar_chart','ks_pie_chart','ks_doughnut_chart'].includes(item.ks_dashboard_item_type); ['ks_bar_chart','ks_horizontalBar_chart','ks_pie_chart','ks_doughnut_chart'].includes(item.ks_dashboard_item_type);
if (use3D) { if (use3D) {
debugger;
switch (theme) { switch (theme) {
case "dark": case "dark":
am4core.unuseAllThemes(); am4core.unuseAllThemes();

View File

@ -0,0 +1,218 @@
/** @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 { _t } from "@web/core/l10n/translation";
import { onAudioEnded } from '@ks_dashboard_ninja/js/ks_global_functions';
import { rpc } from "@web/core/network/rpc";
export class Ksdashboardprofile extends Component {
setup() {
debugger;
var self = this;
this.orm = useService("orm");
this.actionService = useService("action");
this.ks_profile = useRef('ks_profile');
this.ks_container_class = 'grid-stack-item';
this.aiAudioRef = useRef("aiAudioRef");
this.ks_inner_container_class = 'grid-stack-item-content';
this.state = useState({
employee: {
name: '',
image_1920: '',
job_id: null,
current_company_exp: null,
doj: '',
employee_id: null,
birthday: '',
attendance_state: null,
mobile_phone: '',
work_email: '',
private_street: '',
department_id: ''
}
});
this.storeService = useService("mail.store");
this.item = this.props.item;
this.ks_dashboard_data = this.props.dashboard_data;
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-profile-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_profile();
var update_interval = this.props.dashboard_data.ks_set_interval;
onWillUpdateProps(async (nextprops) => {
if (nextprops.ksdatefilter != 'none') {
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
}
if (Object.keys(nextprops.pre_defined_filter).length) {
if (nextprops.pre_defined_filter?.item_ids?.includes(this.item.id)) {
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
}
}
if (Object.keys(nextprops.custom_filter).length) {
if (nextprops.custom_filter?.item_ids?.includes(this.item.id)) {
await this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
}
}
});
useEffect(() => {
if (update_interval && !this.env.inDialog) {
const interval = setInterval(() => {
this.ksFetchUpdateProfile(this.item.id, this.props.dashboard_data.context);
}, update_interval);
return () => clearInterval(interval);
}
});
onMounted(() => {
if (this.ks_ai_analysis) {
const dashboardItems = this.ks_profile.el.querySelectorAll('.ks_dashboarditem_id');
dashboardItems.forEach(item => {
item.classList.add('ks_ai_chart_body');
});
}
this.aiAudioRef.el?.addEventListener('ended', onAudioEnded);
});
onWillUnmount(() => {
this.aiAudioRef.el?.removeEventListener('ended', onAudioEnded);
});
}
ksFetchUpdateProfile(item_id, domain) {
var self = this;
if (!domain) {
if (this.__owl__.parent.component.hasOwnProperty('ksGetParamsForItemFetch') &&
this.__owl__.parent.component?.ksGetParamsForItemFetch(item_id) instanceof Function) {
domain = this.__owl__.parent.component?.ksGetParamsForItemFetch(item_id);
} else {
domain = {};
}
}
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, domain
],
kwargs: { context: this.props.dashboard_data.context },
}).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_profile();
}.bind(this));
}
ksStopClickPropagation(e) {
this.ksAllowItemClick = false;
}
prepare_profile() {
var self = this;
var ks_rgba_background_color, ks_rgba_font_color, ks_rgba_button_color;
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_button_color = self._ks_get_rgba_format(this.item.ks_button_color);
if (this.item.ks_info) {
var ks_description = this.item.ks_info.split('\n');
var ks_description = ks_description.filter(element => element !== '');
} else {
var ks_description = false;
}
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;
// Fetch employee data
this.fetchEmployeeData();
}
async fetchEmployeeData() {
try {
debugger;
const employeeData = await this.orm.call("hr.employee", 'get_user_employee_details');
debugger;
if (employeeData && employeeData.length > 0) {
const employee = employeeData[0];
this.state.employee = {
name: employee.name,
image_1920: employee.image_1920,
doj: employee.doj,
job_id: employee.job_id,
employee_id: employee.employee_id,
current_company_exp: employee.current_company_exp,
attendance_state: employee.attendance_state,
birthday: employee.birthday,
mobile_phone: employee.mobile_phone,
work_email: employee.work_email,
private_street: employee.private_street,
department_id: employee.department_id ? employee.department_id[1] : ''
};
}
} catch (error) {
console.error("Error fetching employee data:", error);
}
}
async attendance_sign_in_out() {
try {
await this.orm.call('hr.employee', 'attendance_manual', [[this.state.employee.id]]);
this.state.employee.attendance_state =
this.state.employee.attendance_state === 'checked_in' ? 'checked_out' : 'checked_in';
} catch (error) {
console.error("Error updating attendance:", error);
}
}
_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 + ";";
return {
'background_style': background_style,
};
}
}
Ksdashboardprofile.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 },
ks_speak: { type: Function, Optional: true },
hideButtons: { type: Number, optional: true },
on_dialog: { type: Boolean, optional: true },
generate_dialog: { type: Boolean, optional: true },
};
Ksdashboardprofile.template = "Ksdashboardprofile";

View File

@ -0,0 +1,330 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="Ksdashboardprofile">
<t t-if="props.on_dialog">
<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_profile">
<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_profile_layout"/>
</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_profile_layout"/>
</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_profile">
<t t-if="ks_ai_analysis">
<div class="ks_ai_explain_body">
<t t-call="ks_profile_layout"/>
<!-- <t t-call="ks_item_explanation"/>-->
</div>
</t>
<t t-else="">
<t t-call="ks_profile_layout"/>
</t>
</div>
</t>
</t>
<t t-name="ks_profile_layout">
<div t-att-class="'ks_dashboarditem_id ks_profile_carousel encapsulated-profile-container ks_explain_ai_view ks_dashboard_profile 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">
<div class="ks_dashboard_item_button_container ks_dropdown_container ks_dashboard_item_header ks_dashboard_item_header_hover"
t-att-data-item_id="item.id">
<t t-if="item.ksIsDashboardManager and props.hideButtons and !props.on_dialog">
<button title="Move/Duplicate" data-bs-toggle="dropdown"
class="ks_dashboard_item_action dropdown-toggle img-bg hover-item me-lg-2 kpi-tile-img bg-white d-md-block d-none"
type="button"
t-att-style="'color:'+ ks_rgba_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.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 dropdown-menu-right">
<li class="ks_md_heading m-2">
<span>Select Dashboard</span>
</li>
<li class="m-2">
<select class="o_input o_group_selector o_add_group ks_dashboard_select">
<t t-foreach="ks_dashboard_list" t-as="ks_dashboard" t-key="ks_dashboard.id">
<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"
tabindex="-1" type="button">Duplicate
</button>
<button class="dash-btn-red o_apply_group o_add_group ks_move_item" tabindex="-1"
type="button">Move
</button>
</li>
</ul>
<button title="Quick Customize"
class="ks_dashboard_quick_edit_action_popup d-md-block d-none img-bg hover-item me-lg-2 kpi-tile-img bg-white"
t-att-style="'color:'+ ks_rgba_button_color + ';'"
type="button" t-att-data-item-id="item.id">
<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>
<div class="ks_chart_inner_buttons dropdown d-md-none dn-setting-panel">
<button data-bs-toggle="dropdown"
class="ks_dashboard_item_action bg-transparent img-bg hover-item me-lg-2 kpi-tile-img dropdown-toggle"
type="button"
t-att-style="'color:'+ ks_rgba_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 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="#4B5563" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.33301 8.58667V7.41333C1.33301 6.72 1.89967 6.14667 2.59967 6.14667C3.80634 6.14667 4.29967 5.29333 3.69301 4.24667C3.34634 3.64667 3.55301 2.86667 4.15967 2.52L5.31301 1.86C5.83967 1.54666 6.51967 1.73333 6.83301 2.26L6.90634 2.38666C7.50634 3.43333 8.49301 3.43333 9.09967 2.38666L9.17301 2.26C9.48634 1.73333 10.1663 1.54666 10.693 1.86L11.8463 2.52C12.453 2.86667 12.6597 3.64667 12.313 4.24667C11.7063 5.29333 12.1997 6.14667 13.4063 6.14667C14.0997 6.14667 14.673 6.71333 14.673 7.41333V8.58667C14.673 9.28 14.1063 9.85333 13.4063 9.85333C12.1997 9.85333 11.7063 10.7067 12.313 11.7533C12.6597 12.36 12.453 13.1333 11.8463 13.48L10.693 14.14C10.1663 14.4533 9.48634 14.2667 9.17301 13.74L9.09967 13.6133C8.49967 12.5667 7.51301 12.5667 6.90634 13.6133L6.83301 13.74C6.51967 14.2667 5.83967 14.4533 5.31301 14.14L4.15967 13.48C3.55301 13.1333 3.34634 12.3533 3.69301 11.7533C4.29967 10.7067 3.80634 9.85333 2.59967 9.85333C1.89967 9.85333 1.33301 9.28 1.33301 8.58667Z" stroke="currentColor" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div role="menu" class="dropdown-menu dropdown-menu-right ks_chart_inner_min_width">
<div class="ks_chart_export_menu">
<div class="ks_dashboard_item_customize ks_chart_export_menu_item"
t-att-data-item_id="item.id"
data-format="chart_xls">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<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>
<span>Customize Item</span>
</div>
<div class="ks_dashboard_item_delete ks_chart_export_menu_item"
t-att-data-item_id="item.id"
data-format="chart_xls">
<svg width="16" height="16" viewBox="0 0 16 16" fill="" class="me-1" 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> <span>Remove Item</span>
</div>
</div>
</div>
</div>
</t>
<t t-if="item.ksIsUser and props.hideButtons and !props.on_dialog">
<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-lg-2 kpi-tile-img bg-white d-md-block d-none"
type="button"
t-att-style="'color:'+ ks_rgba_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 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="item.ks_company"/></span>
</div>
<div class="ks_info" style="margin-left:10px">
<t t-if="ks_info">
<t t-foreach="ks_info" t-as="ks_description" t-key="ks_description_index">
<span><t t-esc="ks_description"/></span>
<br></br>
</t>
</t>
</div>
</div>
</div>
</div>
</t>
<t t-if="item.ksIsUser and props.hideButtons and !props.on_dialog">
<div class="ks_chart_inner_buttons d-md-block d-none">
<button title="More" data-bs-toggle="dropdown"
class="ks_dashboard_item_action img-bg hover-item me-lg-2 kpi-tile-img bg-white dropdown-toggle o-no-caret"
type="button"
t-att-style="'color:'+ ks_rgba_button_color + ';'"
aria-expanded="true">
<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="dropdown-menu dropdown-menu-right">
<div class="ks_chart_export_menu">
<div class="ks_chart_json_export ks_chart_export_menu_item d-flex"
t-att-data-item_id="item_id"
data-format="chart_xls">
<img src="/ks_dashboard_ninja/static/images/dashboardOverview/document-upload.svg" alt="document-upload" class="img-fluid" loading="lazy"/>
<span>Export Item</span>
</div>
<t t-if="item.ksIsDashboardManager and props.hideButtons and !props.on_dialog">
<div class="d-flex align-items-center">
<button type="button" title="Remove Item"
class="ks_dashboard_item_delete d-md-flex d-none img-bg hover-item me-lg-2 kpi-tile-img bg-white"
t-att-style="'color:'+ ks_rgba_button_color + ';'">
<svg width="16" height="16" viewBox="0 0 16 16" class="me-1" 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>
Remove
</button>
</div>
<div class="d-flex align-items-center">
<button id='ks_ai_item_exp_dash' class="img-bg hover-item me-lg-2 kpi-tile-img bg-white"
t-on-click="_onButtonClick4" 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 align-items-center">
<button class="ks_dashboard_item_chatter_wizard img-bg hover-item me-lg-2 kpi-tile-img bg-white" title="Internal Chat" 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>
</t>
</div>
</div>
</div>
</t>
</div>
<!-- Profile Card Content -->
<div class="ks-profile-header">
<div class="ks-profile-image">
<img t-att-src="'data:image/png;base64,' + state.employee.image_1920"
alt="Employee Image"
t-att-class="state.employee.image_1920 ? '' : 'ks-default-image'" />
</div>
<div class="ks-profile-details">
<div class="ks-profile-info">
<h1>
<t t-esc="state.employee.name"/>
<t t-if="state.employee.employee_id">
- <t t-esc="state.employee.employee_id"/>
</t>
</h1>
<p class="ks-job-title">
<t t-if="state.employee.job_id">
<t t-esc="state.employee.job_id[1]"/>
</t>
<t t-if="!state.employee.job_id">
Add Job Title
</t>
</p>
<p class="ks-joined">
<t t-if="state.employee.doj">
Joined <t t-esc="state.employee.current_company_exp"/> ago
</t>
<t t-if="!state.employee.doj">
Joined Date: <t t-esc="state.employee.doj"/>
</t>
</p>
<p>
Birthday :
<t t-if="state.employee.birthday">
<t t-esc="state.employee.birthday"/>
</t>
<t t-else="">
--/--/----
</t>
</p>
</div>
<div class="ks-profile-contact">
<p>
<i class="fa fa-phone"></i>
<t t-if="state.employee.mobile_phone">
<t t-esc="state.employee.mobile_phone"/>
</t>
<t t-if="!state.employee.mobile_phone">
---
</t>
</p>
<p>
<i class="fa fa-envelope"></i>
<t t-if="state.employee.work_email">
<t t-esc="state.employee.work_email"/>
</t>
<t t-if="!state.employee.work_email">
---
</t>
</p>
<p>
<i class="fa fa-home"></i> Address:
<t t-if="state.employee.private_street">
<t t-esc="state.employee.private_street"/>
</t>
<t t-if="!state.employee.private_street">
---
</t>
</p>
</div>
</div>
<div class="ks-stat-att" t-on-click="attendance_sign_in_out">
<t t-if="state.employee.attendance_state == 'checked_out'">
<div class="ks-stat-atticon">
<i class="fa fa-sign-in"></i>
</div>
<div class="ks-stat-attcontent">
<p>Check In</p>
</div>
</t>
<t t-if="state.employee.attendance_state == 'checked_in'">
<div class="ks-stat-atticon">
<i class="fa fa-sign-out"></i>
</div>
<div class="ks-stat-attcontent">
<p>Check Out</p>
</div>
</t>
</div>
</div>
</div>
</t>
</templates>

View File

@ -0,0 +1,239 @@
.ks-profile-container {
font-family: 'Arial', sans-serif;
color: #333;
background: linear-gradient(135deg, #6a11cb, #2575fc);
border-radius: 15px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.ks-profile-header {
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 20px;
color: #fff;
}
.ks-profile-image {
flex: 0 0 150px;
height: 150px;
border-radius: 50%;
overflow: hidden;
margin-right: 20px;
border: 4px solid rgba(255, 255, 255, 0.3);
}
.ks-profile-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ks-default-image {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.ks-profile-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.ks-profile-info h1 {
margin: 0;
font-size: 1.8em;
font-weight: bold;
color: #fff;
}
.ks-job-title {
font-style: italic;
font-size: 1.1em;
color: rgba(255, 255, 255, 0.9);
margin: 0;
}
.ks-joined {
font-size: 0.9em;
opacity: 0.9;
margin: 0;
}
.ks-profile-contact {
margin-top: 10px;
font-size: 0.9em;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.ks-profile-contact p {
margin: 0;
display: flex;
align-items: center;
gap: 8px;
}
.ks-profile-contact i {
color: rgba(255, 255, 255, 0.8);
font-size: 1.2em;
}
.ks-stat-att {
width: 100px;
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
text-align: center;
padding: 15px;
cursor: pointer;
transition: all 0.3s ease;
margin-left: auto;
}
.ks-stat-att:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-3px);
}
.ks-stat-atticon {
font-size: 2em;
color: #fff;
margin-bottom: 5px;
}
.ks-stat-attcontent p {
font-size: 0.9em;
color: #fff;
margin: 0;
font-weight: bold;
}
.ks-profile-container {
font-family: 'Arial', sans-serif;
color: #333;
background: linear-gradient(135deg, #6a11cb, #2575fc);
border-radius: 15px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.ks-profile-header {
display: flex;
flex-wrap: wrap;
align-items: center;
padding: 20px;
color: #fff;
}
.ks-profile-image {
flex: 0 0 150px;
height: 150px;
border-radius: 50%;
overflow: hidden;
margin-right: 20px;
border: 4px solid rgba(255, 255, 255, 0.3);
}
.ks-profile-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.ks-default-image {
background-color: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
}
.ks-profile-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.ks-profile-info h1 {
margin: 0;
font-size: 1.8em;
font-weight: bold;
color: #fff;
}
.ks-job-title {
font-style: italic;
font-size: 1.1em;
color: rgba(255, 255, 255, 0.9);
margin: 0;
}
.ks-joined {
font-size: 0.9em;
opacity: 0.9;
margin: 0;
}
.ks-profile-contact {
margin-top: 10px;
font-size: 0.9em;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.ks-profile-contact p {
margin: 0;
display: flex;
align-items: center;
gap: 8px;
}
.ks-profile-contact i {
color: rgba(255, 255, 255, 0.8);
font-size: 1.2em;
}
.ks-stat-att {
width: 100px;
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
text-align: center;
padding: 15px;
cursor: pointer;
transition: all 0.3s ease;
margin-left: auto;
}
.ks-stat-att:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-3px);
}
.ks-stat-atticon {
font-size: 2em;
color: #fff;
margin-bottom: 5px;
}
.ks-stat-attcontent p {
font-size: 0.9em;
color: #fff;
margin: 0;
font-weight: bold;
}
/* Additional styles for the dashboard container */
.encapsulated-profile-container {
background: linear-gradient(135deg, #6a11cb, #2575fc);
border-radius: 15px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}

View File

@ -7,6 +7,8 @@ import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_til
import { patch } from "@web/core/utils/patch"; import { patch } from "@web/core/utils/patch";
import { rpc } from "@web/core/network/rpc"; import { rpc } from "@web/core/network/rpc";
import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi'; import { Ksdashboardkpiview } from '@ks_dashboard_ninja/components/ks_dashboard_kpi_view/ks_dashboard_kpi';
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
patch(Ksdashboardgraph.prototype,{ patch(Ksdashboardgraph.prototype,{
@ -35,6 +37,7 @@ patch(Ksdashboardgraph.prototype,{
} }
}); });
patch(Ksdashboardkpiview.prototype,{ patch(Ksdashboardkpiview.prototype,{
async _openChatWizard(ev){ async _openChatWizard(ev){

View File

@ -23,6 +23,7 @@ import { Ksdashboardtile } from '@ks_dashboard_ninja/components/ks_dashboard_til
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do'; 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 { 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 { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
import { Dialog } from "@web/core/dialog/dialog"; import { Dialog } from "@web/core/dialog/dialog";
import { rpc } from "@web/core/network/rpc"; import { rpc } from "@web/core/network/rpc";
@ -208,7 +209,7 @@ export class KsAIDashboardNinja extends Component {
// Add widgets to the grid // Add widgets to the grid
this.state.ks_dashboard_items.forEach(function (item) { this.state.ks_dashboard_items.forEach(function (item) {
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 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', 'ks_profile'];
var ksPreview = document.getElementById(item.id); var ksPreview = document.getElementById(item.id);
if (ksPreview) { if (ksPreview) {
@ -533,6 +534,6 @@ export class KsAIDashboardNinja extends Component {
speak_once(ev,item){ speak_once(ev,item){
} }
} }
KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardtodo, Dialog, FormViewDialog}; KsAIDashboardNinja.components = { Ksdashboardtile,Ksdashboardgraph,Ksdashboardkpiview, Ksdashboardprofile, Ksdashboardtodo, Dialog, FormViewDialog};
KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader" KsAIDashboardNinja.template = "ksaiDashboardNinjaHeader"
registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja); registry.category("actions").add("ks_ai_dashboard_ninja",KsAIDashboardNinja);

View File

@ -10,6 +10,9 @@ import { Ksdashboardgraph } from './../components/ks_dashboard_graphs/ks_dashboa
import { Ksdashboardtile } from './../components/ks_dashboard_tile_view/ks_dashboard_tile'; import { Ksdashboardtile } from './../components/ks_dashboard_tile_view/ks_dashboard_tile';
import { Ksdashboardtodo } from './../components/ks_dashboard_to_do_item/ks_dashboard_to_do'; import { Ksdashboardtodo } from './../components/ks_dashboard_to_do_item/ks_dashboard_to_do';
import { Ksdashboardkpiview } from './../components/ks_dashboard_kpi_view/ks_dashboard_kpi'; import { Ksdashboardkpiview } from './../components/ks_dashboard_kpi_view/ks_dashboard_kpi';
import { Ksdashboardprofile } from './../components/ks_dashboard_profile_view/ks_dashboard_profile';
import { rpc } from "@web/core/network/rpc"; import { rpc } from "@web/core/network/rpc";
import { user } from "@web/core/user"; import { user } from "@web/core/user";
@ -129,7 +132,7 @@ CustomDialog.props = {
} }
CustomDialog.components = { Dialog, Ksdashboardgraph, Ksdashboardtile, Ksdashboardkpiview, Ksdashboardtodo }; CustomDialog.components = { Dialog, Ksdashboardgraph, Ksdashboardtile, Ksdashboardkpiview, Ksdashboardtodo, Ksdashboardprofile };
CustomDialog.template = "ks_dashboard_ninja.CustomDialog"; CustomDialog.template = "ks_dashboard_ninja.CustomDialog";

View File

@ -22,6 +22,7 @@ import { Ksdashboardlistview } from '@ks_dashboard_ninja/components/ks_dashboard
import { Ksdashboardtodo } from '@ks_dashboard_ninja/components/ks_dashboard_to_do_item/ks_dashboard_to_do'; 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 { 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 { Ksdashboardgraph } from '@ks_dashboard_ninja/components/ks_dashboard_graphs/ks_dashboard_graphs';
import { Ksdashboardprofile } from '@ks_dashboard_ninja/components/ks_dashboard_profile_view/ks_dashboard_profile';
import { KschatwithAI } from '@ks_dashboard_ninja/components/chatwithAI/ks_chat'; import { KschatwithAI } from '@ks_dashboard_ninja/components/chatwithAI/ks_chat';
import { CustomFilter } from '@ks_dashboard_ninja/js/custom_filter'; import { CustomFilter } from '@ks_dashboard_ninja/js/custom_filter';
import { DateTimePicker } from "@web/core/datetime/datetime_picker"; import { DateTimePicker } from "@web/core/datetime/datetime_picker";
@ -379,7 +380,7 @@ export class KsDashboardNinja extends Component {
this.gridstackConfig = JSON.parse(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++) { 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 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', 'ks_profile']
var ks_preview = document.getElementById(item[i].id) var ks_preview = document.getElementById(item[i].id)
if (ks_preview && !this.ks_dashboard_data.ks_ai_explain_dash) { if (ks_preview && !this.ks_dashboard_data.ks_ai_explain_dash) {
if (item[i].id in self.gridstackConfig) { if (item[i].id in self.gridstackConfig) {
@ -2022,7 +2023,7 @@ export class KsDashboardNinja extends Component {
} }
KsDashboardNinja.components = { Ksdashboardtile, Ksdashboardlistview, Ksdashboardgraph, Ksdashboardkpiview, Ksdashboardtodo, DateTimePicker, DateTimeInput,KschatwithAI, CustomFilter}; KsDashboardNinja.components = { Ksdashboardtile, Ksdashboardlistview, Ksdashboardgraph, Ksdashboardkpiview, Ksdashboardtodo, Ksdashboardprofile, DateTimePicker, DateTimeInput,KschatwithAI, CustomFilter};
KsDashboardNinja.template = "ks_dashboard_ninja.KsDashboardNinjaHeader" KsDashboardNinja.template = "ks_dashboard_ninja.KsDashboardNinjaHeader"
registry.category("actions").add("ks_dashboard_ninja", KsDashboardNinja); registry.category("actions").add("ks_dashboard_ninja", KsDashboardNinja);

View File

@ -35,7 +35,7 @@ export class KsGraphPreview extends Component {
el.remove(); el.remove();
}); });
if (rec.ks_dashboard_item_type !== 'ks_tile' && rec.ks_dashboard_item_type !== 'ks_kpi' && if (rec.ks_dashboard_item_type !== 'ks_tile' && rec.ks_dashboard_item_type !== 'ks_kpi' && rec.ks_dashboard_item_type !== 'ks_profile' &&
rec.ks_dashboard_item_type !== 'ks_list_view' && rec.ks_dashboard_item_type !== 'ks_to_do') { rec.ks_dashboard_item_type !== 'ks_list_view' && rec.ks_dashboard_item_type !== 'ks_to_do') {
if (rec.ks_data_calculation_type !== "query") { if (rec.ks_data_calculation_type !== "query") {

View File

@ -24,7 +24,8 @@ export class KsDashboarditemtype extends Component {
{'id':14,'name':'List','Tech_name':'ks_list_view'}, {'id':14,'name':'List','Tech_name':'ks_list_view'},
{'id':15,'name':'Map','Tech_name':'ks_map_view'}, {'id':15,'name':'Map','Tech_name':'ks_map_view'},
{'id':16,'name':'To-do','Tech_name':'ks_to_do'}, {'id':16,'name':'To-do','Tech_name':'ks_to_do'},
{'id':17,'name':'KPI','Tech_name':'ks_kpi'} {'id':17,'name':'KPI','Tech_name':'ks_kpi'},
{'id':18,'name':'Profile','Tech_name':'ks_profile'}
]}); ]});
} }

View File

@ -195,6 +195,15 @@
<path d="M14.7006 21.5609L20.8749 16.4059C21.3649 15.9943 22.0117 16.1119 22.3449 16.6607L24.6971 20.5809C25.0303 21.1297 25.6771 21.2277 26.1671 20.8357L32.3414 15.6807" stroke="" stroke-width="1.49595" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/> <path d="M14.7006 21.5609L20.8749 16.4059C21.3649 15.9943 22.0117 16.1119 22.3449 16.6607L24.6971 20.5809C25.0303 21.1297 25.6771 21.2277 26.1671 20.8357L32.3414 15.6807" stroke="" stroke-width="1.49595" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"/>
</svg> </svg>
</t> </t>
<t t-elif="item_name === 'Profile'">
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24 24C29.5228 24 34 19.5228 34 14C34 8.47715 29.5228 4 24 4C18.4772 4 14 8.47715 14 14C14 19.5228 18.4772 24 24 24Z"
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
<path d="M10 40C10 33.3726 16.3726 28 24 28C31.6274 28 38 33.3726 38 40"
stroke="" stroke-width="1.49595" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10"/>
</svg>
</t>
</t> </t>

View File

@ -0,0 +1,73 @@
/** @odoo-module */
import { registry } from "@web/core/registry";
import { useState, onMounted } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { Component } from "@odoo/owl";
class KsProfile extends Component {
setup() {
this.orm = useService("orm");
this.state = useState({
employee: {
name: '',
image_1920: '',
job_id: null,
current_company_exp: null,
doj: '',
employee_id: null,
birthday: '',
attendance_state: null,
mobile_phone: '',
work_email: '',
private_street: '',
department_id: ''
}
});
onMounted(async () => {
await this.fetchEmployeeData();
});
}
async fetchEmployeeData() {
try {
debugger;
const employeeData = await this.orm.call("hr.employee", 'get_user_employee_details');
if (employeeData && employeeData.length > 0) {
const employee = employeeData[0];
this.state.employee = {
name: employee.name,
image_1920: employee.image_1920,
doj: employee.doj,
job_id: employee.job_id,
employee_id: employee.employee_id,
current_company_exp: employee.current_company_exp,
attendance_state: employee.attendance_state,
birthday: employee.birthday,
mobile_phone: employee.mobile_phone,
work_email: employee.work_email,
private_street: employee.private_street,
department_id: employee.department_id ? employee.department_id[1] : ''
};
}
} catch (error) {
console.error("Error fetching employee data:", error);
}
}
async attendance_sign_in_out() {
try {
await this.orm.call('hr.employee', 'attendance_manual', [[this.state.employee.id]]);
this.state.employee.attendance_state =
this.state.employee.attendance_state === 'checked_in' ? 'checked_out' : 'checked_in';
} catch (error) {
console.error("Error updating attendance:", error);
}
}
}
KsProfile.template = "ks_profile";
export const KsProfileField = {
component: KsProfile,
};
registry.category("fields").add('ks_profile_preview', KsProfileField);

View File

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="ks_profile" owl="1">
<div class="ks-profile-container">
<div class="ks-profile-header">
<div class="ks-profile-image">
<img t-att-src="'data:image/png;base64,' + state.employee.image_1920"
alt="Employee Image"
t-att-class="state.employee.image_1920 ? '' : 'ks-default-image'" />
</div>
<div class="ks-profile-details">
<div class="ks-profile-info">
<h1>
<t t-esc="state.employee.name"/>
<t t-if="state.employee.employee_id">
- <t t-esc="state.employee.employee_id"/>
</t>
</h1>
<p class="ks-job-title">
<t t-if="state.employee.job_id">
<t t-esc="state.employee.job_id[1]"/>
</t>
<t t-if="!state.employee.job_id">
Add Job Title
</t>
</p>
<p class="ks-joined">
<t t-if="state.employee.doj">
Joined <t t-esc="state.employee.current_company_exp"/> ago
</t>
<t t-if="!state.employee.doj">
Joined Date: <t t-esc="state.employee.doj"/>
</t>
</p>
<p>
Birthday :
<t t-if="state.employee.birthday">
<t t-esc="state.employee.birthday"/>
</t>
<t t-else="">
--/--/----
</t>
</p>
</div>
<div class="ks-profile-contact">
<p>
<i class="fa fa-phone"></i>
<t t-if="state.employee.mobile_phone">
<t t-esc="state.employee.mobile_phone"/>
</t>
<t t-if="!state.employee.mobile_phone">
---
</t>
</p>
<p>
<i class="fa fa-envelope"></i>
<t t-if="state.employee.work_email">
<t t-esc="state.employee.work_email"/>
</t>
<t t-if="!state.employee.work_email">
---
</t>
</p>
<p>
<i class="fa fa-home"></i> Address:
<t t-if="state.employee.private_street">
<t t-esc="state.employee.private_street"/>
</t>
<t t-if="!state.employee.private_street">
---
</t>
</p>
</div>
</div>
<div class="ks-stat-att" t-on-click="attendance_sign_in_out">
<t t-if="state.employee.attendance_state == 'checked_out'">
<div class="ks-stat-atticon">
<i class="fa fa-sign-in"></i>
</div>
<div class="ks-stat-attcontent">
<p>Check In</p>
</div>
</t>
<t t-if="state.employee.attendance_state == 'checked_in'">
<div class="ks-stat-atticon">
<i class="fa fa-sign-out"></i>
</div>
<div class="ks-stat-attcontent">
<p>Check Out</p>
</div>
</t>
</div>
</div>
</div>
</t>
</templates>

View File

@ -6,17 +6,17 @@
<div class="row" style="min-height: 60vh;"> <div class="row" style="min-height: 60vh;">
<div class="col-6 d-flex flex-column align-items-stretch chat_explain_ai"> <div class="col-6 d-flex flex-column align-items-stretch chat_explain_ai">
<t t-if="props.ks_dashboard_item_type === 'ks_tile'"> <!-- <t t-if="props.ks_dashboard_item_type === 'ks_tile'">-->
<Ksdashboardtile item="props.item" <!-- <Ksdashboardtile item="props.item"-->
dashboard_data="props.dashboard_data" <!-- dashboard_data="props.dashboard_data"-->
ksdatefilter="props.ksdatefilter" <!-- ksdatefilter="props.ksdatefilter"-->
pre_defined_filter="props.pre_defined_filter" <!-- pre_defined_filter="props.pre_defined_filter"-->
custom_filter="props.custom_filter" <!-- custom_filter="props.custom_filter"-->
hideButtons="0" <!-- hideButtons="0"-->
on_dialog="true" <!-- on_dialog="true"-->
ks_speak="props.ks_speak"/> <!-- ks_speak="props.ks_speak"/>-->
</t> <!-- </t>-->
<t t-elif="props.ks_dashboard_item_type === 'ks_kpi'"> <t t-if="props.ks_dashboard_item_type === 'ks_kpi'">
<Ksdashboardkpiview item="props.item" <Ksdashboardkpiview item="props.item"
dashboard_data="props.dashboard_data" dashboard_data="props.dashboard_data"
ksdatefilter="props.ksdatefilter" ksdatefilter="props.ksdatefilter"

View File

@ -938,6 +938,9 @@
<t t-elif="items.ks_dashboard_item_type === 'ks_to_do'"> <t t-elif="items.ks_dashboard_item_type === 'ks_to_do'">
<Ksdashboardtodo item="items" hideButtons="1" dashboard_data="ks_dashboard_data" explain_ai_whole="explain_ai_whole"/> <Ksdashboardtodo item="items" hideButtons="1" dashboard_data="ks_dashboard_data" explain_ai_whole="explain_ai_whole"/>
</t> </t>
<t t-elif="items.ks_dashboard_item_type === 'ks_profile'">
<Ksdashboardprofile item="items" hideButtons="1" on_dialog="on_dialog" dashboard_data="ks_dashboard_data" />
</t>
<t t-else=""> <t t-else="">
<Ksdashboardgraph item="items" hideButtons="1" explain_ai_whole="explain_ai_whole" dashboard_data="ks_dashboard_data" ksdatefilter="state.ksDateFilterSelection" pre_defined_filter = "state.pre_defined_filter" custom_filter="state.custom_filter" ks_speak="(ev)=>this.speak_once(ev,items)"/> <Ksdashboardgraph item="items" hideButtons="1" explain_ai_whole="explain_ai_whole" dashboard_data="ks_dashboard_data" ksdatefilter="state.ksDateFilterSelection" pre_defined_filter = "state.pre_defined_filter" custom_filter="state.custom_filter" ks_speak="(ev)=>this.speak_once(ev,items)"/>
</t> </t>

View File

@ -219,7 +219,7 @@
class="w-100" class="w-100"
widget="ks_dashboard_graph_preview" widget="ks_dashboard_graph_preview"
invisible="ks_dashboard_item_type in invisible="ks_dashboard_item_type in
['ks_to_do', 'ks_tile', 'ks_list_view', 'ks_kpi', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_kpi']"/> ['ks_to_do', 'ks_tile', 'ks_list_view', 'ks_kpi', 'ks_map_view', 'ks_funnel_chart', 'ks_bullet_chart', 'ks_kpi', 'ks_profile']"/>
<field name="ks_list_view_preview" class="w-100 encapsulated-list-preview" <field name="ks_list_view_preview" class="w-100 encapsulated-list-preview"
widget="ks_dashboard_list_view_preview" widget="ks_dashboard_list_view_preview"
invisible="ks_dashboard_item_type != 'ks_list_view'"/> invisible="ks_dashboard_item_type != 'ks_list_view'"/>
@ -240,10 +240,19 @@
<field name="ks_map_preview" string="Map Preview" <field name="ks_map_preview" string="Map Preview"
widget="ks_dashboard_map_preview" class="flex-grow-1 w-100" widget="ks_dashboard_map_preview" class="flex-grow-1 w-100"
invisible="ks_dashboard_item_type != 'ks_map_view'"/> invisible="ks_dashboard_item_type != 'ks_map_view'"/>
<field name="ks_profile_preview" string="Profile Preview"
widget="ks_profile_preview" class="flex-grow-1 w-100"
invisible="ks_dashboard_item_type != 'ks_profile'"/>
</div> </div>
</div> </div>
</div> </div>
<div class="encapsulated-input-group col-xl-7 col-lg-6"> <div class="col-6 gap-2 d-flex flex-column" invisible="ks_dashboard_item_type != 'ks_profile'">
<label for="name" string="Name" class="o_form_label"/>
<field name="name" required="1" placeholder="Enter Name" class="form-control form-input-box w-100"/>
</div>
<div class="encapsulated-input-group col-xl-7 col-lg-6" invisible="ks_dashboard_item_type == 'ks_profile'">
<div class="chart-form-detail row"> <div class="chart-form-detail row">
<div class="col-6 gap-2 d-flex flex-column"> <div class="col-6 gap-2 d-flex flex-column">
<label for="name" string="Name" class="o_form_label"/> <label for="name" string="Name" class="o_form_label"/>
@ -267,7 +276,7 @@
<field name="ks_model_id" placeholder="Enter Model Name" <field name="ks_model_id" placeholder="Enter Model Name"
class="form-control form-input-box encapsulated-form-arrow bg-white" class="form-control form-input-box encapsulated-form-arrow bg-white"
options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" nolabel="1" options="{'no_create': True, 'no_create_edit':True, 'no_open': True}" nolabel="1"
context="{'current_id': id}" required="ks_dashboard_item_type != 'ks_to_do' and data_source == 'odoo'" context="{'current_id': id}" required="ks_dashboard_item_type not in ['ks_to_do','ks_profile'] and data_source == 'odoo'"
invisible="ks_data_calculation_type == 'query' or data_source != 'odoo' or ks_dashboard_item_type not in invisible="ks_data_calculation_type == 'query' or data_source != 'odoo' or ks_dashboard_item_type not in
['ks_kpi','ks_radar_view','ks_flower_view','ks_tile','ks_bar_chart','ks_horizontalBar_chart','ks_line_chart','ks_area_chart','ks_pie_chart', ['ks_kpi','ks_radar_view','ks_flower_view','ks_tile','ks_bar_chart','ks_horizontalBar_chart','ks_line_chart','ks_area_chart','ks_pie_chart',
'ks_doughnut_chart','ks_polarArea_chart','ks_list_view','ks_scatter_chart','ks_radialBar_chart','ks_funnel_chart','ks_bullet_chart','ks_map_view']" 'ks_doughnut_chart','ks_polarArea_chart','ks_list_view','ks_scatter_chart','ks_radialBar_chart','ks_funnel_chart','ks_bullet_chart','ks_map_view']"